Permissive Cross-Domain-Richtlinie mit nicht vertrauenswürdigen Domains
Beschreibung
Permissive Cross-Domain-Richtlinie mit nicht vertrauenswürdigen Domains tritt auf, wenn Software eine Cross-Domain-Richtliniendatei (wie crossdomain.xml oder clientaccesspolicy.xml) verwendet, die Domains enthält, denen nicht vertraut werden sollte. Diese Richtliniendateien kontrollieren, welche externen Domains Cross-Origin-Anfragen an eine Webanwendung stellen können. Übermäßig permissive Richtlinien, insbesondere solche, die Wildcards (*) verwenden, ermöglichen es jeder Website, mit der Anwendung zu interagieren, was möglicherweise zu Datendiebstahl, CSRF-Angriffen und anderen Cross-Origin-Schwachstellen führt.
Risiko
Übermäßig permissive CORS-Richtlinien und Cross-Domain-Dateien setzen Anwendungen erheblichen Risiken aus. Angreifer können authentifizierte Anfragen von bösartigen Seiten stellen und Benutzerdaten stehlen oder unautorisierte Aktionen durchführen. Die Wildcard (*) in Access-Control-Allow-Origin kombiniert mit Credentials ermöglicht es jeder Seite, Benutzer zu imitieren. Fehlkonfiguriertes CORS hat zu zahlreichen Datenlecks geführt, bei denen Angreifer sensible Informationen aus authentifizierten Sitzungen extrahierten. APIs konfigurieren häufig CORS falsch und legen interne Daten offen.
Lösung
Verwenden Sie niemals Wildcard (*) für Access-Control-Allow-Origin, wenn Credentials involviert sind. Führen Sie eine strikte Whitelist erlaubter Origins. Validieren Sie den Origin-Header gegen die Whitelist, bevor Sie ihn reflektieren. Vertrauen Sie nicht benutzersupplied Origins. Entfernen oder beschränken Sie crossdomain.xml- und clientaccesspolicy.xml-Dateien. Implementieren Sie ordnungsgemäße CORS-Header mit spezifischen Origins. Verwenden Sie SameSite-Cookies als zusätzlichen Schutz. Prüfen Sie regelmäßig Cross-Origin-Konfigurationen.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Vertraulichkeit | Bereich: Datendiebstahl Bösartige Seiten können Antworten von der anfälligen Anwendung lesen und Benutzerdaten stehlen. |
| Integrität | Bereich: Unautorisierte Aktionen Cross-Origin-Anfragen können zustandsändernde Operationen als authentifizierter Benutzer durchführen. |
| Zugriffskontrolle | Bereich: Authentifizierungsumgehung Angreifer können auf authentifizierte Ressourcen zugreifen, indem sie Benutzersitzungen ausnutzen. |
Beispielcode + Lösungscode
Anfälliger Code
<!-- ANFÄLLIG: crossdomain.xml mit Wildcard -->
<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<allow-access-from domain="*" /> <!-- Erlaubt JEDE Domain! -->
</cross-domain-policy>
<!-- ANFÄLLIG: clientaccesspolicy.xml -->
<?xml version="1.0" encoding="utf-8"?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from http-request-headers="*">
<domain uri="*"/> <!-- Erlaubt JEDE Domain! -->
</allow-from>
<grant-to>
<resource path="/" include-subpaths="true"/>
</grant-to>
</policy>
</cross-domain-access>
</access-policy>
# ANFÄLLIG: Wildcard CORS mit Credentials
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
CORS(app, origins="*", supports_credentials=True) # GEFÄHRLICH!
# ANFÄLLIG: Origin ohne Validierung reflektieren
@app.after_request
def add_cors_headers(response):
origin = request.headers.get('Origin')
# Reflektiert JEDEN Origin!
response.headers['Access-Control-Allow-Origin'] = origin
response.headers['Access-Control-Allow-Credentials'] = 'true'
return response
# ANFÄLLIG: Regex-Umgehung
ALLOWED_ORIGINS_PATTERN = r'.*\.example\.com'
@app.after_request
def add_cors_regex(response):
origin = request.headers.get('Origin')
if re.match(ALLOWED_ORIGINS_PATTERN, origin):
# Angreifer verwendet: evil.com.example.com oder evil-example.com
response.headers['Access-Control-Allow-Origin'] = origin
response.headers['Access-Control-Allow-Credentials'] = 'true'
return response
// ANFÄLLIG: Spring CORS mit Wildcard
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*") // Jeder Origin!
.allowCredentials(true) // Mit Credentials!
.allowedMethods("*");
}
}
// ANFÄLLIG: Filter reflektiert Origin
@WebFilter("/*")
public class VulnerableCorsFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String origin = request.getHeader("Origin");
// Reflektiert jeden Origin!
response.setHeader("Access-Control-Allow-Origin", origin);
response.setHeader("Access-Control-Allow-Credentials", "true");
chain.doFilter(req, res);
}
}
// ANFÄLLIG: Express mit permissivem CORS
const cors = require('cors');
app.use(cors({
origin: true, // Reflektiert jeden Origin
credentials: true
}));
// ANFÄLLIG: Manuelle CORS mit Reflektion
app.use((req, res, next) => {
// Reflektiert welchen Origin auch immer gesendet wird
res.header('Access-Control-Allow-Origin', req.headers.origin);
res.header('Access-Control-Allow-Credentials', 'true');
next();
});
// ANFÄLLIG: Unzureichende Origin-Prüfung
app.use((req, res, next) => {
const origin = req.headers.origin;
// Schwache Prüfung - Angreifer verwendet example.com.evil.com
if (origin && origin.includes('example.com')) {
res.header('Access-Control-Allow-Origin', origin);
res.header('Access-Control-Allow-Credentials', 'true');
}
next();
});
Korrigierter Code
<!-- SICHER: Nur spezifische Domains -->
<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<site-control permitted-cross-domain-policies="master-only"/>
<allow-access-from domain="app.example.com" secure="true"/>
<allow-access-from domain="www.example.com" secure="true"/>
</cross-domain-policy>
<!-- Oder besser: Entfernen, wenn nicht benötigt -->
<!-- Wenn Flash/Silverlight nicht verwendet wird, crossdomain.xml komplett löschen -->
# SICHER: Strikte Origin-Whitelist
from flask import Flask, request
from flask_cors import CORS
app = Flask(__name__)
ALLOWED_ORIGINS = {
'https://app.example.com',
'https://www.example.com',
'https://admin.example.com'
}
def check_origin(origin):
return origin in ALLOWED_ORIGINS
CORS(app, origins=check_origin, supports_credentials=True)
# SICHER: Manuelle CORS mit strikter Validierung
@app.after_request
def add_cors_headers(response):
origin = request.headers.get('Origin')
if origin and origin in ALLOWED_ORIGINS:
response.headers['Access-Control-Allow-Origin'] = origin
response.headers['Access-Control-Allow-Credentials'] = 'true'
response.headers['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'
response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization'
response.headers['Access-Control-Max-Age'] = '86400'
# Niemals Wildcard mit Credentials verwenden
# Nicht vertrauenswürdige Origins nicht reflektieren
return response
# SICHER: Ordnungsgemäße Subdomain-Validierung
def is_valid_origin(origin):
if not origin:
return False
try:
from urllib.parse import urlparse
parsed = urlparse(origin)
# Muss HTTPS sein
if parsed.scheme != 'https':
return False
# Exakte Übereinstimmung oder gültige Subdomain
allowed_domains = ['example.com', 'example.org']
host = parsed.netloc.lower()
for domain in allowed_domains:
if host == domain or host.endswith('.' + domain):
return True
return False
except:
return False
// SICHER: Spring CORS mit Whitelist
@Configuration
public class SecureCorsConfig implements WebMvcConfigurer {
private static final List<String> ALLOWED_ORIGINS = List.of(
"https://app.example.com",
"https://www.example.com",
"https://admin.example.com"
);
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins(ALLOWED_ORIGINS.toArray(new String[0]))
.allowCredentials(true)
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("Content-Type", "Authorization")
.maxAge(86400);
}
}
// SICHER: Benutzerdefinierter CORS-Filter mit Validierung
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class SecureCorsFilter implements Filter {
private static final Set<String> ALLOWED_ORIGINS = Set.of(
"https://app.example.com",
"https://www.example.com"
);
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String origin = request.getHeader("Origin");
if (origin != null && ALLOWED_ORIGINS.contains(origin)) {
response.setHeader("Access-Control-Allow-Origin", origin);
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
response.setHeader("Access-Control-Max-Age", "86400");
}
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
return;
}
chain.doFilter(req, res);
}
}
// SICHER: Spring Security verwenden
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().configurationSource(corsConfigurationSource());
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(List.of(
"https://app.example.com",
"https://www.example.com"
));
configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE"));
configuration.setAllowCredentials(true);
configuration.setAllowedHeaders(List.of("*"));
configuration.setMaxAge(86400L);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
// SICHER: Express mit strikter Origin-Whitelist
const cors = require('cors');
const ALLOWED_ORIGINS = new Set([
'https://app.example.com',
'https://www.example.com',
'https://admin.example.com'
]);
const corsOptions = {
origin: (origin, callback) => {
// Anfragen ohne Origin erlauben (mobile Apps, curl, etc.)
// Nur wenn dies spezifisch benötigt wird
if (!origin) {
return callback(null, true);
}
if (ALLOWED_ORIGINS.has(origin)) {
callback(null, true);
} else {
callback(new Error('Nicht von CORS erlaubt'));
}
},
credentials: true,
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization'],
maxAge: 86400
};
app.use(cors(corsOptions));
// SICHER: Manuelle Implementierung mit strikter Validierung
function validateOrigin(origin) {
if (!origin) return false;
try {
const url = new URL(origin);
// Muss HTTPS sein
if (url.protocol !== 'https:') return false;
// Gegen Whitelist prüfen
const allowedHosts = ['app.example.com', 'www.example.com'];
return allowedHosts.includes(url.hostname);
} catch {
return false;
}
}
app.use((req, res, next) => {
const origin = req.headers.origin;
if (validateOrigin(origin)) {
res.header('Access-Control-Allow-Origin', origin);
res.header('Access-Control-Allow-Credentials', 'true');
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
res.header('Access-Control-Max-Age', '86400');
}
if (req.method === 'OPTIONS') {
return res.sendStatus(200);
}
next();
});
Ausgenutzt in der Praxis
Facebook CORS-Fehlkonfiguration (2019)
Eine CORS-Fehlkonfiguration in Facebooks API ermöglichte es Angreifern, private Daten zu lesen, indem sie Cross-Origin-Anfragen von bösartigen Websites stellten.
Verschiedene API-Datenlecks
Mehrere Organisationen haben durch CORS-Fehlkonfigurationen in ihren APIs Datenlecks erlitten, die es jeder Website ermöglichten, Benutzerdaten aus authentifizierten Sitzungen zu extrahieren.
Adobe Flash Cross-Domain-Angriffe
Vor der Einstellung von Flash ermöglichten permissive crossdomain.xml-Dateien zahlreiche Cross-Site-Datendiebstahl-Angriffe.
Tools zum Testen/Ausnutzen
-
Burp Suite - CORS-Konfigurationen testen.
-
CORS Scanner - Automatisierter CORS-Fehlkonfigurationsscanner.
-
Browser DevTools - CORS-Header inspizieren.
-
curl - CORS manuell mit Origin-Header testen.
CVE-Beispiele
-
CVE-2021-38112 - Amazon Kindle CORS-Schwachstelle.
-
CVE-2020-5741 - Plex CORS-Fehlkonfiguration.
-
CVE-2019-9787 - WordPress CORS-Problem.
Referenzen
-
MITRE. "CWE-942: Permissive Cross-domain Policy with Untrusted Domains." https://cwe.mitre.org/data/definitions/942.html
-
OWASP. "CORS Security." https://owasp.org/www-community/attacks/CORS_OriginHeaderScrutiny