在我的跨平台应用程序中,我使用QNetworkAccessManager向需要身份验证的HTTP服务发送HTTP请求。我最近升级到QT5,在MacOSX上,我的应用程序在某些情况下会尽可能快地向我的服务发送大量请求,这让我感到非常惊讶。
经过一些调试后,发现只有当我在请求中指定了错误的身份验证凭证时才会发生这种情况。如果在我的HTTP请求中指定了无效的用户名/密码,QNetworkAccessManager将无限期地重新发送请求到我的服务。
我的代码在以前的QT版本中工作了很长时间,所以我决定它必须是QT5的东西。
我偶然发现了QT5中添加的以下增强:https://bugreports.qt.io/browse/QTBUG-22033
基本上,这个增强背后的想法是检查keychain的用户名/密码,如果它的中间代理需要认证凭据。事实证明这是很糟糕的实现,这段代码被添加到QNetworkAccessManager::authenticationRequired()信号中,而不是添加到proxyAuthenticationRequired()信号中。
关于这个问题的有趣部分是,我没有为我的应用程序设置代理,也没有为我使用的QNetworkAccessManager。这使得这个问题很难调试!
由于位置不好,这个"keychain查询"发生在任何authenticationRequired信号上。底层的getProxyAuth()方法使用空白主机名调用"SecKeychainFindInternetPassword",该主机名与我的钥匙链中的第一个"Internet密码"相匹配,并使用它向我的服务发送带有此新凭据的请求。想象一下,当我看到我的另一个/个人密码被发送到我的HTTP服务时,我有多惊讶!
这不仅是一个安全问题,但它会导致无限循环在你的应用程序。我打开了一个bug与QT关于这个:https://bugreports.qt.io/browse/QTBUG-30434
是否有临时解决方案?有!我一直在寻找解决这个问题的方法。这是一个令人讨厌的黑客。但在QT的人把事情搞清楚之前,它是有效的。这个hack工作是因为它确保"SecKeychainFindInternetPassword"不匹配keychain中的任何条目,因此跳过"keychain查询"。
基本上我将代理主机名设置为"而不是",这将防止任何匹配导致我的应用程序中的无限循环。
处理:
QNetworkProxy proxy = manager_->proxy();
proxy.setHostName(" ");
manager_->setProxy(proxy);
我希望这是解决在QT的下一个版本,所以我可以删除这个可怕的黑客。