@accountnujen

Почему мне не удаётся совершить второй запрос по Digest?

Я прочитал документацию по rfc7616 (https://datatracker.ietf.org/doc/html/rfc7616), но у меня не получается выполнить второй запрос в рамках одной авторизации. Насколько я понимаю, я должен сделать нулевой (пустой) запрос, затем получить nonce из ответа, посчитать A1 и A2, а затем, с полученным заголовком, сделать первый запрос. В последующих запросах я должен увеличить NC и изменить URI.

  1. Я делаю пустой запрос.
  2. Получаю ответ 401 и nonce.
  3. Я вычисляю ответ, A1 и A2.
  4. Я делаю первый запрос.
  5. Получаю ответ 200.
  6. Я меняю URI, NC и считаю новый ответ.
  7. Я получаю ответ 401 stale=true


По какой-то причине второй запрос возвращает мне ошибку 401 и stale=true. Подскажите пожалуйста, я где-то ошибся или проблема в сервере?

$urlcam = 'http://website.com';
$username = 'admin';
$password = 'password';

function request($url, $header) {
	$request_header = array($header);
  	$request_header[] = 'Accept: */*';

	$ch = curl_init($GLOBALS['urlcam'].$url);
	curl_setopt_array($ch, [
    	CURLOPT_RETURNTRANSFER => 1,
    	CURLOPT_CUSTOMREQUEST => "GET",
    	CURLOPT_HTTPAUTH => CURLAUTH_DIGEST,
    	CURLOPT_HTTPHEADER => $request_header,
    	CURLOPT_HEADER => true
  	]);
  	$response = curl_exec($ch);
  	$info = curl_getinfo($ch);
  	curl_close($ch);
  	return ["res" => $response, "info" => $info];
}

function authparse($data) {
	preg_match('/WWW-Authenticate: Digest (.*)/', $data, $matches);
	$auth_header_array = explode(',', $matches[1]);
	$result = [];
	foreach ($auth_header_array as $pair) {
	  $vals = explode('=', $pair);
	  $result[trim($vals[0])] = trim(trim($vals[1]),'"');
	}
	return $result;
}


$start = date("Y-m-d%20H:i:s", strtotime('18.07.2022 09:00:00'));
$end = date("Y-m-d%20H:i:s", strtotime('18.07.2022 18:00:00'));


##################################################################################
##################################################################################
##################################################################################
# Empty request

$urlCreate = "/cgi-bin/mediaFileFind.cgi?action=factory.create";
$resultCreate = request($urlCreate, '');

##################################################################################
##################################################################################
##################################################################################
# First request

$resultCreateParse = authparse($resultCreate['res']);

$realm = $resultCreateParse['realm'];
$qop = $resultCreateParse['qop'];
$opaque = $resultCreateParse['opaque'];
$nonce = $resultCreateParse['nonce'];

$cnonce = "0a4f113b";
$nc = "00000001";

$a1 = md5($username.":".$realm.":".$password);
$a2 = md5("GET:".$urlCreate);
$a3 = md5($a1.':'.$nonce.':'.$nc.':'.$cnonce.':'.$qop.':'.$a2);

$headerCreate = 'Authorization: Digest username="'.$username.'",realm="'.$realm.'",nonce="'.$nonce.'",uri="'.$urlCreate.'",cnonce="'.$cnonce.'",nc='.$nc.',response="'.$a3.'",qop="'.$qop.'",opaque="'.$opaque.'"';

$resultCreate = request("$urlCreate", $headerCreate);


$id = explode('result=',trim($resultCreate['res']))[1];


##################################################################################
##################################################################################
##################################################################################
# Second request
$urlFindFile = "/cgi-bin/mediaFileFind.cgi?action=findFile&condition.Channel=1&condition.StartTime=$start&condition.EndTime=$end&condition.Types[0]=dav&object=$id";

$cnonce = "0a4f113b";
$nc = "00000002";

$a1 = md5($username.":".$realm.":".$password);
$a2 = md5("GET:".$urlFindFile);
$a3 = md5($a1.':'.$nonce.':'.$nc.':'.$cnonce.':'.$qop.':'.$a2);

$headerFindFile = 'Authorization: Digest username="'.$username.'",realm="'.$realm.'",nonce="'.$nonce.'",uri="'.$urlFindFile.'",cnonce="'.$cnonce.'",nc='.$nc.',response="'.$a3.'",qop="'.$qop.'",opaque="'.$opaque.'"';

$resultFindFile = request($urlFindFile, $headerFindFile);
  • Вопрос задан
  • 74 просмотра
Пригласить эксперта
Ответы на вопрос 1
Rsa97
@Rsa97
Для правильного вопроса надо знать половину ответа
Ответ stale: true говорит о том, что nonce протух.

Если в ответе на запрос возвращается параметр nextnonce, то надо сбросить счётчик nc и использовать новое значение nonce. https://datatracker.ietf.org/doc/html/rfc7616#sect...

Если такого параметра нет, то новый nonce возвращается при ответе 401.

Да, ещё сервер может прислать вам список методов в qop. И вам надо не просто скопировать присланное значение, а выбрать из этого списка подходящий метод.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы