Posts Tagged ‘Clickjacking’
Guarding the Web: Understanding and Mitigating Modern Application Security Risks: XSS • CSRF • Clickjacking • CORS • SSRF
Modern web applications operate in a hostile environment. Attackers exploit input handling, browser trust, and server connectivity to inject code (XSS), trigger unauthorized actions (CSRF), trick users into clicking hidden UI (clickjacking), abuse permissive cross-origin policy (CORS), or make the server itself fetch sensitive resources (SSRF). This article explains the mechanics of each threat and provides concrete, production-grade mitigation patterns you can adopt today.
Cross-Site Scripting (XSS): When Untrusted Input Becomes Code
Threat model: User-provided data is rendered into a page without correct encoding or policy restrictions, allowing script execution in the victim’s browser.
Typical Exploits
Stored XSS (comments, profiles):
<script>fetch('/api/session/steal', {credentials:'include'})</script>
Reflected XSS (search query):
GET /search?q=<script>alert(1)</script>
DOM-based XSS (dangerous sinks):
// Anti-pattern: innerHTML with untrusted input
const result = new URLSearchParams(location.search).get('msg');
document.getElementById('banner').innerHTML = result; // XSS sink
High-Confidence Mitigations
- Contextual Output Encoding: Encode before insertion, based on context (HTML, attribute, URL, JS, CSS).
- Prefer Safe APIs: Use
textContent
/setAttribute
overinnerHTML
; avoideval
/Function constructors. - Framework Defaults: Modern templating (e.g., React, Angular) auto-escapes. Avoid escape bypasses (e.g.,
dangerouslySetInnerHTML
) unless you sanitize with robust libraries. - Content Security Policy (CSP): Block inline scripts and restrict sources; use nonces.
CSP Example (Nonce-Based)
Content-Security-Policy: default-src 'none';
script-src 'self' 'nonce-r4nd0mNonce';
style-src 'self';
img-src 'self' data:;
connect-src 'self';
base-uri 'self';
frame-ancestors 'self';
form-action 'self';
Server/Framework Snippets
Express.js: encode + CSP headers
app.use((req, res, next) => {
res.set('Content-Security-Policy',
"default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self' data:; connect-src 'self'; base-uri 'self'; frame-ancestors 'self'");
res.set('X-Content-Type-Options', 'nosniff');
next();
});
Do sanitize if you must render HTML: Use a vetted sanitizer (e.g., DOMPurify on the client, OWASP Java HTML Sanitizer on the server) with an allowlist.
Cross-Site Request Forgery (CSRF): Abusing Session Trust
Threat model: A logged-in user’s browser sends a forged state-changing request (e.g., money transfer) to a trusted site because cookies are automatically included.
Exploit Example
<form action="https://bank.example/transfer" method="POST">
<input type="hidden" name="to" value="attacker">
<input type="hidden" name="amount" value="1000">
</form>
<script>document.forms[0].submit();</script>
Mitigations That Work Together
- Synchronizer (Anti-CSRF) Tokens: Embed a per-session/per-request token in each state-changing form or AJAX request; verify server-side.
- SameSite Cookies: Set session cookies to
SameSite=Lax
orStrict
andSecure
to block cross-site inclusion. - Method & Content Checks: Require POST/PUT/DELETE with
Content-Type: application/json
; reject unexpected content types. - Origin/Referer Validation: For sensitive endpoints, verify
Origin
(preferred) orReferer
. - Re-authentication / Step-Up: For high-value actions, require a second factor or password confirmation.
Example (Express + CSRF Token)
// Pseudocode with csurf-like middleware
app.post('/transfer', requireAuth, verifyCsrfToken, (req, res) => {
// process transfer
});
SPA + API note: Prefer token-based auth (Authorization header) to avoid ambient cookies. If you must use cookies, combine SameSite
with CSRF tokens.
Clickjacking: UI Redress and Hidden Frames
Threat model: An attacker overlays your site in an invisible <iframe>
and tricks users into clicking sensitive controls.
Exploit Sketch
<iframe src="https://target.example/approve" style="opacity:0;position:absolute;top:0;left:0;width:100%;height:100%"></iframe>
Mitigations
- X-Frame-Options (XFO):
DENY
orSAMEORIGIN
. (Legacy but still widely respected.) - CSP frame-ancestors: Modern, fine-grained embedding control.
- UI Hardening: Re-prompt for confirmation on dangerous actions; disable one-click irreversible changes.
Header Examples
X-Frame-Options: DENY
Content-Security-Policy: frame-ancestors 'self'
Server Config
Nginx:
add_header X-Frame-Options "DENY" always;
add_header Content-Security-Policy "frame-ancestors 'self'" always;
Apache:
Header always set X-Frame-Options "DENY"
Header always set Content-Security-Policy "frame-ancestors 'self'"
CORS: Safe Cross-Origin Requests Without Overexposure
Threat model: Overly permissive CORS allows arbitrary origins to read sensitive API responses or send authenticated requests.
Dangerous Patterns
Access-Control-Allow-Origin: *
combined withAccess-Control-Allow-Credentials: true
(browsers will ignore, but this signals confusion and often pairs with other mistakes).- Reflecting the request
Origin
wholesale without an allowlist. - Forgetting
Vary: Origin
, causing caches/CDNs to serve one origin’s CORS response to all.
Safe Configuration
Access-Control-Allow-Origin: https://app.example
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Authorization, Content-Type
Access-Control-Expose-Headers: ETag, X-Request-Id
Vary: Origin
Implementation Tip
// Pseudocode: strict allowlist
const allowed = new Set(['https://app.example', 'https://admin.example']);
const origin = req.headers.origin;
if (allowed.has(origin)) {
res.setHeader('Access-Control-Allow-Origin', origin);
res.setHeader('Vary', 'Origin');
}
Principle: CORS is not an auth mechanism—treat it as a read-permission gate. Apply per-endpoint scoping; don’t turn it on globally.
Server-Side Request Forgery (SSRF): Turning Your Server Into a Proxy
Threat model: The application fetches remote resources based on user input (URLs), allowing attackers to reach internal networks or cloud metadata endpoints.
Exploit Examples
- Cloud metadata theft:
http://169.254.169.254/latest/meta-data/
(AWS) /http://metadata.google.internal/
/http://169.254.169.254/metadata/instance
(Azure; IMDSv2/headers required). - Reaching services on
localhost
or RFC1918 IPs (e.g., Redis, internal dashboards). - Schema abuse:
file://
,gopher://
, orftp://
if unsupported schemas aren’t blocked. - Open redirect chains or DNS rebinding that convert a safe-looking hostname into an internal IP at resolution time.
Defense-in-Depth
- Strict Allowlists: Only permit fetching from specific hosts/paths; reject everything else.
- URL & IP Validation: Parse the URL; resolve DNS; block private and link-local ranges; re-validate after redirects.
- Egress Proxy with ACL: Force all outbound HTTP(S) through a proxy that enforces destination policies and logs requests.
- Cloud Hardening: Require IMDSv2 (AWS); block server access to metadata endpoints unless strictly needed.
- Timeouts & Size Limits: Short connect/read timeouts and response byte caps to prevent internal scanning and DoS.
Hardening Snippet (Pseudocode)
function safeFetch(userUrl) {
const url = new URL(userUrl);
// allowlist scheme
if (!['https:'].includes(url.protocol)) throw new Error('Blocked scheme');
// DNS resolve and block private IPs
const ip = resolveToIP(url.hostname);
if (isPrivate(ip) || isLinkLocal(ip) || isLoopback(ip)) throw new Error('Blocked destination');
// enforce egress proxy
return proxyHttpGet(url, { timeoutMs: 2000, maxBytes: 1_000_000, followRedirects: 3, revalidateIPOnRedirect: true });
}
Header note: SSRF is best mitigated by network policy and URL validation; “headers” alone can’t prevent SSRF, but you may set request policies (e.g., disallow redirects, strip sensitive headers) and enforce gateway rules.
Complementary Security Headers
- Strict-Transport-Security:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
- X-Content-Type-Options:
nosniff
to block MIME type sniffing. - Referrer-Policy: e.g.,
strict-origin-when-cross-origin
. - Permissions-Policy: Restrict powerful APIs (camera, geolocation, etc.).
- Cross-Origin-Opener-Policy / Resource-Policy / Embedder-Policy: Strengthen isolation where feasible.
Operational Controls & SDLC Integration
- Threat Modeling: Map trust boundaries (browser ⇄ app ⇄ services ⇄ internet) and identify high-risk data flows.
- Static/Dynamic Testing: SAST, DAST, and dependency scanning in CI; add security unit tests for templating and request flows.
- Observability: Log security-relevant events (CSP violations via
report-to
, WAF blocks, CSRF failures, SSRF proxy denies) and alert. - WAF/Gateway Policies: Enforce header baselines, block known bad payloads, and constrain egress with explicit ACLs.
- Secrets Hygiene: Short-lived tokens, mTLS for service-to-service, and key rotation.
- Least Privilege by Default: Scope CORS per endpoint, narrow IAM roles, network segmentation.
Deployment Checklist
- ✅ XSS: Contextual encoding, CSP with nonces, sanitizer for any HTML rendering.
- ✅ CSRF: Anti-CSRF tokens,
SameSite
+Secure
cookies, Origin checks, step-up auth on critical actions. - ✅ Clickjacking:
X-Frame-Options: DENY
andCSP frame-ancestors 'self'
. - ✅ CORS: Explicit allowlist, credentials only when necessary,
Vary: Origin
, scoped to sensitive endpoints. - ✅ SSRF: Allowlist destinations, block internal ranges, egress proxy with ACL, timeouts/size caps, re-validate after redirects.
- ✅ Headers: HSTS, XCTO, Referrer-Policy, Permissions-Policy in place.
- ✅ Ops: Logging/alerting on policy violations; SAST/DAST integrated; WAF rules tuned to app.