You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Chrome浏览器首次Basic Auth认证后后续输入凭证被忽略的问题及应用端解决方案求助

Chrome浏览器首次Basic Auth认证后后续输入凭证被忽略的问题及应用端解决方案求助

大家好,我最近遇到一个浏览器依赖的Basic Auth问题,折腾了好几个小时都没搞定,想请教下有没有应用端的可行 workaround。

问题现象

我的Web应用有这么个场景:用户第一次登录时输入了错误凭证,由于这些凭证会传给另一台服务器,不会立刻返回401;等应用发现请求失败后,下次请求会再次弹出Basic Auth提示框让用户重新输入。

这个流程在Pale Moon里完全正常——每次弹框输入新凭证,浏览器都会把新凭证发给服务器;但在Chrome和所有Chromium系浏览器里就出问题了:第一次输入的凭证像被“粘”住了一样,不管后续弹框时用户输入什么新内容,浏览器始终只会把第一次的凭证发给服务器,完全忽略后续输入的内容。

我已经尝试过的调试手段

  1. 动态修改Basic Auth的realm:我本来以为给realm加个随机字符串(比如当前时间戳),让浏览器以为每次都是不同的认证域,就能触发它使用新凭证,但试了之后完全没用。
  2. 强制每次请求都返回401:我甚至写了一段PHP代码,每次请求都直接返回401并重新设置realm,但不管用,第一次的凭证还是顽固地被反复发送:
if (!isset($_SERVER['PHP_AUTH_PW']) || $_SESSION['bauth']['reprompt'] == 2) {
    $_SESSION['bauth']['reprompt'] = 0; /* Reset */
    $_SESSION['bauth']['realm'] = "myrealm " . time();
    header("WWW-Authenticate: Basic realm=\"" . $_SESSION['bauth']['realm'] . "\"");
    header("HTTP/1.1 401 Unauthorized");
    echo "Re-enter credentials";
} else {
    error_log("User: " . $_SERVER['PHP_AUTH_USER'], 0);
    if ($_SERVER['PHP_AUTH_USER'] !== "done") {
        $_SESSION['bauth']['reprompt'] = 0; /* Reset */
        $_SESSION['bauth']['realm'] = "myrealm " . time();
        header("WWW-Authenticate: Basic realm=\"" . $_SESSION['bauth']['realm'] . "\"");
        header("HTTP/1.1 401 Unauthorized");
        echo "Re-enter credentials";
    }
}

我还直接解码了原始的Authorization请求头确认,确实Chrome就是在重复发送第一次的凭证,和用户后续输入的内容无关。目前唯一的临时解决办法是完全关闭浏览器再重新打开,但问题会重复出现。

新发现的奇怪规律

我后来做了更细致的测试,发现Chrome对realm的内容有很奇怪的判定逻辑:

  • 如果realm里加的是固定的字符串/数字(比如下面这段代码里的12345),Chrome就能正常使用每次新输入的凭证:
<?php
header("HTTP/1.1 401 Unauthorized");
header("WWW-Authenticate: Basic realm=\"" . "myrealm" . "12345" . "\"");
error_log("User: " . $_SERVER['PHP_AUTH_USER'], 0);
die();
  • 但如果realm里加的是time()或者rand()生成的动态随机值,Chrome就又会“粘”住第一次的凭证,不管用户后续输入什么都没用:
<?php
header("HTTP/1.1 401 Unauthorized");
header("WWW-Authenticate: Basic realm=\"" . "myrealm" . time() . "\"");
error_log("User: " . $_SERVER['PHP_AUTH_USER'], 0);
die();

更奇怪的是,如果我把realm从固定字符串A改成固定字符串B,Chrome是能识别这是不同域并使用新凭证的——也就是说,它不是完全不支持realm变化,只是对带动态随机数字的realm有异常?我还没搞清楚这里的判定边界到底在哪里。

另外我也试过调换WWW-AuthenticateHTTP/1.1 401 Unauthorized的返回顺序,结果还是一样。

求助

因为浏览器是不可控的,我想问问有没有从应用端出发的解决办法,能让Chrome每次都尊重用户后续输入的新凭证,不再“粘”住第一次的内容?

火山引擎 最新活动