Html Websocket 服务器:如何授权客户端?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5089528/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Websocket server: how to authorize clients?
提问by Michal
I am currently building a webpage with a game using html5 canvas and websockets. I have a websocket server written in perl running on server:3000. On the server I have also installed apache, and made a website that the user can visit: http://server/. javascript on this page creates a websocket to ws://server:3000
我目前正在使用 html5 canvas 和 websockets 构建一个带有游戏的网页。我有一个用 perl 编写的 websocket 服务器,在 server:3000 上运行。在服务器上我也安装了apache,并制作了一个用户可以访问的网站:http://server/。此页面上的 javascript 创建一个 websocket 到 ws://server:3000
Connection works and I can send messages from my browser and get the responses, everything shown in a div for now. The messages that I send are for now only "message:...", so the server knows that it is a message and outputs '...' to all users currently connected to the "game".
连接工作,我可以从我的浏览器发送消息并获得响应,现在所有显示在 div 中。我发送的消息现在只是“消息:...”,因此服务器知道这是一条消息,并向当前连接到“游戏”的所有用户输出“...”。
Now the problem is that anyone could write their own client that would connect to ws://server:3000 and send/receive appropriate messages. This way they would use my backend, but not my client (I would like them to play only from http://server/).
现在的问题是任何人都可以编写自己的客户端来连接到 ws://server:3000 并发送/接收适当的消息。这样他们就可以使用我的后端,而不是我的客户端(我希望他们只能从http://server/播放)。
How can I ensure that only my client is used? The main concern is cheating. You could write a bot that connect to a port and plays for you by sending messages and intepreting the ones that it receives...How to overcome this issue?
如何确保只使用我的客户端?主要担心是作弊。您可以编写一个连接到端口并通过发送消息并解释它接收到的消息来为您播放的机器人......如何克服这个问题?
回答by Christian Lacdael
I'm using a Jetty web server.
我正在使用 Jetty Web 服务器。
I am using Basic authorisation. I used this at first simply because it was easy to implement. However, after discovering the authorisation issue presented by websockets, I think basic authorisation is a good mechanism to use.
我正在使用基本授权。我最初使用它只是因为它易于实现。但是,发现websockets带来的授权问题后,我认为基本授权是一个很好的使用机制。
The upgrade request header has authorisation data hashed in it:
升级请求标头中包含散列的授权数据:
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
In my websocket server, with each OnMessage event I call:
在我的 websocket 服务器中,我调用每个 OnMessage 事件:
session.getUpgradeRequest().getUserPrincipal()
I can then use this information to decide whether the data is authorised to be processed. Also, I check the origin of the socket in the OnConnect event:
然后我可以使用这些信息来决定数据是否被授权处理。另外,我在 OnConnect 事件中检查了套接字的来源:
session.getUpgradeRequest().getOrigin()
回答by Periata Breatta
What you are asking for is impossible to achieve. You can take steps to make it difficultfor a third party to make an unauthorised client, but in the end as long as the third party is able to use your legitimate client, they can always watch what it does and copy it, and there is nothing you can do to stop that.
你所要求的是不可能实现的。你可以采取措施,使其难以对第三方进行未经授权的客户端,但最终只要第三方能够使用您的合法客户,他们可以随时观看它做什么,并把它复制,并有你无能为力阻止它。
There are things that you can do to make it harder, though:
不过,您可以做一些事情来让它变得更难:
- Deliver your client as obfuscated, encrypted javascript.
- Use encryption to make the messages you send and receive through your websocket interface difficult for a casual hacker to interpret.
- 将您的客户端作为经过混淆的加密 javascript 交付。
- 使用加密使您通过 websocket 接口发送和接收的消息难以让普通黑客解读。
But even if you do this, a determined attacker can decrypt and deobfuscate your javascript, find the key you're using to encrypt the messages, and then revert them to plain text and reverse engineer what they do.
但即使您这样做,坚定的攻击者也可以解密和反混淆您的 javascript,找到您用来加密消息的密钥,然后将它们还原为纯文本并对它们所做的进行逆向工程。
回答by robx
As others have remarked, you won't be able to enforce that only your own client-side code talks to your websocket. However, you can tie websocket connections to the rest of your web server.
正如其他人所说,您将无法强制要求只有您自己的客户端代码才能与您的 websocket 对话。但是,您可以将 websocket 连接绑定到 Web 服务器的其余部分。
For example, suppose you authenticate your players via a login form served by your web server. Then on successful login you generate a token that you hand out to the client, and have your client code pass the token as a query parameter that you can check against in your websocket connection handler:
例如,假设您通过 Web 服务器提供的登录表单对玩家进行身份验证。然后在成功登录时生成一个令牌,您将其分发给客户端,并让您的客户端代码将令牌作为查询参数传递,您可以在 websocket 连接处理程序中检查它:
- user posts username/password to
http://server/play
- generate a random token, put it in a database as
(token, username, timestamp)
- generate and serve an HTML document that loads your game's Javascript code, and passes this token (e.g. the body contains
myGame.start(<literaltoken>)
- your game's Javascript connects to
ws://server:3000/?token=<token>
- your server looks up the token and can tie the connection to the user, and/or reject the connection if the token is not known or too old
- 用户将用户名/密码发布到
http://server/play
- 生成一个随机令牌,将其放入数据库中
(token, username, timestamp)
- 生成并提供加载游戏 JavaScript 代码的 HTML 文档,并传递此令牌(例如,正文包含
myGame.start(<literaltoken>)
- 您游戏的 Javascript 连接到
ws://server:3000/?token=<token>
- 您的服务器查找令牌并可以将连接绑定到用户,和/或如果令牌未知或太旧则拒绝连接
If you want to avoid having to keep state server-side, you could instead make the token an encrypted and signed blob of (username, timestamp)
, using some secret server-side key, and decrypt/verify that blob in the websocket handler.
如果您想避免必须保持服务器端的状态,您可以(username, timestamp)
使用一些秘密的服务器端密钥使令牌成为加密和签名的 blob ,并在 websocket 处理程序中解密/验证该 blob。
回答by robx
Basic Auth worksas indicated by this answer here: HTTP headers in Websockets client API
基本身份验证的工作方式如下此答案所示:Websockets client API 中的 HTTP headers
With Basic Auth you can include the username and password in the URL:
使用基本身份验证,您可以在 URL 中包含用户名和密码:
ws://username:password@localhost:8888/
Alternatively you can implement your own security just sending hashed/md5/sha1 passwords through the protocol and a username or some other session identifier. Of course it's good to have a token request before all that the client also passes up.
或者,您可以实现自己的安全性,只需通过协议和用户名或其他会话标识符发送散列/md5/sha1 密码。当然,在客户端也通过之前有一个令牌请求是很好的。
回答by Shiv Kumar
The nature of the web is such that this sort of thing becomes easier (for the hackers) and harder for those building applications/websites. Normally you'd use "referer" to sort of ensure that the request is coming from your site/domain. It's not fool proof but works for the majority of cases.
网络的性质使得这类事情变得更容易(对于黑客而言),而对于那些构建应用程序/网站的人来说则变得更难。通常您会使用“referer”来确保请求来自您的站点/域。这不是万无一失的,但适用于大多数情况。
In Html 5 I know hyper links don't have to send the referer. That could change to include websockets and the like as well.
在 Html 5 中,我知道超链接不必发送引用者。这可能会更改为包括 websockets 等。
Even if you were to encrypt your message with a salt of some sort and send the hash of it along with your message to validate the message against the hash on the server, your client side code is potentially available and visible to anyone so they can crack your logic.
即使您要使用某种盐加密您的消息并将其散列与您的消息一起发送以根据服务器上的散列验证消息,您的客户端代码也可能对任何人可用且可见,因此他们可以破解你的逻辑。
The WebSocket spec has been is constant flux. Some browsers have either disabled or removed their WebSocket support for the time being.
WebSocket 规范一直在不断变化。一些浏览器暂时禁用或删除了对 WebSocket 的支持。
The WebSocket handshake protocol (using Sec-WebSocket-Key1 and Sec-WebSocket-Key2) was supposed to make things bit secure but this spec won't work through most proxy servers. You can read the spec here http://www.whatwg.org/specs/web-socket-protocol/
WebSocket 握手协议(使用 Sec-WebSocket-Key1 和 Sec-WebSocket-Key2)应该使事情变得有点安全,但该规范不适用于大多数代理服务器。你可以在这里阅读规范 http://www.whatwg.org/specs/web-socket-protocol/
Note that the handshake protocol was introduced for a very different purpose. That is not what you're after but rather to prevent a client from hacking a server such that unless the server responds with a handshake the client can't communicate with the server. But in your case you'll need to respond with a handshake without knowing the client.
请注意,引入握手协议的目的非常不同。这不是您想要的,而是为了防止客户端入侵服务器,除非服务器通过握手响应,否则客户端无法与服务器通信。但是在您的情况下,您需要在不知道客户端的情况下通过握手进行响应。
So I don't think there is a reliable way yet to do what you need.
所以我认为还没有一种可靠的方法来做你需要的。
回答by Sergey Birukov
I came to the same problem. I'm writing websocket->socket proxy to make HTML5 client for our JAVA/Flash game. They use self-made encryption at authorization stage to make sure it is legacy client.
我遇到了同样的问题。我正在编写 websocket->socket 代理来为我们的 JAVA/Flash 游戏制作 HTML5 客户端。他们在授权阶段使用自制加密来确保它是旧客户端。
I don't think it is secure to insert the same encryption code as the sources of js file are open. For now I hid that auth algorithm in my WS proxy, but I need to somehow detect unauthorized WS clients now :)
我认为在 js 文件源打开时插入相同的加密代码是不安全的。现在,我将该身份验证算法隐藏在我的 WS 代理中,但我现在需要以某种方式检测未经授权的 WS 客户端:)
I'm using temporary session ids from the web site to check if a websocket client is authorized on the web site. It is not reliable though.
我正在使用来自网站的临时会话 ID 来检查 websocket 客户端是否在网站上获得授权。虽然它不可靠。
Also I'm thinking on some mechanism to make a client (browser) to download dynamically generated javascript file, run it, and send to websocket server, that can check for the valid result. That way I can be sure that the client is browser (or complicated bot with JS engine :) ). Anyway, that are just my thoughts and it seems hard to implement, I didn't try that yet.
此外,我正在考虑某种机制,使客户端(浏览器)下载动态生成的 javascript 文件,运行它,然后发送到 websocket 服务器,该服务器可以检查有效结果。这样我就可以确定客户端是浏览器(或带有 JS 引擎的复杂机器人 :))。无论如何,这只是我的想法,似乎很难实施,我还没有尝试过。
回答by securecurve
Very simple I guess, add a header on websocket connect, let it be hostname or something, and assign to it some cryptic value, and check this cryptic value everytime a websocket connection is made against your webscoket servers.
我想很简单,在 websocket 连接上添加一个标头,让它成为主机名或其他东西,并为其分配一些神秘值,并在每次针对您的 webscoket 服务器建立 websocket 连接时检查这个神秘值。
回答by Kurt Pattyn
I propose you have a look at how other services do this.
See for instance pusher.com, specifically the private channels they use.
You can learn more about their protocol at http://pusher.com/docs/pusher_protocol.
You can have a look at the source code of their client librariesas well.
我建议您看看其他服务是如何做到这一点的。参见例如pusher.com,特别是他们使用的私人频道。
您可以在http://pusher.com/docs/pusher_protocol 上了解有关其协议的更多信息。
您也可以查看他们的客户端库的源代码。
回答by nilskp
Do login/authentication the usual way and then include the session id in the web socket upgrade request.
以通常的方式进行登录/身份验证,然后在 Web 套接字升级请求中包含会话 ID。