-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Sending Authorization Header on handshake? #196
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Currently no. See https://github.com/sockjs/sockjs-node#authorisation for more information. |
That makes sense, thanks for the response. |
do you plan to support it in future release ? |
@francoisledroff No. Read the link, it is a security issue to allow them because of the iframe transports. Authorization should occur over the SockJS channel. |
@brycekahle What about supporting it in a mode where you exclude IFrame based transports (with an explicit log message) ? Or the other way, you include the user provided Authorization header only if there is no IFrame based transport configured by the user. Another strong argument in favor of supporting this is Basic Authentication. Based on my tests on Chrome, passing username and password in the URL, for example |
@sdeleuze That becomes a slippery slope. Once you start supporting that, then the server needs to have options for setting CORS headers. What is your use case? Your example code would be incredibly insecure because the password is in plaintext, in the open. |
@brycekahle The basic authentication example was just coming from this SO question. I agree with you it is not very secured. But I am a lot more concerned by the impossibility to use OAuth2 bearer token style security with SockJS, since it requires to customize the request headers. This kind of mechanism has been designed with cross domain in mind, being able to use it with SockJS makes sense IMO. |
@sdeleuze 👍 |
For example with Spring Session you have option, to exchange session id with cookie, which automatically is send by browser with handshake or use header to send it (major thing if you deal with single page applications). I think there should be a way, to include some headers with handshake, even if they are not connected with authentication. Anyway session id is sent with every normal http request. Reconsider reopen this issue, because it may help many people. |
@Mati20041 Session id is another form of authentication. The problem is a security one. If anyone can embed an iframe on the SockJS host domain, which automatically authenticates, and they can cause that iframe to send any message to your server, they now have full control. Anyone can secretly embed your SockJS iframe and do whatever they like with it. This problem doesn't magically get solved. It would require fundamentally changing how SockJS works. |
It is a problem which current Single Page Applications must face. Just like you can take the token, and use it outside the browser to use the API. Well, at least thank you for response. |
@brycekahle but this is problem only for cookie based authentication, right?! |
@Mati20041 The difference is you can't embed a SPA and control it from outside. With SockJS you can because of how it is designed to use the iframe as middlemen to support browsers without CORS. @IRus Any authentication value that is automatically sent by the browser would have this issue. |
@brycekahle Cookies automatically sends, but token that stored, for example, in local storage - not. |
+1 for custom header to hold stateless authentication information (token) to be validated during hand shake. |
Is there a reason you cannot authenticate over the SockJS channel as soon as the channel opens? |
In my case It is a problem with binding user to websocket in Spring ( I'm aware that is more Spring problem than SockJS - that's why I have asked about this feature and I need to point that also in Spring Community).
So it says that Authentication has to be in Handshake stage (for example by session cookie). There is no problem when I use cookie session option, but it will create problems when I switch to session over header. There was some asks in stackoverflow about how to authenticate user in opened websocket but with no solution. Example question: Only solution for now that I have found is to pass token by query parameters thanks to #72 . I don't understand why query parameters might be more secure than sending informations in headers. |
@brycekahle I have a similar case like @Mati20041 using the spring web socket stack. We have a stateless application that uses a JWT token to authenticate the user. The token is part of each request. The application has REST and WebSocket resources and we want to use the same system for authentication and authorization. I managed to pass the token as query parameter to SocksJS and check the token in a custom spring HandshakeInterceptor. But instead of using query parameters I would like to pass those information in a HTTP header during first connect to establish the web socket connection. |
Query string is the only thing that works in all transports anyways. JSONP and Websockets don't have a way to set custom headers |
How do I pass the query parameter then? |
Just add |
Lol, I was using version 0.3.4 from the dist folder instead of 1.0.3... |
Bryce, we've built a stateless application that manages its own credential lifecycle semantics. This means that embedding the sockjs iframe wouldn't result in auto-authentication as we manually provision the credentials as headers when setting up sockjs from some persistence store ( localstorage/cookies ). The inability to pass headers with AuthN/AuthZ information is forcing us to include it as query parameters and to implement a Spring AuthenticationProvider that is able to process those query parameters. The side-effects are worse in that now we're having to update our load balancer and logging to not log query parameters. I'm not sure I understand the issue with allow headers to be passed through in the initial connection, if the header contents must come from the iFrame host. Another malicious sites wouldn't be able to furnish the user authentication headers without having acquired them in an alternate fashion. |
You can't pass headers for JSONP and Websockets. That isn't sockjs limiting it, but the specification. I suggest sending the auth data over the sockjs connection instead of relying on HTTP semantics. |
I see. Sad times that the protocol doesn't support this. Unfortunately our gating authentication is handled by spring at the time the connection is initiated. Looks like we'll have to go with query parameters for now. |
@brycekahle
So where does the specification of websocket limit it? |
@Mati20041 Cookies are dangerous for the reason specified many times. Authorization headers would have to be specified by including the username and password in the connection url. There is no API to specify any custom headers. That is why it is limited, you have no secure way of specifying custom headers. That is also just websockets and doesn't solve it for JSONP. |
@Mati20041 The IETF spec says "MAY", not must, and unfortunately for all of us, the major browser vendors did not support setting headers when they implemented the JavaScript WebSocket API Spec found here: https://html.spec.whatwg.org/multipage/comms.html#network I share in the angst that this lack of header support has caused, but it's not a SockJS issue. The browser's must first allow JavaScript to set headers on a WebSocket request (and apply security constraints like we have with CORS) before SockJS could 'pass along' that capability. Like @geekbeast , we will have to pass our token as a query parameter instead of its normal Authorization header position, and I'll have to create a custom interceptor to validate the token before permitting the handshake to continue. |
If it is a security issue to send Authorization headers or cookies over the handshake http call, must the browser be prevented from doing so by itself? As an example, consider this flow of messages:
Is this similarly insecure? Even without the native browser loging form after 401, a SESSIONID might be set for the domain if the domain server also serves session-based http content, and the user logged in previously. Must a server for websockets prevent Basic auth for all http calls, because of SockJS limitations? Must a server with websockets run on a different domain than for serving other http calls with cookie-based sessions, to prevent the browser from sending session cookies? |
For people who reach this issue in the future looking for a solution to token-based Spring+SockJS websocket authorization, I have posted a non-query-parameter workaround to this Spring functionality gap here: http://stackoverflow.com/questions/30887788/json-web-token-jwt-with-spring-based-sockjs-stomp-web-socket/39456274#39456274 (Sorry to the SockJS community for the noise not directly related to SockJS) |
One last update, the Spring Framework now supports token-based authentication using headers at the STOMP protocol level after the SockJS session is established. This is just a pointer for those who come across this ticket. Please do not leave further questions about the feature here. |
I'm still confused on how to keep the initial request (which is http) secured. Are we supposed to open up the http endpoint to public access and then only handle the authorization at the stomp-protocol level? Also, from what I can tell all the examples (including the ones included in the spring docs) handles the authorization lookup at connection time, but it does not actually force a disconnect if the authorization fails. How is this supposed to be handled? Just let danging un-authorized websocket connections stay around for as long as the clients want them to? My hope was that StopJS would allow me to just put an "Authorization: Bearer ..." header into the initial request so I could keep the info endpoint "secured." I realize this doesn't secure the websocket itself, but at least I can prevent expired tokens (i.e., not a hacker, but just a user with an old token) from establishing connections and unknowingly leaving those connections open. Am I missing something? |
@francoisledroff, setting 'X-Frame-Options' to 'SAMEORIGIN should fix the issue, shouldn't it? This way iframe won't load on some other domain except ours and so it won't communicate with other websites. I was able to integrate sockjs to Spring Security's CSRF filter by adding header from cookie to XHRReceiver and XHRSender. I consider this secure, as attacker won't have access to iframe transport (due to iframe's SAMEORIGIN policy). XHR and WS will be unaccessible either (because it would be crossdomain requests). |
You also use access_token as parameter instead to use Authorization in Header.
|
Updating Spring Framework's token-based authentication docs. |
@SammyVimes Just a heads-up, XHR has a same-origin policy, but a WS endpoint can be accessed from any domain by default. You have to implement your own same-origin policy by checking the origin header on the server. |
hey guys, I am trying to authorize a websocket client connection to a server with a token on C#, however whatever I do, it fails. can someone please help me on this issue. it is much appreciated. Cheers |
Is this a secure solution? Wouldn't people be able to sniff your token if you did this? |
There is no difference in this case between header and query parameter. But using good old cookie with http-only, samesite and secure flags should be preferred |
Is it possible to specify an
Authorization
header on the socket connection handshake?The text was updated successfully, but these errors were encountered: