我的公司在去年秋天遇到了这种情况,从 iOS 6 开始,我们能够确定的是,作为其安全“增强”的一部分,它是一个真正的 Apple Safari 漏洞。他们没有真正解释基本原理,但这是我们在调试和数据包嗅探器中看到的。
在正常操作中,Safari 浏览器会通过 GET 向服务器请求页面(或页面中的对象)。如果该资产受到访问控制列表的保护,在我们的例子中是 Apache Basic Auth,并且它是会话中该主机上的第一个请求,服务器将使用 401 HTTP 响应标头进行响应,指示客户端(浏览器)它需要再次请求,这次添加具有授权凭据的基本身份验证标头。然后浏览器向用户显示一个登录对话框,用户可以在其中输入用户并传递凭据,然后提交或取消请求。提交时,客户端使用 auth 标头中的这些凭据重新请求。
假设凭据在第二个 GET 请求中被接受,正确的资产将在响应中返回,并且浏览器中的文档将继续加载页面的其余部分(假设它是您请求的页面)。如果您有驻留在不同主机上的嵌入式资产,并且该主机需要对该资产进行身份验证,则该过程会在页面加载时重复。
这就是它被破坏的地方。如果您在同一页面上嵌入对来自超过 2 个主机的对象的调用,这需要基本身份验证,则该页面上的第三个身份验证提示将被抑制,因此浏览器将永远旋转,等待您在从未见过的提示上输入凭据. 你的 Safari 浏览器现在挂在那个停滞的身份验证提示上,在这个和任何其他选项卡上,即使在重新加载时,你也不会得到另一个提示,除非你硬关闭你的浏览器或重新启动你的设备。
这不会影响 Chrome,只会影响 Safari,而且它在 iPhone 和装有 iOS 6 或更高版本的 iPad 上都有。在撰写本文时,我拥有最新的 iOS 版本(7.0.6),但问题仍然存在。
去年我们有一个解决方法,我们将创建一个内部页面,其中包含每个嵌入式主机的数组,然后我们将使用 iframe 循环遍历该页面,该 iframe 嵌入对该主机位置的 favicon.ico 的调用。直到最近才起作用,现在,也许是因为 iOS 7 冻结背景选项卡的功能,身份验证提示再次被冻结。
这是 JavaScript 示例:
hosts=["store","profile","www","secure-store","images","m","modules"];
devhost=location.hostname;
var i=0;
while (hosts[i])
{
newhost=devhost.replace('store.mydomain',hosts[i]+'.mydomain');
document.write("<iframe Xhidden seamless=seamless width=0 height=0 src=http://"+newhost+"/favicon.ico><img height='16' width='20' alt='NOT' title='NOT AUTHENTICATED' src=http://"+newhost+"/favicon.ico> Authenticated on "+newhost+"</a></br></iframe>");
document.write("<img height='16' width='20' alt='NOT' title='NOT AUTHENTICATED' src="+(newhost.indexOf('secure')>0?'https://':'http://')+newhost+"/favicon.ico> Authenticated on "+newhost+"</a></br>");
i++;
}
document.write 中的第二组将直观地指示哪些主机已通过身份验证,因为现在显示了它们的 favicon。它还可以让您知道哪个主机可能会停止,因为它的图标丢失了。
由于此解决方法在 iOS 7 上停止工作,我们唯一繁琐的解决方案是为每个 favicon 预先打开一个单独的选项卡(直接在 URL 中),输入身份验证,返回,转到列表中的下一个,然后重复,直到您缓存了页面上使用的所有主机的所有身份验证凭据。此时,您可以加载原始页面,因为您的凭据现在已被缓存。粗鲁,对最终消费者来说完全不合理,但这是我们需要为公共 CDN 后面的测试站点做的事情,因为我们需要使用 ACL 保护该开发站点上的资产。
时至今日,我们仍在寻找更好的解决方法。在 Android、Windows 或任何其他 iOS 上都不是问题。
乔布斯在世时,当然工作得更好。
希望有些帮助。