【问题标题】:Websocket server: how to authorize clients?Websocket 服务器:如何授权客户端?
【发布时间】:2011-07-02 15:36:41
【问题描述】:

我目前正在使用 html5 画布和 websockets 构建一个包含游戏的网页。我有一个用 perl 编写的 websocket 服务器,在 server:3000 上运行。在服务器上我也安装了apache,并做了一个用户可以访问的网站:http://server/。此页面上的 javascript 创建一个到 ws://server:3000 的 websocket

连接正常,我可以从浏览器发送消息并获得响应,现在所有内容都显示在 div 中。我发送的消息现在只有“消息:...”,因此服务器知道这是一条消息,并向当前连接到“游戏”的所有用户输出“...”。

现在的问题是任何人都可以编写自己的客户端来连接到 ws://server:3000 并发送/接收适当的消息。这样他们会使用我的后端,而不是我的客户端(我希望他们只在http://server/ 玩)。

如何确保只使用我的客户端?主要担心的是作弊。您可以编写一个连接到端口并通过发送消息并解释它接收到的消息来为您播放的机器人......如何克服这个问题?

【问题讨论】:

  • 当然不能授权客户;几乎按照定义,客户是您无法控制的。但是,您可以授权来自客户端的消息。也许这就是你想要的?

标签: html websocket


【解决方案1】:

我正在使用 Jetty 网络服务器。

我正在使用基本授权。我最初使用它只是因为它易于实现。但是,在发现websockets存在的授权问题后,我认为基本授权是一个很好的机制。

升级请求标头中包含哈希授权数据:

Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-GB,en-US;q=0.8,en;q=0.6
Authorization:Basic YWRtaW46cm9vdA==
Cache-Control:no-cache
Connection:Upgrade

在我的 websocket 服务器中,我调用的每个 OnMessage 事件:

session.getUpgradeRequest().getUserPrincipal()

然后我可以使用此信息来决定是否授权处理数据。另外,我在 OnConnect 事件中检查了套接字的来源:

 session.getUpgradeRequest().getOrigin()

【讨论】:

    【解决方案2】:

    您的要求是不可能实现的。您可以采取措施使第三方难以制作未经授权的客户端,但最终只要第三方能够使用您的合法客户端,他们就可以随时观察它的行为并复制它,你无法阻止它。

    不过,您可以采取一些措施来增加难度:

    • 以经过混淆的加密 javascript 交付您的客户端。
    • 使用加密使您通过 websocket 接口发送和接收的消息难以被普通黑客解读。

    但即使你这样做了,一个坚定的攻击者也可以解密和反混淆你的 javascript,找到你用来加密消息的密钥,然后将它们恢复为纯文本并对他们所做的事情进行逆向工程。

    【讨论】:

      【解决方案3】:

      正如其他人所说,您将无法强制只有您自己的客户端代码与您的 websocket 对话。但是,您可以将 websocket 连接绑定到 Web 服务器的其余部分。

      例如,假设您通过网络服务器提供的登录表单对您的玩家进行身份验证。然后在成功登录后,您生成一个令牌并分发给客户端,并让您的客户端代码将令牌作为查询参数传递,您可以在 websocket 连接处理程序中进行检查:

      1. 用户将用户名/密码发布到http://server/play
      2. 生成一个随机令牌,作为(token, username, timestamp)存入数据库
      3. 生成并提供加载游戏 Javascript 代码并传递此令牌的 HTML 文档(例如,正文包含 myGame.start(<literaltoken>)
      4. 您游戏的 Javascript 连接到 ws://server:3000/?token=<token>
      5. 您的服务器查找令牌并可以将连接绑定到用户,和/或在令牌未知或太旧时拒绝连接

      如果您想避免必须在服务器端保留状态,则可以改为使用某个服务器端秘密密钥将令牌设为(username, timestamp) 的加密和签名 blob,然后在 websocket 处理程序中解密/验证该 blob .

      【讨论】:

        【解决方案4】:

        Basic Auth works 如此处的答案所示:HTTP headers in Websockets client API

        使用基本身份验证,您可以在 URL 中包含用户名和密码:

        ws://username:password@localhost:8888/
        

        或者,您可以实现自己的安全性,只需通过协议和用户名或其他会话标识符发送散列/md5/sha1 密码。 Of course it's good to have a token request before all that the client also passes up.

        【讨论】:

          【解决方案5】:

          Web 的性质使得这类事情变得更容易(对黑客而言),而对那些构建应用程序/网站的人而言则更难。通常你会使用“referer”来确保请求来自你的站点/域。这不是万无一失的,但适用于大多数情况。

          在 Html 5 中,我知道超链接不必发送引荐来源网址。这可能会更改为包括 websocket 等。

          即使您要使用某种盐对您的消息进行加密并将其哈希与您的消息一起发送以根据服务器上的哈希验证消息,您的客户端代码也可能对任何人都可用和可见,因此他们可以破解你的逻辑。

          WebSocket 规范一直在不断变化。一些浏览器暂时禁用或删除了对 WebSocket 的支持。

          WebSocket 握手协议(使用 Sec-WebSocket-Key1 和 Sec-WebSocket-Key2)本应使事情变得更安全,但该规范不适用于大多数代理服务器。您可以在此处阅读规范 http://www.whatwg.org/specs/web-socket-protocol/

          请注意,引入握手协议的目的非常不同。这不是您所追求的,而是为了防止客户端入侵服务器,除非服务器以握手响应,否则客户端无法与服务器通信。但在您的情况下,您需要在不知道客户的情况下以握手响应。

          所以我认为目前还没有可靠的方法来满足您的需求。

          【讨论】:

            【解决方案6】:

            我遇到了同样的问题。我正在编写 websocket->socket 代理来为我们的 JAVA/Flash 游戏制作 HTML5 客户端。他们在授权阶段使用自制加密来确保它是旧客户端。

            我不认为在 js 文件源打开时插入相同的加密代码是安全的。现在我在我的 WS 代理中隐藏了该身份验证算法,但我现在需要以某种方式检测未经授权的 WS 客户端 :)

            我正在使用来自网站的临时会话 ID 来检查是否在网站上授权了 websocket 客户端。但这并不可靠。

            我也在考虑某种机制,让客户端(浏览器)下载动态生成的 javascript 文件,运行它,然后发送到 websocket 服务器,它可以检查有效的结果。这样我就可以确定客户端是浏览器(或带有 JS 引擎的复杂机器人 :))。无论如何,这只是我的想法,似乎很难实现,我还没有尝试过。

            【讨论】:

              【解决方案7】:

              我想很简单,在 websocket 连接上添加一个标头,让它成为主机名或其他东西,并为其分配一些神秘的值,并在每次针对您的 webscoket 服务器建立 websocket 连接时检查这个神秘的值。

              【讨论】:

              • 您不能向 websocket 连接添加额外的标头。
              【解决方案8】:

              我建议您看看其他服务如何做到这一点。 例如,请参阅 pusher.com,特别是他们使用的私人频道。
              您可以在http://pusher.com/docs/pusher_protocol 了解有关他们协议的更多信息。
              你也可以看看他们client libraries的源码。

              【讨论】:

                【解决方案9】:

                以通常的方式进行登录/身份验证,然后在 Web 套接字升级请求中包含会话 ID。

                【讨论】:

                • Session id 很容易获取。我的意思是,这个人可以使用我的网页登录,获取会话 ID 并在他/她的程序中使用它来与套接字通信......我正在寻找一种解决方案,它不允许使用我的网页以外的任何其他客户端。但我开始相信现在不可能......
                • 我不知道这怎么可能。你无法控制客户端。这与任何人通过 HTTP 访问您的 Web 服务器并没有什么不同。您需要以完全相同的方式处理 websocket 命中。
                • 这听起来是个非常糟糕的主意,在每个 websocket 请求中传递会话 id 意味着您需要删除 cookie 的“httponly”标志,这使得 cookie 极易受到跨站点脚本的攻击。
                • @user3746259 不是 每个 websocket 请求。在初始 HTTP websocket 升级请求中。一旦 websocket 建立起来,它就是持久的,基于原始的 HTTP 升级请求。
                • Christian Lacdael 上面所说的基本上与我所说的相同(但不会被否决,哈哈)。
                猜你喜欢
                • 2013-08-23
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2011-12-26
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多