Same-Origin-Policy (SOP)
Same-Origin-Policy is a mechanism in browsers to protect the users from dynamically loaded document or script. It prevents running malicious scripts in browser to retrieve data from third party services. SOP specifies that dynamic requests can only be sent to URLs with the same Origin as the page they are requested from. Two URLs have the same origin if they share the same protocol, host and port. SOP assures that untrusted sites cannot perform authorized requests with the user's cookies, browser secrets or session identifiers by preventing requests to third parties. It only allows pages to call APIs in its own origin and blocks all other cross-origin requests. By default, modern browsers follow the SOP standards as a security mechanism.
Example: A user visiting https://untrustedsite.com
prevents the site from calling https://api.trustedsite.com
. The untrusted site pretends to call the trusted site on behalf of the user or without the user's permission. Such requests are blocked by SOP.
Cross-Origin-Resource-Sharing (CORS)
While SOP is an important security measure, it also restricts legitimate cross-origin API calls. CORS relaxes the SOP so that it can be called from a trusted origin that is in a different domain than that of what is currently being called from. CORS policy informs the browser which domains are allowed to access the response object of a request, which HTTP methods are allowed and if cookies should be sent with requests.
- The response header
Access-Control-Allow-Origin
specifies which origins are allowed to access the response objects from cross-origin requests. - The
Access-Control-Allow-Credentials
specifies if cookies need to be attached. Boolean value. - The
Access-Control-Allow-Methods
andAccess-Contol-Allow-Headers
header specifies which methods and headers are allowed.
All requests made from the browser should have a Origin
header.
Example: If Access-Control-Allow-Origin: https://trustedclient.com
is set on https://api.trustedserver.com
. Only the trusted client is able to access the response from the server. Calls from all other origins are blocked by the SOP.
Access-Control-Allow-Origin: *
is set to grant resource access to all domains.
Preflight requests
Since Access-Control-Allow-Methods
and Access-Contol-Allow-Headers
are response headers, there should first be a request made to fetch allowed methods and headers before sending out the actual request. Thus, browsers send a preflight request. The preflight request is an OPTIONS
request with the headers Access-Control-Request-Method
and Origin
. The API then responds with an empty response (HTTP 204) with the appropriate response headers. If the API does not implement CORS then the browser falls back to SOP and the cross-origin request is denied. Requests to resources on the same origin as the requesting site, however, are not preflighted and are also not subjected to SOP. Simple requests are also not preflighted, but do still require CORS headers to be set on response and will restrict access to response data if CORS policy does not allow.
WebSocket protocols (WS/WSS) and Cross-Site WebSocket Hijacking (CSWSH)
Cross-origin restrictions imposed by SOP and CORS policies do not apply to WebSockets because those restrictions are placed on HTTP responses while WebSockets work over WS
(WebScoket) or WSS
(WebSocketSecure) protocols. To initiate a WebSocket connection, however, the client has to connect to the server over HTTP. Yet, SOP and CORS do not have any effect because no HTTP response data is required to complete WS handshake and data transfer afterwards is completely over the WebSocket protocol WS/WSS. The initial handshake occurs via HTTP Upgrade
request, the response body is disregarded and the HTTP/HTTPS
protocol is upgraded to WS/WSS
protocol. Since CORS only restricts access to response and SOP cannot restrict access on WebSocket protocol, attackers could potentially establish a cross-origin WS connection and send malicious data or receive data from a subscribed channel. If a webserver supports WebSockets, an attacker could create a cross-origin WS connection to the server. Even though the server does not respond with CORS header, WebSocket connection will be established if the server supports WebSockets and sends a 101 Switching Protocol
status. From there on, the attacker can simply send and subscribe to data from the server. This is similar to Cross-Site Request Forgery (CSRF)
but is extended from write-only CSRF attack to full read/write communication via WebSockets.
Upgrade HTTP to WebSocket
Connection: Upgrade
Upgrade: websocket
The Upgrade
header field is used by clients to switch protocols with the server. The server responds with 101 Switching Protocols
response and the client-server can begin communicating in the new protocol. WebSockets is the most common use case for upgrading an HTTP connection.
Securing WebSockets
Since SOP and CORS are ineffective for WebSockets, the server implementation should verify the Origin
header on the Upgrade
request to prevent cross-site WS connections.
const io = require("socket.io")(httpServer, {
allowRequest: (req, callback) => {
const isOriginValid = check(req);
callback(null, isOriginValid);
}
});
Authentication/authorization should also be performed while establishing connection eg. via token.
As a developer, it is necessary to be aware of this attack and to know how to prevent it.
Happy Hacking!
Top comments (0)