Zum Hauptinhalt springen
tsecurity.de LIVE
Echtzeit-Radar & Feeds
Alle RSS Feeds
👥 Community & Social
Sichere ProgrammierungWhy Claude Code keeps writing shell commands that fail on your Mac(20.09.2026 um 21:06 Uhr)
Sichere Programmierungllms.txt v2: What the Spec Says, and What 137,000 Domains Show(20.09.2026 um 21:17 Uhr)
Sicherheitslücken (CVE)NiceTryGPT: Less pattern matching. More actual hacking.(20.09.2026 um 21:19 Uhr)
IT Security VideoActivities BoF (kde2026)(20.09.2026 um 00:00 Uhr)
IT Security Toolsirdoc-app(20.09.2026 um 20:33 Uhr)
Sichere ProgrammierungWhy Claude Code keeps writing shell commands that fail on your Mac(20.09.2026 um 21:06 Uhr)
Sichere Programmierungllms.txt v2: What the Spec Says, and What 137,000 Domains Show(20.09.2026 um 21:17 Uhr)
Sicherheitslücken (CVE)NiceTryGPT: Less pattern matching. More actual hacking.(20.09.2026 um 21:19 Uhr)
IT Security VideoActivities BoF (kde2026)(20.09.2026 um 00:00 Uhr)
IT Security Toolsirdoc-app(20.09.2026 um 20:33 Uhr)
Intelligence View
⚡ tsecurity.de Intelligence

Web Security 101- From SOP to CORS: Understanding the Web’s Cross‑Origin Security Model

Reagiere als Erste:r — dein Feedback zählt!

Modern web applications often have multiple subdomains, your frontend hosted at https://app.example.com, API at https://api.example.com, maybe file storage at https://fs.example.com.

 

That architecture is powerful, until you hit the dreaded error:

Access to fetch at 'https://api.example.com' from origin 'https://app.example.com'
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

 

If you’ve seen that, welcome — you’ve just met CORS (Cross-Origin Resource Sharing), the security mechanism browsers use to safely break the rules of the Same-Origin Policy (SOP).

 

This article walks you through what SOP is, what CORS really does, and how to configure your backend (with examples) to handle cross-origin requests properly.

 

Table of Contents

  1. The Same-Origin Policy
  2. What Is an Origin?
  3. What Is a Cross-Origin Request?
  4. What Is CORS (Cross-Origin Resource Sharing)?
  5. Simple CORS Requests
  6. Preflight Requests
  7. Key CORS Headers Explained
  8. CORS with Cookies and Credentials
  9. Practical Example: CORS in Rust (Axum)
  10. API Gateway and Backend: Where Should You Configure CORS?
  11. Loading Resources Cross‑Domain with the <script> Tag
  12. A Short History of CORS
  13. Summary
  14. References

 

1. The Same Origin Policy

Before diving into CORS, you must understand its foundation, the Same-Origin Policy.

This rule is the browser’s built‑in firewall. It prevents malicious websites from freely interacting with another site you’re logged into.

In simple terms:

“A script loaded from one origin cannot freely read or modify data from another origin.”

For example, JavaScript running on https://app.example.com cannot read the data or cookies from https://api.example.com unless the server explicitly allows it.

Without SOP, any random site could load your webmail or banking page in the background and read sensitive data — a complete privacy disaster.

 

2. What Is an Origin?

An origin is defined as the combination of:

scheme (protocol) + host (domain) + port

Two pages share the same origin only if all three are identical.

URL Same as https://app.example.com/a.html? Why
https://app.example.com/b.html ✅ Yes Same scheme, domain, and port
http://app.example.com/c.html ❌ No Different scheme
https://sub.app.example.com/d.html ❌ No Different domain
https://app.example.com:8080/e.html ❌ No Different port

 

3. What Is a Cross Origin Request?

Whenever your JavaScript tries to fetch a resource from a different origin (different scheme, host, or port), it becomes a cross-origin HTTP request.

Example:

fetch("https://api.example.com/data");

If your page is served from https://app.example.com, this is a cross-origin call.

When the server does not explicitly allow this, the browser blocks the response and logs:

Access to fetch at 'https://api.example.com/data'
from origin 'https://app.example.com' has been blocked by CORS policy

The browser enforces this for security — not because it can’t send the request, but because it refuses to reveal the response unless the server approves it.

 

4. What Is CORS (Cross Origin Resource Sharing)?

CORS is the official web standard that defines how a server can state:

“These specific sites are allowed to access my resources.”

CORS works through additional HTTP headers sent by the server to “grant permission” to specific origins.

Example server response:

Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Content-Type

When a browser sees this response, it verifies if the Origin header of the request matches the allowed origin(s).

If they match ✅ — the JavaScript call succeeds.

If not ❌ — the response is hidden from JavaScript.

 

5. Simple CORS Requests

Some requests are so common and safe that browsers send them immediately — these are simple requests.

To qualify as a simple request, all of the following conditions must hold:

  • The HTTP method is GET, HEAD, or POST.
  • The only manually set headers are “CORS-safelisted” (Accept, Accept-Language, Content-Language, Content-Type with restricted MIME types).
  • The allowed Content-Type values are:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

Example

fetch("https://api.example.com/data");

The browser automatically adds:

Origin: https://app.example.com

If the API responds with:

Access-Control-Allow-Origin: https://app.example.com

the response is shared successfully with JavaScript.

If the header is missing or mismatched, the Fetch API rejects the promise with a CORS error, even though the network request technically went through.

 

6. Preflight Requests

When a request might affect server data or uses custom headers, non‑standard methods (DELETE, PUT, PATCH, etc.), or a Content-Type like application/json, browsers perform an extra validation step called a Preflight Request.

Step 1 — The OPTIONS Preflight

Before sending the actual request, the browser asks permission by sending an OPTIONS request:

OPTIONS /data HTTP/1.1
Origin: https://app.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-CUSTOM-HEADER, Content-Type

Step 2 — The Server’s Response

If the server approves, it responds with:

Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: X-CUSTOM-HEADER, Content-Type
Access-Control-Max-Age: 86400

This tells the browser that:

  • The origin is allowed.
  • The method POST and headers can be used.
  • The permission is valid for 24 hours (86400 seconds).

Step 3 — The Actual Request

After approval, the browser sends the intended request, e.g.:

POST /data HTTP/1.1
Origin: https://app.example.com
Content-Type: application/json
X-CUSTOM-HEADER: 123

If the response again includes a valid Access-Control-Allow-Origin, your code can finally read the payload.

 

7. Key CORS Headers Explained

Header Purpose
Access-Control-Allow-Origin Specifies which origin(s) are allowed. Use * for any, or a specific domain like https://app.example.com.
Access-Control-Allow-Methods Declares which HTTP methods can be used.
Access-Control-Allow-Headers Lists the allowed non-simple headers the client can send.
Access-Control-Max-Age How long browsers can cache the preflight result (in seconds).
Access-Control-Expose-Headers Allows JavaScript to read additional response headers beyond the default six (Cache-Control, Content-Language, Content-Type, Expires, Last-Modified, Pragma).
Access-Control-Allow-Credentials Indicates whether the server allows credentials (cookies, Authorization headers) for cross-origin requests.

Example:

Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: X-My-Custom-Header

 

8. CORS with Cookies and Credentials

By default, cross-origin requests do not include cookies or credentials due to security risks.

To enable them:

Client‑side

For Fetch API:

fetch("https://api.example.com/data", { credentials: "include" });

For XMLHttpRequest:

const xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.open("POST", "https://api.example.com/data");
xhr.send();

Server‑side

The response must include:

Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: https://app.example.com

⚠️ Important:

When Access-Control-Allow-Credentials: true is used,

Access-Control-Allow-Origin cannot be * — it must name the specific origin.

Otherwise, the browser will reject the response, showing:

The value of 'Access-Control-Allow-Origin' must not be '*' when the request’s credentials mode is 'include'.

This combination ensures sensitive authenticated requests are only allowed from known, trusted sites.

 

9. Practical Example: CORS in Rust (Axum)

Here’s how to configure multi-subdomain CORS support in your backend using the Rust web framework Axum.

Cargo.toml

[dependencies]
axum = "0.8.6"
serde_json = "1.0.145"
tokio = { version = "1.48.0", features = ["full"] }
tower-http = { version = "0.6.6", features = ["cors"] }

Main Application

use axum::{
    Json, Router, http,
    http::{HeaderValue, Method, StatusCode},
    response::IntoResponse,
    routing::get,
};
use serde_json::json;
use std::net::SocketAddr;
use tower_http::cors::CorsLayer;

#[tokio::main]
async fn main() {
    let allowed_origins = vec![
        "https://app.example.com",
        "https://api.example.com",
        "https://fs.example.com",
    ];

    let cors = CorsLayer::new()
        .allow_origin(
            allowed_origins
                .into_iter()
                .filter_map(|o| o.parse::<HeaderValue>().ok())
                .collect::<Vec<_>>(),
        )
        .allow_methods([Method::GET, Method::POST, Method::DELETE, Method::OPTIONS])
        .allow_headers([http::header::CONTENT_TYPE, http::header::AUTHORIZATION])
        .allow_credentials(true);

    let app = Router::new()
        .route("/api/data", get(get_data).post(post_data))
        .layer(cors);

    let addr = SocketAddr::from(([127, 0, 0, 1], 8080));
    println!("Server running at http://{addr}");

    axum::serve(tokio::net::TcpListener::bind(addr).await.unwrap(), app)
        .await
        .unwrap();
}

async fn get_data() -> impl IntoResponse {
    (StatusCode::OK, Json(json!({ "message": "GET OK" })))
}

async fn post_data() -> impl IntoResponse {
    (StatusCode::OK, Json(json!({ "message": "POST OK" })))
}

Explanation

  • Allows specific subdomains (app, api, fs) to share resources.
  • Enables all major methods and headers.
  • Credentials (cookies/tokens) are explicitly allowed.
  • Other unlisted origins are blocked at the browser level.

 

10. API Gateway and Backend: Where Should You Configure CORS?

When your backend is served behind an API Gateway — such as AWS API Gateway, NGINX, Kong, or Traefik — it can be confusing where to configure CORS (Cross-Origin Resource Sharing).

Let’s go through when and where to apply CORS: Gateway, Backend, or both.

 

First Principle

CORS is enforced by browsers, not servers.

The only thing that matters is that the final HTTP response reaching the browser includes valid CORS headers.

That means it doesn’t matter who adds them — as long as the browser sees the correct headers.

 

Option 1 — Handle CORS at the API Gateway (Recommended)

The API Gateway is the first server a browser talks to.
That makes it the perfect place for centralized CORS handling.

Advantages

  1. Centralized Policy Management
    Manage all origins, headers, and methods in one place.

  2. Simplified Backends
    Microservices don’t have to duplicate CORS logic.

  3. Automatic Preflight Handling
    The Gateway can respond to OPTIONS requests itself.

  4. Faster Updates
    Adjust CORS rules without rebuilding backend code.

Example — AWS API Gateway CORS Config

{
  "CorsConfiguration": {
    "AllowOrigins": ["https://app.example.com"],
    "AllowMethods": ["GET", "POST", "OPTIONS"],
    "AllowHeaders": ["Content-Type", "Authorization"],
    "AllowCredentials": true
  }
}

The Gateway:

  • Responds automatically to OPTIONS preflight.
  • Injects the proper headers into responses.
  • Hides the complexity from your backend APIs.

 

Option 2 — Handle CORS in the Backend (When Needed)

You might choose backend-level CORS if:

  • Your Gateway acts as a transparent proxy (no header manipulation).
  • Different services require different origins or rules.
  • Certain API calls skip the Gateway entirely.

You must handle:

  • OPTIONS preflight responses.
  • Matching origins exactly between request and header.
  • No wildcard * when Access-Control-Allow-Credentials: true is used.

 

Option 3 — Handle CORS in Both (Not Rcommanded)

In some environments, both Gateway and Backend add CORS headers — typically during a migration.

This is fine only if both configurations return identical headers.

Otherwise, conflicting values (for example, Access-Control-Allow-Origin) cause browsers to discard the response.

Use this dual setup only temporarily, not as a permanent architecture.

 

When You Don’t Need CORS

CORS is purely a browser security mechanism.

If requests originate from:

  • Another backend server
  • Mobile apps using native HTTP clients
  • Internal service networks (no browsers)

Then you don’t need CORS at all.

 

Best Practice Decision Table

Scenario Who Should Handle CORS? Why
Browser calls API through public gateway Gateway Centralized and simpler
Gateway is transparent or not configurable Backend Backend must manage headers
Gradual migration Both Temporary safety
Internal or mobile-only access None Not needed
  • CORS belongs at the first browser-facing layer, ideally the API Gateway.
  • The Backend should only handle CORS if the Gateway can’t or shouldn’t.
  • Having both handle it can create conflicts unless headers match exactly.
  • For consistent behavior, centralize CORS logic at the Gateway.

 

Testing Your Setup

Use curl or a REST client to simulate preflight requests:

curl -i -X OPTIONS \
  -H "Origin: https://app.example.com" \
  -H "Access-Control-Request-Method: POST" \
  https://api.example.com/data

If your configuration is correct, you should see:

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: POST, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Allow-Credentials: true

That means your Gateway or Backend CORS rules are properly aligned.

If browsers connect to your API via the Gateway, configure CORS on the Gateway.

Use backend CORS only when the Gateway can’t handle it.

 

11. Loading Resources Cross Domain with the Script Tag

Under the Same‑Origin Policy (SOP), web pages are generally restricted from reading data returned by requests to other domains. However, some HTML elements — such as <script>, <img>, and <link> — are not limited by this rule.

The <script> element was intentionally designed to allow loading and executing code from different origins. This design supports the reuse of external resources, such as shared libraries, analytics scripts, or frameworks hosted on content delivery networks (CDNs). The restriction under SOP applies mainly to reading data, not to loading and executing external code.

When a browser processes a tag like the following:

<script src="https://cdn.example.com/library.js"></script>

it sends an HTTP request to the external domain, retrieves the JavaScript file, and executes it in the context of the current page. The browser does not block this behavior because the script is not trying to read external data; it simply imports executable code that runs locally once loaded.

This capability forms the foundation of how websites include shared scripts, but it also introduces potential security risks. If a malicious or compromised external script is loaded, it gains full access to the page’s environment, including the Document Object Model (DOM), cookies (when accessible), and user interactions. For this reason, modern security practices recommend:

  • Hosting critical scripts within the same origin when possible.
  • Using Subresource Integrity (SRI) to ensure the script’s content matches an expected hash.
  • Limiting external dependencies to trusted sources.

In modern browsers, this cross‑domain script inclusion remains allowed but is managed through stricter security mechanisms such as Content Security Policy (CSP) and SRI, which help reduce risks associated with externally loaded scripts.

 

12. A Short History of CORS

Web browsers originally enforced the Same‑Origin Policy (SOP), which restricted web pages from making requests to different domains. To work around this limitation, developers used a method known as JSONP (JSON with Padding). JSONP allowed limited cross‑domain data exchange through <script> tags but was constrained to GET requests and presented security concerns.

The World Wide Web Consortium (W3C) initiated work on a standardized solution in May 2006, when the first W3C Working Draft was published. In March 2009, the draft was renamed to Cross‑Origin Resource Sharing (CORS), and in January 2014, it became an official W3C Recommendation.

CORS introduced a standardized set of HTTP headers that enable controlled access to resources across different origins, defining how browsers and servers can interact securely across domains.

 

13. Summary

Scenario Required Headers Notes
Simple Request Access-Control-Allow-Origin GET/POST/HEAD only
Non‑Simple (Preflighted) Access-Control-Allow-Origin, Access-Control-Allow-Methods, Access-Control-Allow-Headers Browser sends an OPTIONS request first
Using Cookies Same as above + Access-Control-Allow-Credentials: true Access-Control-Allow-Origin must not use *
Expose Extra Headers Add Access-Control-Expose-Headers Allows JS to read non‑default headers

Troubleshooting Flow:

  1. Check whether your request is “simple” or requires preflight.
  2. Ensure your backend handles the OPTIONS call correctly.
  3. Validate Access-Control-Allow-Origin matches exactly.
  4. When using cookies, ensure both client and server specify credentials explicitly.

 

14. References

Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Web Security 101- From SOP to CORS: Understanding the Web’s Cross‑Origin Security Model

Thematisch verwandte Begriffe: Security, From, CORS, Understanding · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-93956 | A flaw has been found in olivier-ls PHP-FTS up to 1.1.2. Affected by thi…
Advisory →
TTS Reader • tsecurity.de Voice
tsecurity.de Icon
tsecurity.de App
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen

tsecurity.de Live Threat Radar

🔴 LIVE RADAR
MONITORING
AKTIV
CVE-DATENBANK
LIVE
🔍
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Bearbeitungsmodus — Senden überschreibt deine Nachricht
Community-Puls — was gerade passiert
lädt…
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
🔖 Gespeicherte Artikel
📂 Keine gespeicherten Artikel vorhanden.
Zurück Ziehen Vor
Links: vorheriger Artikel Rechts: nächster Artikel unten: schließen
News NIS-2 Frühwarnung Tier-1 Intel ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...

Zurück: vorheriger Vor: nächster
↗ Original-Quelle
Social Reaktionen Deine Reaktion zählt
Einstufung & Relevanz-Poll 0 Stimmen
In sozialen Netzwerken teilen 1-Klick