发布到 https 表单并不总是有效
在我的网站上,我有一个简单的登录表单。 该页面通过 HTTP 提供服务,但表单的 POST URL 是 HTTPS。
正常的方法是用户填写用户名/密码,提交表单(到同一站点上的完全限定的 HTTPS URL),然后 POST 处理执行 303 重定向到用户的主页。 但有时这不会发生。
循环(这是 100% 可重复的)是这样的:
- 访问登录表单,填写详细信息并提交
- 在服务器上调用登录脚本,验证数据,然后,如果一切顺利,则执行 303 重定向到用户主页页。
- 然后,我单击“注销”,然后单击“登录”,此时我将返回到登录表单
- ,然后再次填写我的详细信息,然后单击“提交”。
- 然而,这一次,登录逻辑没有执行(在步骤 2 中记录登录的调试代码没有被调用),但我仍然被重定向到用户主页。 但是因为我没有成功登录,所以我被踢到了首页...
那么为什么POST总是不调用登录表单呢? 我不认为 303 正在被缓存(根据规范,它不应该被缓存)...
查看服务器中的 HTTPS 日志,login.phpo 第一次被调用,但不是第二次。 ...
编辑:
好的,我们已经解决了问题。 对于那些感兴趣的人:
该网站在负载平衡器后面的 2 个网络服务器上运行。 用户会话是“粘性的”——也就是说,一旦用户在一台 Web 服务器上浏览,负载均衡器就会让他们“附加”到该服务器。 这是通过 cookie 完成的。 但是,一旦我们切换到 HTTPS,LB 就无法读取 cookie,因为浏览器和 Web 服务器之间的连接是加密的。 所以它在服务器之间交替。 我们有代码在网络服务器之间传播登录身份验证,但这发生的速度不够快。 所以发生的事情是:
- 用户浏览服务器 A,获取一个 cookie,上面写着“让我在 A 上”,填写他们的登录凭据并点击“提交”。 负载
- 均衡器无法破译 HTTPS 流量(因此无法破译 cookie),因此将它们发送给服务器 A。 50%的时间 B
- B 验证登录并设置用户在会话中进行身份验证,然后将用户重定向到非 https 主页
- 因为主页是非 https,所以 LB 读取 cookie 并将其发送给 A,这对身份验证一无所知,因为它从 B 传播的速度不够快...
解决方案是允许 LB 解密 HTTPS 流量,从而确保用户确实停留在一台 Web 服务器上,无论 HTTP/HTTPS 转换如何。
On my site I have a simple login form. The page is served via HTTP, but the form's POST URL is HTTPS.
The normal method is that the user fills in their username/password, the form is submitted (to the fully qualified HTTPS URL, on the same site), and then the POST processing does a 303 redirect to the users' homepage. But sometimes this doesn't happen.
The cycle (and this is 100% repeatable) is this:
- Visit login form, fill in details and submit
- On the server the login script gets called, validates the data and then , if all is well, does a 303 redirect to the users home page.
- I then click logout and then click login, at which point I'm taken back to the login form
- I then fill in my details again, hit submit.
- This time, however, the login logic doesn't execute (the debug code that logged the login at step 2 doesn't get called), and yet I'm still redirected to the users homepage. But because I've not been logged in successfully, I get kicked out to the front page...
So why isn't the POST always calling the login form? I don't think the 303 is being cached (and it shouldn't be, according to the spec)...
Looking at the HTTPS logs in the server, login.phpo is being called the first time, but not the second....
Edit:
OK, we've solved the problem. For those that are interested:
The site is run on 2 webservers behind a load balancer. user sessions are 'sticky' - that is to say once a user is browsing on one web server the LB will keep them 'attached' to that server. This is done via a cookie. But once we switch to HTTPS the LB can't read the cookie, as the connection is encrypted between the browser and web server. So it was alternating between servers. WWe have code to propagate login authentications between webservers, but this wasn't happening fast enough. So what was happening was:
- User browsers to server A, gets a cookie saying 'keep me on A', fills in their login credentials and hits submit
- The LB, being unable to decipher the HTTPS traffic (and thus the cookie), sends them 50% of the time to B
- B validates the login and sets the user to be authenticated in the session, before redirecting the user to the non https homepage
- Because the homepage is non https, the LB reads the cookie and sends them to A, which knows nothing of the authentication since it wasn't propagating fast enough from B...
The solution was to allow the LB to decrypt HTTPS traffic, thus ensuring that users really do stay on one web server, regardless of HTTP/HTTPS transitions.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
如何“注销” 您是否尝试过清除缓存以查看是否有任何剩余的会话变量将其关闭?
在 Firefox 中:工具 -> 清除私人数据-> 检查缓存、Cookie 和经过身份验证的会话
How do you "log out" Have you tried clearing your cache to see if any leftover session variables are throwing it off?
In Firefox: Tools -> Clear Private Data -> Check Cache, Cookies, and Authenticated Sessions
不,浏览器不会缓存 303,但其他级别可能会缓存它或序列中的其他页面。 另外,假设您使用 cookie 来存储登录状态,您需要确保设置“路径”和“域”,以便设置和删除相同的 cookie,而不是为网站的不同部分设置多个影子副本。
需要更多代码来诊断。
不要那样做。 如果不手动查看源(并检查引用的每个脚本),用户无法得知“操作”URL 将是 HTTPS,而这种情况是不会发生的。
因此,中间人攻击者可以通过简单地使用登录表单更改初始 HTTP 页面来获取身份验证详细信息。 这使得对 POST 接收器的任何保护都完全没有意义。
登录过程的每个阶段(包括包含登录表单的任何页面)都必须位于 HTTPS 上,您才能从中受益。
No, a 303 won't be cached by the browser, but some other level might be caching it or other pages in the sequence. Also, assuming you are using cookies to store login state, you need to ensure that you're setting ‘path’ and ‘domain’ so that the same cookie is being set and deleted, instead of multiple shadowed copies for different parts of the site.
More code needed to diagnose.
Don't do that. The user has no way of telling that the ‘action’ URL is going to be HTTPS without looking at the source manually (and checking every script referenced), which isn't going to happen.
So it's possible for a man-in-the-middle attacker to grab authentication details by simply altering the initial HTTP page with the login form. This makes any protection on the POST receiver entirely moot.
Every stage of the login process, including any page containing a login form, must be on HTTPS for you to get any benefit from it.
我想这似乎一定是缓存问题。 我会在页面上设置标题,以便您明确不缓存任何内容,然后看看它是如何工作的。
第二个猜测是您遇到了会话/cookie 问题(诚然,我还没有考虑过这是如何工作的)。 在您的注销页面中,您是否明确销毁会话(以及客户端上的任何非永久 cookie)?
最后,您是否使用任何服务器端缓存? 我不认为 PHP 操作码缓存会表现出这种行为,但我在 memcache 中看到了奇怪的事情(并且,如果您使用框架,每个框架的缓存都略有不同)。
Seems like it must be a caching issue, I would think. I'd set the headers on the pages so that you're explicitly not caching anything, and see how that works.
Second guess is that you have a session/ cookie issue (admittedly, I haven't thought through how this would work). In your logout page, do you explicitly destroy the session (and any non-permanent cookies on the client)?
Finally, are you using any server side caching? I don't think a PHP opcode cache would exhibit this behavior, but I've seen stranger things with memcache (and, if you're using a framework, each framework caches a little differently).