This article is currently an experimental machine translation and may contain errors. If anything is unclear, please refer to the original Chinese version. I am continuously working to improve the translation.
Same-Origin Policy (SOP) refers to a security mechanism in Web browsers that allows a web page’s script to access data from another web page only if both pages share the same URI, hostname, and port number. When two websites meet these conditions, they are considered to have the same origin. This policy helps prevent malicious scripts on one webpage from accessing sensitive data on another webpage via the Document Object Model (DOM).
Cross-Origin Resource Sharing (CORS) is a mechanism that allows restricted resources on a web page to be accessed by web pages from different origins.
Cross-Site Request Forgery (CSRF), also known as a one-click attack or session riding, commonly abbreviated as CSRF or XSRF, is an attack method that tricks a user into performing unintended actions on a web application where they are already authenticated.
0x00 SOP & CORS
In browsers, the concept of origin exists. Two URLs are considered same-origin if their protocol, port (if specified), and host are identical.
Browsers enforce the same-origin policy by default, which restricts interactions between pages from different origins. Cross-origin requests are therefore subject to limitations.
CORS configuration is determined by response headers such as Access-Control-Allow-xxx sent by the server. These headers mainly control client-side AJAX requests.
For example, in a front-end and back-end separated development setup, accessing the front-end at http://localhost:63343/, where JavaScript code attempts to access a back-end API (http://localhost:8080/user/auth) that hasn’t been configured with CORS:
1 | const backend_url = "http://localhost:8080" |
Chrome throws an error and the request fails:
Access to XMLHttpRequest at 'http://localhost:8080/user/auth' from origin 'http://localhost:63343' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
However, some requests are allowed by default. Specifically, only simple requests that meet the following criteria are temporarily permitted. However, if the server’s response does not include the Access-Control-Allow-Origin header, or the allowed origin does not include the current origin, the browser will block the response from being accessed by JavaScript—even though the request may have already reached and been processed by the server. Similarly, if the request includes cookies but the response lacks the header Access-Control-Allow-Credentials: true, the browser will also block the response.
Simple Requests
Certain requests do not trigger a CORS preflight request. Such requests are referred to as “simple requests” (note that this term is not part of the Fetch specification, which defines CORS). A request qualifies as a simple request only if it meets all the following conditions:
- Uses one of the following methods:
- Apart from headers automatically set by the user agent (e.g.,
Connection,User-Agent) and those forbidden by the Fetch spec, only the following CORS-safe listed headers can be manually set:
AcceptAccept-LanguageContent-LanguageContent-Type(with additional restrictions)- The
Content-Typeheader value must be one of the following:
text/plainmultipart/form-dataapplication/x-www-form-urlencoded- The request must not use any event listeners on the
XMLHttpRequestobject; theXMLHttpRequest.uploadproperty may still be accessed.- The request must not use a
ReadableStreamobject.
(It’s worth noting that regular POST form submissions are allowed across origins by default—for compatibility reasons.)
For non-simple (complex) requests, the browser first sends a preflight request to check the server’s CORS configuration.
If CORS is not configured, or the allowed origins do not include the current origin, the browser will not send the actual request, meaning the server never receives it.
For more details, see: https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS
In Spring Boot back-end development, the simplest way is to add @CrossOrigin to the corresponding Controller class to allow cross-origin access.
1 |
|
Alternatively, configure a reverse proxy in nginx, routing the API to a specific path so that it’s accessed from the same origin.
0x01 CSRF
CSRF exploits the browser’s automatic inclusion of cookies in requests.
For example, a user logs into website A, and their session information is stored in a cookie.
The user then visits a malicious website B, which constructs a form that submits data to website A. Since the request targets A’s domain, the browser automatically attaches cookies associated with A. The server validates the cookie and completes the action requested by website B—without the user’s knowledge. (CORS by default allows cross-origin POST form submissions.)
Traditional CSRF defenses require including a CSRF token in the request. This token can be embedded in the page HTML or retrieved via a cookie—essentially using information that only the legitimate domain can access to prevent CSRF attacks.
Servers can also defend against CSRF by checking the Origin and Referer headers.
With front-end and back-end separation, it’s no longer feasible to directly embed CSRF tokens in HTML pages.
However, the “double-submit cookie” pattern (storing the CSRF token in a cookie) can still be used to prevent CSRF.
Nowadays, in most front-end/back-end separated applications, JSON is used for data exchange. If the back end validates the Content-Type header and properly sets Access-Control-Allow-Origin, CSRF can be effectively mitigated. (Cross-origin JSON requests are blocked by default due to CORS.) See: https://stackoverflow.com/questions/11008469/are-json-web-services-vulnerable-to-csrf-attacks
A more modern authentication approach is JWT. When authentication is done via tokens sent in request headers (e.g., Authorization), CSRF is inherently prevented—offering the same level of protection as the double-submit cookie method.
For applications still using cookie-based authentication, there is now a definitive solution to CSRF: SameSite cookies.
This approach solves CSRF at the root by preventing cookies from being sent in cross-origin requests. Recent browser versions now default to SameSite=Lax, which provides strong protection against CSRF attacks.
This article is licensed under the CC BY-NC-SA 4.0 license.
Author: lyc8503, Article link: https://blog.lyc8503.net/en/post/cors-and-csrf/
If this article was helpful or interesting to you, consider buy me a coffee¬_¬
Feel free to comment in English below o/