spring-securitycorscsrfspring-websocketsame-origin-policy

Why is CSRF protection needed for connecting to websockets if Spring Security implements Same Origin Policy at server level?


As per Spring Security documentation, for websockets there is SOP implemented at the server level, as opposite to regular http where the browser implements SOP. However, Spring Security also requires a CSRF token for CONNECT messages in order to ensure SOP. From Spring documentation:

Any inbound CONNECT message requires a valid CSRF token to enforce the Same Origin Policy.

How can a CSRF attack take place if SOP is implemented at the server level? Is the connection request a simple request? Even if it is, won't it just be rejected by the server? As far as I know tampering with the origin header is not possible in a browser. I have also checked this thread, but it is still not clear if a server-side check of origin is enough.

Any help is appreciated !


Solution

  • Since nobody could give me an answer I will try to post here my rationale for why checking the Origin header on the server should be enough for security of websockets. Mind you that I am no security/ websockets expert. First we need to understand why we need a CSRF token when it comes to http requests and why SOP implemented by browsers is not enough.

    Browsers do not enforce SOP for simple requests, which means the request will be sent together with the cookies and be processed by the server, but the response will not be available for reading. Since the request was processed, the damage was already done. In order to overcome this limitation, CSRF token was introduced as a defense mechanism.

    I would say that even for http requests, server side Origin check should be enough for CSRF protection, as, if implemented properly, it should block the request before processing takes place. For websockets it should be even safer, as working with websockets is a 2 step process:

    1. Connect to the endpoint (issue a GET ws://example.com:8080/ HTTP/1.1)
    2. Subscribe and start exchanging messages (do actual business processing)

    Because we check the origin on the server, the bad actor will never reach step 2, as the request will be blocked by step 1.

    OWASP moved the server side origin check to the list of defense in depth strategies. As I understood from this link, it is due to some browsers (like IE11) not sending the Origin header in some rare cases. Apparently those cases are rare enough to ignore. Also I assume that if no Origin header is set, a good implementation will block the request by default (hopefully Spring Security does it).

    You might ask why go to the trouble of not using CSRF token if Spring Security provides it out of the box. The reason is I have added Spring Cloud Gateway in front of the microservice that uses websockets, and I have implemented security (CSRF token included) at the gateway level. However, while the REST API is secured (because gateway is sending Authorization header via TokenRelay filter, which makes the microservice skip CSRF validation, essentially trusting the gateway) it has no effect on websockets. Also enabling websocket security in the microservice will enable CSRF token, but requests will fail, as I am sending the gateway’s CSRF token (there are 2 separate token repositories, one for gateway and one for microservice). I will probably add another question for this topic only. As a consequence, I found myself forced into disabling CSRF token for websockets and questioning if it is actually needed.