Protecting the User
Modern browsers enforce a set of security policies based on HTTP headers sent by the server. These headers are the server's way of telling the browser: "Here are the rules for how my content should be handled." The browser enforces them — even if the JavaScript on the page tries to work around them.
The Same-Origin Policy
Before CORS, we need to understand what it solves. Browsers enforce the Same-Origin Policy (SOP): JavaScript running on https://myblog.com is only allowed to read responses from https://myblog.com. It cannot read responses from https://api.google.com. This prevents a malicious website from using your browser (and your cookies) to silently make requests to your bank's API and read the results.
CORS (Cross-Origin Resource Sharing)
Sometimes legitimate cross-origin requests are necessary — your frontend at https://app.example.com needs to call your API at https://api.example.com. CORS is the mechanism that lets the server explicitly grant permission for this.
When a browser detects a cross-origin request, it adds an Origin header:
Origin: https://app.example.com
The server must respond with:
Access-Control-Allow-Origin: https://app.example.com
If this header is absent or doesn't match, the browser blocks the JavaScript code from reading the response. The request still reaches the server — the server still processes it and sends a response — but the browser intercepts and hides that response from the JavaScript. This is a critical distinction: CORS is enforced by the browser, not the server.
For requests that modify data (POST, PUT, DELETE) or use custom headers, the browser first sends a preflight request — an OPTIONS request asking the server "are you okay with this?" before sending the real request. The server must respond with the appropriate Access-Control-Allow-Methods and Access-Control-Allow-Headers headers.
Security Headers
| Header | What it does |
|---|---|
Strict-Transport-Security: max-age=31536000; includeSubDomains |
Tells the browser: never connect to this site over plain HTTP again, for the next year, including all subdomains. Prevents SSL-stripping attacks. |
Content-Security-Policy: default-src 'self'; script-src 'self' cdn.example.com |
Whitelists exactly which sources the browser may load scripts, styles, images, and fonts from. Prevents Cross-Site Scripting (XSS) by blocking inline scripts and unauthorized external scripts. |
X-Frame-Options: DENY |
Prevents the page from being embedded in an <iframe> on another site. Blocks clickjacking attacks. |
X-Content-Type-Options: nosniff |
Tells the browser not to guess the content type — use exactly what Content-Type says. Prevents MIME-sniffing attacks. |
Key Point: Security headers are a defense-in-depth layer. Even if an attacker injects a malicious <script> tag into your HTML (via a database injection), a properly configured Content-Security-Policy will prevent the browser from executing it. These headers are free to implement and have a significant security impact — yet they are routinely missing from production applications.
A common interview question: "A developer sets Access-Control-Allow-Origin: * on their API. What are the security implications?" The answer: wildcard CORS allows any website to make requests to your API and read the responses. For public, read-only APIs (like a weather API), this is fine. For APIs that use cookie-based authentication or return sensitive user data, this is dangerous — a malicious site could use the victim's browser to call your API and read private data. Note that * cannot be used together with Access-Control-Allow-Credentials: true; browsers will reject that combination.