3

Obviously TLS is a must for any and all secure authentication. Please turn your paranoia settings up to 11 for this.

Background: (In case people are unfamiliar with the WebSocket (WS) protocol and its idiosyncrasies) The WebSocket TLS (WSS) connection is a different connection from the HTTP TLS connection. This means that one can not automatically authenticate the other. Because of proxies, especially a malicious one performing a MitM attack, simply having the same remote IP address (or even the same session ID) does not guarantee that the two connections are from the same browser.

WS is a persistent TCP connection with a very limited API on the client side that does not allow inspecting of the TLS details for a WSS connections. It is designed to play well with firewalls and (non-malicious) proxies that restrict traffic to just HTTP traffic, and is desireable due to its ubiquity in modern web browsers.

In PHP, WS is (typically) implemented using a command line (CLI) script, which runs its own server accepting and managing the socket connections directly, rather than being mediated through an HTTP server. (If an HTTP server is involved, it is only to forward traffic after the successful upgrade, and becomes a transparent proxy for all purposes after the handshake.) Thus, the typical PHP superglobals are meaningless in PHP CLI.

Passing cookies is possible during the WS handshake, including a session ID. In PHP CLI it is possible (but ungainly) to access the current session data, even after a state change triggered by the HTTP side of things, if you know the session ID. However, because the cookies are passed only during the WS handshake, the WS server does not get notified of changes to cookies, such as the session ID.

AJAX remains authenticated through the HTTPS connection, of course, and I'm sure there's a way to leverage AJAX requests to authenticate WSS connections using the same browser.

Example Session Hijacking: Alice logs on to bob.com via normal HTTPS means, but happens to have a malicious proxy between them, owned by Mallory, running a MitM eavesdropping attack that has compromised the session ID.

Mallory then uses the session ID in his own session cookie to connect to the WSS server, which is where I run into my issues, because I don't know who to then differentiate between Alice's open and fully-authenticated browser and Mallory's completely different browser on a completely different computer.

So, knowing that the session ID is potentially insecure, is a prime target, and is immutable once the WS connection is initiated, how can I authenticate that a given WSS connection is running in the same browser instance on the same computer as a given HTTPS connection?

Edit: Once the HTTPS connection is started, Mallory does not attempt to interfere in order to prevent being detected. Thus, once TLS is established, the HTTPS connection is secure from Mallory from this point forward, but Mallory would have the session ID still.

Justification for this edge-case requirement: I'm writing open source WebSocket software, thus am unable to enforce protecting the session ID through means such as ensuring the session cookie has the Secure flag set, that the session ID gets regenerated, etc., but can enforce having the implementer include a client script that would aid in ensuring authentication across both mediums.

Ghedipunk
  • 5,766
  • 2
  • 23
  • 34
  • Also see [Preventing CSRF attacks against WebSocket communications](http://security.stackexchange.com/q/76816/8340), [Do WebSocket-powered web apps (e.g. “comet” apps) have to worry about CSRF?](http://security.stackexchange.com/questions/36158/do-websocket-powered-web-apps-e-g-comet-apps-have-to-worry-about-csrf/77051#77051) [Generating authentication token from PHP sessions](http://security.stackexchange.com/a/80160/8340) and [Secure socket communication between iOS device and 3rd party server](http://security.stackexchange.com/a/89494/8340). – SilverlightFox Aug 03 '15 at 10:28
  • Basically you can verify the Session ID before the Websockets upgrade and then rely on TLS/SSL to keep this connection private. Once the upgrade is made, you know that socket was opened by the client that logged in under that Session ID. – SilverlightFox Aug 03 '15 at 10:29
  • What's the difference between Mallory stealing the session ID to use in a websocket, and Mallory stealing the session ID to make HTTP requests? – user253751 Jun 14 '19 at 02:19

2 Answers2

2

The WebSocket TLS (WSS) connection is a different connection from the HTTP TLS connection.

A WebSocket connection is created sending a HTTP request containing the wish to upgrade the connection to WebSocket and by receiving a HTTP response granting this wish. From then on the WebSocket protocol is spoken inside the upgraded HTTP connection.

This means that the common security properties of HTTP are still usable with WS, i.e. things like basic authentication or verifying the identity of the peer against a session cookie given by a previous login.

It also means that the security properties of TLS can be used as with normal HTTPS connections. Like HTTPS, which is HTTP spoken inside a TLS connection, WSS is WS inside a TLS connection. This also means that preventing man-in-the-middle attacks by validating the certificates is done exactly the same way as with HTTPS, because every WSS connections starts as HTTPS connection.

If I understand you right you consider that Mallory manages a man-in-the-middle attack against the connection at least once. If Mallory is able to do this he must be able to man-in-the-middle the TLS connection and in this case game over is anyway, no matter if WebSockets are used or not. If Mallory is instead gaining the information from a non-TLS connection (i.e. HTTP not HTTPS) than you have a design bug in your application if you use unprotected authorization data for authorization inside secured connections, no matter if HTTPS or WSS. And no TLS or other methods can make compromised authorization information magically safe to use again.

Steffen Ullrich
  • 184,332
  • 29
  • 363
  • 424
  • They're still different systems, and the session ID is explicitly suspect in this question. HTTP authentication can't work for WebSockets, because the server itself is running through the command line, rather than CGI, so can't check back with the web server to verify. The WS RFC explicitly states to start a new TLS handshake, and all browsers send a new TLS handshake as the first bytes, so best case scenario the web server handles the TLS handshake, but there are still no clues other than the (very probably compromised) session ID. – Ghedipunk Jul 30 '15 at 19:51
  • Also, once TLS starts for HTTP traffic, Mallory stops being an active attacker (No eavesdropping possible, no injecting XSS, etc.) and can only monitor to see if the connection is still open. As you say, if they can actively MitM a TLS connection, it's game over, so no sense in worrying about it. Since this is for software intended to be deployed by many third parties, I can't enforce session ID discipline, which means for designing as if the session ID is always suspect, so I need an extra way to authenticate the new connection compared to the HTTPS connection that is ongoing. – Ghedipunk Jul 30 '15 at 19:56
  • @Ghedipunk: WebSocket can use basic authentication and can have access to the cookies. All these data are contained in the HTTP request initiating the WebSocket connection. If your specific use of WebSockets has no access to these data then this is a limit of your implementation only, not of WebSockets. Also, it is not possible to secure a connection somehow if the initial data leading to this connection might already be compromised as they are in your attack scenario. – Steffen Ullrich Jul 30 '15 at 20:29
  • @Ghedipunk: Why should an attacker stop with active MITM after the first success? If the attacker is able to MITM once then he can do it again. And if you think your customers which deploy the software are unable to keep the ID secure, then why do you think the will be able to maintain the rest of the security needed for deployment. I have the feeling that both your assumptions about the attacker and the assumptions about the customers have not much to do with reality. – Steffen Ullrich Jul 30 '15 at 20:34
  • I'm assuming that the customers are PHP developers smart enough to write a WebSocket app. PHP has a long legacy of bad security practices, so even good developers don't know about session hijacking, but once they catch wind of it, they'd be quick to address it. Also, I'm not protecting against government agencies that can successfully MitM a TLS connection, I'm only worried about people doing MitM against a non-secure HTTP connection, which, as I've realized, if their system is vulnerable to session hijacking, there is nothing I can do as the WS framework developer. – Ghedipunk Jul 30 '15 at 20:43
  • 1
    @Ghedipunk: Since you assume that authorization information are compromised by the attacker no TLS and no other constructs will help, since you cannot built trust based on something which is not trustworthy (i.e. the authorization information). – Steffen Ullrich Jul 30 '15 at 20:47
  • One small nitpick before I accept this answer: The session ID can be regenerated, which helps prevent hijacking, and OWASP recommends regenerating the ID as part of login/logout ( https://www.owasp.org/index.php/Session_Management_Cheat_Sheet#Renew_the_Session_ID_After_Any_Privilege_Level_Change ). I didn't want to accept that as THE answer because I didn't think of the attacker creating a new HTTPS connection with the same session ID. By the way, thank you very much for making me question my assumptions; this has been very helpful. – Ghedipunk Jul 30 '15 at 21:02
  • @Ghedipunk: while a session-ID can be generated to limit the impact of a successful hijack (and not to prevent it) you can do the same with WebSockets: limit the time a WebSocket connection can run and on re-establishment it needs to be validated again with the new session. – Steffen Ullrich Jul 30 '15 at 21:17
  • @Ghedipunk: apart from that you need a tight connection between the session and the WebSocket anyway: if the user logs out the WebSocket connection must be forcible closed by the server, at least if it is running under the assumption that the user is stil authorized. And the same should be done if the session ID authorizing the WebSocket connection is no longer valid because it expired. – Steffen Ullrich Jul 30 '15 at 21:20
1

I believe your premise is flawed. Alice doesn't log on to bob.com via normal HTTPS means, because Alice sees the invalid certificate error and smartly decides not to enter in her credentials. If Alice chooses to ignore the warning and proceed anyway, then now she has the same problem that she would have on any financial or high security site too. Her credentials may have been compromised along with all of the data that she has access to.

If a MITM attack is spoofing the browser's connection to begin with, there is no way for your server to tell the difference. The spoofer can make the request look like whatever it wants.

To make sure that the session ID is secure, the best you can do on your end is first make sure the connection is encrypted, then allow the login, then after authenticating the user generate the session ID. But you'll still have to hope that a user presented with a certificate error due to a MitM attack does not proceed to login.

TTT
  • 9,122
  • 4
  • 19
  • 31
  • I was thinking more along the lines that Mallory was seeing non-TLS traffic, such as the initial request to bob.com before Alice started logging in and the connection switches to HTTPS, thus was a passive MitM to collect the session ID and not trigger any TLS warnings, thus once TLS is established, the connection is secure, and only becomes an active attacker once they attempt to connect through the WebSocket. – Ghedipunk Jul 30 '15 at 18:41
  • Thank you, though; that does stress the need to ensure that the Secure and non-Secure session ID cookie doesn't mix, and that the non-Secure session ID never points to an authenticated user. I'm working on implementing TLS and session management in open source WS server software, so while I can most certainly stress the importance of not mixing secure and non-secure session IDs, I can't enforce it on the systems that implement the server, so the eavesdropping is still an issue. I'll update my question. – Ghedipunk Jul 30 '15 at 18:47
  • By the time the user is logging in, the connection should already be encrypted. If it is not, then this would be a problem. – TTT Jul 30 '15 at 18:47
  • 1
    I see what you mean, and I agree with you. You can't associate a session ID with an authenticated user until after the user logs in. And the user can't login until after TLS is established. So, first encrypt, then login, then session ID. This should be safe. If there is a MitM, then no login should happen at all. (In a perfect world where people heed the warnings.) – TTT Jul 30 '15 at 18:53
  • I just realized that there is no way to authenticate the HTTPS connection based on session ID alone either, if the session ID is also suspect in the WSS connection. (Or more precisely, verify that Mallory isn't hijacking the session, because any party in a TLS connection can start a brand new connection at any time.) Thus, if the session isn't regenerated on the Web side after logging in (and obviously after starting TLS) but before starting WebSockets, then the WebSocket side can never be securely authenticated. – Ghedipunk Jul 30 '15 at 20:29
  • ...Thus, I have to trust the people implementing the software on their servers to properly regenerate the session and there's nothing I can do to strictly enforce it. So... to make my long-windedness short(er), since your comments touch this point specifically, if you edit your answer, I'll be very happy to accept it. – Ghedipunk Jul 30 '15 at 20:31