使用 nginx 进行基本身份验证,然后在 PHP 中进行摘要身份验证失败

Posted

技术标签:

【中文标题】使用 nginx 进行基本身份验证,然后在 PHP 中进行摘要身份验证失败【英文标题】:basic authentication with nginx followed by digest authentication in PHP fails 【发布时间】:2014-04-17 01:29:28 【问题描述】:

我正在开发一个新应用,并决定使用基本身份验证来保护云登台服务器。

我使用的是 nginx,所以配置如下:

location / 
  auth_basic "Restricted";
  auth_basic_user_file .htpasswd;
  try_files $uri $uri/ @php_mvc;

我的 MVC 应用还有一个“管理”模块,它使用 HTTP Digest 进行保护:

$realm = 'Access Restricted.';
$nonce = md5(uniqid());
$opaque = md5(uniqid());
$valid = false;

$headers = System::getallheaders();
if (array_key_exists('Authorization', $headers)) 
    $authHeader = substr($headers['Authorization'],  strlen('Digest'));
    $parsed = array();
    foreach (explode(',', $authHeader) as $pair) 
        if (substr(trim($pair), 0, 4) == ($_u = 'uri=')) 
            $parsed[substr($_u, 0, -1)] = trim(substr($pair, 5), ' "');
         else 
            $vals = explode('=', $pair);
            $parsed[trim($vals[0])] = trim($vals[1], '" ');
        
    

    $A1 = md5(self::DIGEST_USERNAME . ':' . $parsed['realm'] . ':' . self::DIGEST_PASSWORD);
    $A2 = md5($_SERVER['REQUEST_METHOD'] . ':' . $parsed['uri']);
    $response = md5($A1 . ':' . $parsed['nonce'] . ':' . $A2);

    $valid = ($response == $parsed['response']);


if (!$valid) 
    header('HTTP/1.1 401 Unauthorized');
    header('Content-Type: text/html');
    header(sprintf('WWW-Authenticate: Digest realm="%s", nonce="%s", opaque="%s"', $realm, $nonce, $opaque));
    echo 'Access denied.';
    exit();


...

function getallheaders()

    $headers = null;
    foreach ($_SERVER as $name => $value) 
        if (substr($name, 0, 5) == 'HTTP_') 
            $name = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))));
            $headers[$name] = $value;
         else if ($name == 'CONTENT_TYPE') 
            $headers['Content-Type'] = $value;
         else if ($name == 'CONTENT_LENGTH') 
            $headers['Content-Length'] = $value;
        
    
    return $headers;

所以,问题在于基于 PHP 的 Digest 身份验证不起作用,因为到那时 $_SERVER['HTTP_AUTHORIZATION'] 已经被基本身份验证的结果所占用: $_SERVER['HTTP_AUTHORIZATION'] = "Basic S1aGUzpuZXzzdXRl ”。

有没有办法将基本身份验证和摘要身份验证的结果分开?

谢谢!

【问题讨论】:

【参考方案1】:

没有。您要么需要在服务器端和后端使用相同的身份验证机制(这不适用于每种机制),要么在其中一个端关闭身份验证。

后者意味着你要么在后端关闭它,只信任服务器提供的用户名(在这种情况下,可以绕过内部网络中的身份验证),要么你在服务器端关闭它并让后端做好工作。

如果您甚至想在服务器和后端使用不同的用户名/密码(并且用户必须同时输入),那么您唯一的选择就是在后端实现基于 html/cookie/session 的登录页面,然后在服务器端使用基于 http 的身份验证

【讨论】:

以上是关于使用 nginx 进行基本身份验证,然后在 PHP 中进行摘要身份验证失败的主要内容,如果未能解决你的问题,请参考以下文章

如何在 PHP 中使用基本 HTTP 身份验证?

为啥 Chrome 有时会要求第二次进行基本身份验证,而 Firefox 则不会?

Jenkins/Nginx - 双重提示基本身份验证,为啥?为啥有内部 Jenkins 身份验证?

ini Nginx:使用基本身份验证限制Web访问

使用基于 SAML 的基本身份验证进行身份验证?

在 mysql 中使用加密存储密码进行摘要身份验证