Recent Posts
Archives

Posts Tagged ‘XSS’

PostHeaderIcon 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 over innerHTML; avoid eval/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 or Strict and Secure 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) or Referer.
  • 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 or SAMEORIGIN. (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 with Access-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://, or ftp:// 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 and CSP 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.
Security is not a single feature; it is a posture expressed through code, configuration, and continuous verification.

PostHeaderIcon [DotSecurity2017] Counter-spells and the Art of Keeping Your Application Safe

In the arcane atelier of application assurance, where user whims whirl into wicked whimsy, wielding wards against web’s wicked whims demands diligence and dexterity. Ingrid Epure, a frontend alchemist at Intercom, invoked this incantation at dotSecurity 2017, transmuting tales of Ember’s exigencies into elixirs for Ember’s endurance. A Romanian expatriate ensconced in Dublin’s digital demesne, Ingrid’s immersion—four-year Ember opus, Rails’ rearward rampart—yields yarns of 55 scribes scripting 2,000 shifts, 100 deploys diurnal.

Ingrid’s invocation opened with Intercom’s incantus: real-time runes for messaging’s mosaic, 250 commits cascading 30K additions—vulnerabilities’ vortex in velocity’s vortex. XSS’s xanthic xanthoma: inline sorcery (Ember’s {{}} incantations) inviting injection’s infestation—’s sorcery, CSP’s countercharm. Ingrid illuminated Ember’s ember: helpers’ hygiene (HTML-escapers’ aegis), bindings’ bulwark (triple braces’ taboo). Tools’ talisman: npm’s audit, ember-cli’s eldritch eyes—vulnerabilities’ vigil, dependencies’ divination.

CSRF’s chicanery: Ember’s CSRF tokens, Rails’ requiem—double-submit’s duality, synchronizer’s sentinel. Ingrid invoked interceptors: Ember’s data’s dominion, Rails’ requital. Content Security Policy’s codex: v2’s vigilance (nonces’ nebula, hashes’ heraldry), v3’s valor—scripts’ scrutiny, inline’s inquisition. Ingrid’s imprecation: Ember addon’s aegis, Node’s nexus—alerts’ alarum, anomalies’ augury.

This conjury: clean code’s creed, tools’ tome—CSP’s citadel, vulnerabilities vanquished.

Vulnerabilities’ Vortex and Wards’ Weave

Ingrid invoked Intercom’s incantus: Ember’s exigencies, XSS’s xanthoma—helpers’ hygiene, bindings’ bulwark.

CSRF’s Chicanery and CSP’s Codex

Tokens’ talisman, interceptors’ insight—v2’s vigilance, v3’s valor. Ingrid’s imprecation: addon’s aegis, Node’s nexus.

Links:

EN_DotSecurity2017_006_009.md