Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
Protect against cross origin websockets. #980
Since CORS headers don't exist in WebSockets land, we need to check origin and host. This adds origin and host checking within the WebSocketHandler.
The opinionated piece of this PR is that cross origin is disabled by default.
If a user wants different behavior, they'll need to override
We should definitely make it easy for applications to check the origin header, and it should probably be turned on by default (I'm not 100% convinced here, but I was surprised when I learned that cross-origin websockets were allowed by default so it's probably better to be conservative). A request with no origin header should probably be allowed rather than rejected - browsers always send the origin, so a request without one is coming from a source where the origin header would provide no meaningful authentication anyway.
Because of proxies like nginx and haproxy, a tornado server doesn't necessarily know its correct origin (it may be listening on another port than the one the client connects to). We need some way to tell Tornado of its true origin. This could either be another option at the WebSocketHandler level, or perhaps we could put it on HTTPServer to make it a part of the incoming request (by analogy with the existing
You added the
When comparing origins the default ports
@bdarnell - Thank you so much for the excellent feedback! I'm never sure how PRs out of nowhere will be received on a project.
It is a protection for endusers on a browser, so that's completely sane. I'll change to match that.
Just the feedback I needed. Wasn't quite sure how to structure this. That's a really good idea. Disable by default but let users override how the checking is done, to include checking for particular origins?
In the server I'm using, which is a client side application, the ports are actually high ports and do appear both on the origin and the header. I can provide samples of this directly to you if necessary.
I submitted this on the road but I'll be back to it soon, including getting tests to pass (and adding some).
While adding tests, I noticed how terrible of an interface I made by putting this in _execute. If they override it, they'd have to provide a default argument for it to do anything different.
That's so ugly.
This is my first time hacking on Tornado, so I'm a bit lost on how to get to certain data and responses within the tests. In particular, I would want to verify the status code that was returned to the WebSocketClientConnection. Can you point me in the right direction so I can make better, more robust tests?
On a side note, I noticed that some of the tests aren't enabled (by way of the
Good catch on the test_websocket_callbacks bug - that wasn't intentional. I'll fix that and I think I've got a trick to detect and prevent these in the future.
For testing the error codes, you should be able to catch the HTTPError raised by websocket_connect - see test_websocket_http_fail.
It's not always possible for an application to pass in all its allowed origins (unless perhaps we introduce some sort of wildcard matching, but that just invites complexity), so I'd turn the interface around a bit:
Cool. That helped. Also made me realize I had the origin check in the wrong spot. Yay for tests.
This is in a happy state now I think. Ready for comments or merging!