WebSockets + PHP(棘轮)登录系统 [英] WebSockets + PHP (Ratchet) login system

查看:36
本文介绍了WebSockets + PHP(棘轮)登录系统的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道如何使用 PHP 构建安全的登录系统,包括散列、加盐和更复杂的安全措施等基础知识.

I know how to make a secure login system with PHP including basics like hashing, salting and more complex security measures.

最近我经常使用 Ratchet 和 WebSockets.我一直想知道是否可以使用 WebSockets 创建一个安全的注册/登录系统.

Recently I've been using Ratchet with WebSockets a lot. And I've been wondering if it is possible to create a secure register/login system using WebSockets.

  1. 用户在表单中输入他的数据.
  2. 数据经过验证和清理.
  3. 密码经过哈希处理.
  4. 一切都通过 WebSocket 发送到服务器.
  5. PHP 将其存储在 MySQL 数据库中并对密码的哈希值加盐.
  6. PHP 通过 WebSocket 返回注册完成的回调.
  7. 用户被授予访问网站的权限.

我认为它可能会奏效.我的疑问是:ws://协议有多安全?如何确保登录后的用户是登录的用户?某种会议?代币?

I see it might work. My doubts are here: how secure is ws:// protocol? How to make sure that after logging in the user is the user that was logged? Some sort of sessions? Tokens?

是否有这样的框架/库/实现?

Are there any frameworks/libraries/implementations of such a thing?

问题更多是出于对新(有点)技术的好奇.如果它不起作用,我将只使用 AJAX POST 请求.:)

Questions are more out of plain curiosity over a new (kinda) piece of tech. If it doesn't work I'll just go for AJAX POST request. :)

推荐答案

不,不能使用任何当前用 PHP 编写的 WebSocket 服务器设置安全身份验证.

No, it is not possible to set up a secure authentication using any of the current WebSocket servers written in PHP.

它们都缺乏 TLS 支持.(即使是我的,但我确实有一个活跃的开发分支,致力于提供 TLS 支持.)

They all lack TLS support. (Even mine, though I do have an active development branch devoted to providing TLS support.)

以下是使用 WebSockets 的安全身份验证系统所需的内容:

Here is what is required for a secure authentication system with WebSockets:

基本的 PHP 安全第一:

  1. 始终通过 TLS 或其他一些安全传输系统进行传输.
  2. 使用 bcrypt 或 scrypt(或未来更安全的系统)来散列密码以存储在数据库中.即使是带有从加密随机源生成的盐的扩展 SHA256 密码现在也被认为是不安全的.
  3. 身份验证令牌(例如由 PHP 创建并存储在会话 cookie 中的会话令牌)必须是加密不可预测的.
  4. 身份验证令牌不得用于非 TLS 流量或客户端脚本.(严格执行 Secure 标志和严格执行 HttpOnly 标志.)这明确表示除非用户处于 https: 和 wss: 模式,否则无法安全地进行身份验证.
  5. 会话数据必须存储在服务器上的安全目录或数据存储中.
  6. 重置会话令牌作为身份验证的一部分.彻底删除与旧会话 ID 关联的数据.

用于生成会话 ID 的 PHP 内置算法使用/dev/urandom 如果它在您的系统上可用.Windows 用户不会获得加密随机会话 ID,但因为大多数 WebSockets 实现都需要 Posix 环境,所以这不是问题.如果使用自己的会话 ID 生成器,请使用 openssl_random_pseudo_bytes(),并记住,在安全方面,使用自己的会话 ID 生成器是个坏主意.

PHP's built in algorithm for generating session IDs uses /dev/urandom if it is available on your system. Windows users do not get cryptographically random session IDs, though because most WebSockets implementations would require a Posix environment, this isn't an issue. If rolling your own session ID generator, use openssl_random_pseudo_bytes(), and remember that when it comes to security, it's a bad idea to roll your own.

此外,默认情况下,PHP 会话 cookie 没有设置 Secure 标志或 HttpOnly 标志.在您的 php.ini 中更改这些,是的,这意味着人们无法对未使用安全连接的任何人进行身份验证——但这无论如何都是正确的,因为没有 TLS,您无法确保任何人都是来自请求的同一用户请求,即使他们使用相同的会话 ID 和相同的 IP.

Also, by default, the PHP session cookie does not have the Secure flag or the HttpOnly flag set. Change these in your php.ini, and yes, this means that people can not authenticate anyone who is not using a secure connection -- but this is true anyways, since without TLS, you can not ensure that anyone is the same user from request to request, even if they're using the same session ID and same IP.

而且,默认情况下,PHP 会话保存路径是您系统的临时目录.这是任何人都可读和可写的.因此,任何流氓进程,无论权限提升如何,都可以访问和更改任何会话数据.最少访问意味着只有 Web 服务器用户,对于我们这些使用 WebSockets 的用户,WS 服务器的用户需要访问会话保存路径.

And, by default, the PHP session save path is your system's temp directory. This is readable and writable by anyone. Thus, any rogue process, regardless of escalated privileges, can access and alter any session data. Least access means that only the web server user and, in the case of those of us using WebSockets, the WS server's user needs to access the session save path.

WebSockets 特定的身份验证:

会话 cookie 在握手期间可供 WebSocket 服务器使用.这包括 cookie 设置了 HttpOnly 标志的时间.(在 Windows 上最新的公开可用的 Chrome 上测试.)(安全标志尚未测试.等我在我的服务器上运行 TLS 时再给我几个月的时间.如果安全 cookie 不可用,或者在非安全上下文中可用,我将代表您亲自向浏览器供应商发出神圣的恶臭.)

The session cookie is available to the WebSocket server during the handshake. This includes when the cookie has the HttpOnly flag set. (Tested on latest publicly available Chrome on Windows.) (Secure flag not testable yet. Give me a couple months as I get TLS working on my server. If secure cookies are not available, or are available in a non-secure context, I'll be personally raising a holy stink with the browser vendors on your behalf.)

这意味着拥有经过身份验证的会话的人也可以在其 WebSocket 连接上预先进行身份验证,而无需通过 Web 文档正文传递数据(无需将会话 ID 嵌入 HTML 或脚本标记中的数据中,然后将通过开放的 WS 连接重新传输).

This means that someone who has an authenticated session can also be pre-authenticated on their WebSocket connection without having to pass data through the web document body (no need to embed the session ID in the HTML or in data in a script tag, which would then be re-transmitted through the open WS connection).

至于使用 WebSockets 安全地对某人进行身份验证...有一个巨大的警告.

As for securely authenticating someone using WebSockets... There is one huge caveat.

由于 WebSocket 服务器同时连接了多个用户,打破了 PHP 会话的传统意义.我们指的是哪个会话?

Because WebSocket servers have multiple users connected at the same time, the traditional sense of PHP sessions is broken. Which session do we mean?

因此,$_SESSION 超全局变量必须严格禁止,并且 session_...() 函数应该被认为是非常危险的.唯一安全且有意义的会话函数是 session_save_path() 的只读版本,它告诉您在哪里可以找到会话文件、session_encode()session_decode().

Thus, the $_SESSION superglobal MUST be strictly off limits, and the session_...() functions should be considered highly dangerous. The only safe and meaningful session functions are the read-only version of session_save_path(), which tells you where to find the session files, session_encode(), and session_decode().

要获取会话数据,您需要读取会话文件,通过 session_decode() 运行其内容,并将结果与​​该特定用户的特定连接相关联.您还需要定期执行此操作,因为会话数据会在没有警告的情况下更改.要将任何数据保存到会话中,session_encode() 当然是您的朋友.由于 PHP 不关心会话数据的竞争条件,因此您也不应该关心.只需读取文件,更改数据,然后写入文件,一切都会好起来的.

To get the session data, you will need to read the session file, running its contents through session_decode(), and associating the results with the specific connection for that specific user. You will also need to do this periodically, as the session data changes without warning. To persist any data to the session, session_encode() is your friend, of course. Since PHP doesn't care about race conditions on session data, you shouldn't either. Just read the file, change the data, and write to the file, and it'll be all good.

这给我们带来了第一个真正的问题:为了进行安全的身份验证,您需要在用户通过身份验证时重置会话令牌.由于客户端 Javascript 无法写入 HttpOnly cookie,因此您无法更改客户端的会话 ID.

And this brings us to the first real problem: In order to have secure authentication, you need to reset the session token when the user is authenticated. Since client side Javascript can't write to an HttpOnly cookie, you can't change the session ID on the client side.

当然,可以在现有会话数据中轻松更新用户是否通过身份验证的状态.这是相当微不足道的.然而,因为我们需要一个新的会话 ID 在我们保持新的身份验证状态之前,并且新的会话 ID 必须立即对所有客户端的连接有效,所以我们不能完全通过WebSocket 连接.

The status of whether the user is authenticated can easily be updated within the existing session data, of course. That's fairly trivial. However, because we need a new session ID before we persist the new authentication state, and that new session ID must be valid for all of the client's connections immediately, we can't completely perform secure authentication through a WebSocket connection.

尽可能多地使用 WebSockets 的可能解决方法(一旦 PHP WS 服务器支持 TLS):

A possible work-around to use as much WebSockets as possible (once a PHP WS server supports TLS, that is):

  • 客户端通过 WebSocket 连接向服务器发送登录信息.
  • 服务器使用加密随机令牌进行响应.
  • 客户端通过 WS 连接使用 salt 进行响应,并通过 AJAX 请求使用哈希和加盐版本的令牌进行响应.
  • 服务器验证盐匹配,并使用 AJAX 请求的脚本调用 session_regenerate_id(true),并返回任何适当的响应(只要 set-cookie: 标题已设置).
  • 服务器将其内部映射更新到用户的新会话 ID.
  • 服务器完全丢弃一次性令牌,并自然地记录任何尝试使用任何无效一次性令牌的行为.
  • Client sends login information to the server through the WebSocket connection.
  • Server responds back with a cryptographically random token.
  • Client responds back with a salt through the WS connection, and with a hashed and salted version of the token through an AJAX request.
  • Server verifies the salt matches, and using the AJAX request's script, calls session_regenerate_id(true), and returns any appropriate response (just so long as the set-cookie: header is set).
  • Server updates its internal mapping to the user's new session ID.
  • Server discards the one-time token completely, and naturally logs any attempted use of any invalid one-time tokens.

(实现真正的 Diffie-Hellman 交换以设置真正安全的共享秘密可能是值得的.我不是安全专家;上述算法可能没有我认为的那么安全,尽管因为它已经在两个 TLS 隧道中,它应该是安全的.(https: 隧道与 wss: 隧道是分开的,不同的,因此需要确认通过一个隧道发送的信息与通过另一个隧道发送的信息匹配,但不应该除了 TLS 已经提供的保密之外,还需要保密.))

(It might be worth it to implement a true Diffie-Hellman exchange to set up a true secure shared secret. I am not a security expert; the above algorithm may not be as secure as I think it is, though because it would already be in two TLS tunnels, it should be secure. (The https: tunnel is separate and distinct from the wss: tunnel, thus there is a need to confirm information sent through one tunnel matches information sent through the other, but should not require secrecy in addition to that already afforded by TLS.))

底线:

是的,安全性很难做好.但值得.

Yes, security is hard to get right. But it's worth it.

这篇关于WebSockets + PHP(棘轮)登录系统的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆