Bird
Raised Fist0
Nginxdevops~15 mins

HSTS header in Nginx - Deep Dive

Choose your learning style10 modes available
Overview - HSTS header
What is it?
HSTS stands for HTTP Strict Transport Security. It is a security feature that tells web browsers to only connect to a website using HTTPS, not HTTP. This helps protect users from attacks that try to intercept or change data by forcing secure connections. The HSTS header is sent by the web server to the browser to enable this behavior.
Why it matters
Without HSTS, users might accidentally connect to a website over an insecure HTTP connection, exposing their data to attackers. HSTS ensures that once a browser knows a site is secure, it will never use an insecure connection again, preventing many common attacks like man-in-the-middle. This makes browsing safer and builds trust between users and websites.
Where it fits
Before learning about HSTS, you should understand basic web protocols like HTTP and HTTPS and how web servers send headers. After mastering HSTS, you can explore other web security headers and HTTPS certificate management to build stronger website security.
Mental Model
Core Idea
HSTS is a server instruction that locks browsers into using secure HTTPS connections to prevent insecure access.
Think of it like...
Imagine a store that tells customers, "From now on, only enter through the secure front door." This prevents anyone from sneaking in through a back door that is less safe.
┌───────────────┐       ┌───────────────┐
│  Web Server   │──────▶│  Browser      │
│ sends HSTS    │       │ remembers to  │
│ header        │       │ use HTTPS only│
└───────────────┘       └───────────────┘
         ▲                      │
         │                      ▼
  ┌───────────────┐       ┌───────────────┐
  │ Next visits   │◀─────│ Browser blocks │
  │ use HTTPS     │       │ HTTP requests │
  └───────────────┘       └───────────────┘
Build-Up - 6 Steps
1
FoundationUnderstanding HTTP vs HTTPS
🤔
Concept: Learn the difference between HTTP and HTTPS protocols.
HTTP is a way browsers and servers talk, but it is not secure. HTTPS adds encryption to protect data during transfer. Without HTTPS, data can be seen or changed by attackers.
Result
You know why HTTPS is important for security.
Understanding the difference between HTTP and HTTPS is key to grasping why HSTS is needed.
2
FoundationWhat is an HTTP header?
🤔
Concept: HTTP headers are extra information sent between browsers and servers.
Headers tell browsers how to handle the website, like language or caching rules. The HSTS header is one such instruction that tells browsers to use HTTPS only.
Result
You understand how servers communicate rules to browsers.
Knowing headers lets you see how HSTS controls browser behavior.
3
IntermediateHow HSTS header works in nginx
🤔
Concept: Learn how to add the HSTS header in nginx configuration.
In nginx, you add the line: add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; This tells browsers to remember to use HTTPS for 1 year (31536000 seconds), including all subdomains, and allows preloading.
Result
nginx sends the HSTS header with every HTTPS response.
Configuring HSTS in nginx is simple but powerful for enforcing HTTPS.
4
IntermediateUnderstanding HSTS header directives
🤔Before reading on: do you think 'includeSubDomains' applies HSTS to subdomains or just the main domain? Commit to your answer.
Concept: Explore the meaning of max-age, includeSubDomains, and preload directives.
max-age sets how long browsers remember to use HTTPS. includeSubDomains extends this rule to all subdomains. preload allows the site to be included in browsers' built-in HSTS lists for extra security.
Result
You can customize HSTS behavior to fit your website's needs.
Knowing each directive helps avoid mistakes that could lock users out or leave parts insecure.
5
AdvancedTesting and deploying HSTS safely
🤔Before reading on: do you think enabling HSTS immediately with a long max-age is safe for all sites? Commit to your answer.
Concept: Learn how to test HSTS before full deployment to avoid locking users out.
Start with a short max-age like 60 seconds to test. Use browser developer tools to check the header. Gradually increase max-age once confident. Avoid enabling preload until fully ready.
Result
You deploy HSTS without breaking access for users.
Testing prevents irreversible mistakes that can cause site access problems.
6
ExpertHSTS preload list and its impact
🤔Before reading on: do you think adding your site to the HSTS preload list can be undone easily? Commit to your answer.
Concept: Understand the HSTS preload list maintained by browsers and its consequences.
The preload list is baked into browsers to enforce HTTPS from the first visit. Once your site is on it, removing it is slow and difficult. This protects users but requires careful preparation before submitting.
Result
You know the power and risks of using the preload feature.
Understanding preload helps avoid permanent mistakes that affect millions of users.
Under the Hood
When a browser receives the HSTS header, it stores the domain and the max-age time in its internal memory. For all future visits within that time, the browser automatically converts any HTTP requests to HTTPS before sending them. This prevents insecure connections from ever happening. The includeSubDomains directive extends this behavior to all subdomains. The preload list is a hardcoded list in browsers that enforces HSTS even before the first visit.
Why designed this way?
HSTS was created to fix a common security gap where users could accidentally use HTTP and be attacked. It uses browser memory to enforce security without server intervention on every request. The preload list was added later to protect first-time visitors, who otherwise could be attacked before receiving the header. This design balances security with performance and usability.
┌───────────────┐       ┌───────────────┐       ┌───────────────┐
│ Server sends │──────▶│ Browser stores │──────▶│ Browser forces │
│ HSTS header  │       │ HSTS policy    │       │ HTTPS requests│
└───────────────┘       └───────────────┘       └───────────────┘
         ▲                      │                      │
         │                      ▼                      ▼
  ┌───────────────┐       ┌───────────────┐       ┌───────────────┐
  │ User tries    │       │ Browser blocks │       │ Secure site   │
  │ HTTP request  │       │ HTTP requests  │       │ connection    │
  └───────────────┘       └───────────────┘       └───────────────┘
Myth Busters - 3 Common Misconceptions
Quick: Does setting HSTS header on HTTP responses protect users? Commit to yes or no.
Common Belief:Setting HSTS header on HTTP responses is enough to protect users.
Tap to reveal reality
Reality:Browsers ignore HSTS headers sent over HTTP; they only accept them over HTTPS.
Why it matters:If you send HSTS on HTTP, users can still connect insecurely, leaving them vulnerable.
Quick: Does HSTS guarantee your site is always safe from all attacks? Commit to yes or no.
Common Belief:HSTS alone makes a website completely secure.
Tap to reveal reality
Reality:HSTS only enforces HTTPS usage; it does not protect against other vulnerabilities like weak certificates or server bugs.
Why it matters:Relying only on HSTS can give a false sense of security and neglect other important protections.
Quick: Can you remove your site from the HSTS preload list instantly? Commit to yes or no.
Common Belief:You can quickly remove your site from the preload list if needed.
Tap to reveal reality
Reality:Removing a site from the preload list takes time and browser updates, so it is not immediate.
Why it matters:Submitting a site prematurely can cause long-term access issues if HTTPS is not properly maintained.
Expert Zone
1
Browsers cache HSTS policies per domain and subdomain, but some browsers have different cache expiration behaviors that can affect testing.
2
The 'always' flag in nginx's add_header directive ensures the header is sent even on error responses, which is critical for consistent HSTS enforcement.
3
HSTS can interfere with legitimate HTTP testing or debugging if not temporarily disabled, requiring careful environment setup.
When NOT to use
Avoid enabling HSTS on sites that do not fully support HTTPS or have mixed content issues. For development or staging environments, use separate configurations without HSTS. Alternatives include redirecting HTTP to HTTPS without HSTS if you want less strict enforcement.
Production Patterns
In production, sites use HSTS with a long max-age and includeSubDomains to secure all subdomains. Preload is used only after thorough testing. Many large sites automate HSTS header deployment via configuration management and monitor browser reports for errors.
Connections
TLS/SSL Certificates
HSTS builds on HTTPS which requires TLS/SSL certificates to encrypt data.
Understanding certificates helps grasp why HSTS depends on HTTPS and why invalid certificates break HSTS protection.
Content Security Policy (CSP)
Both HSTS and CSP are security headers that protect users by controlling browser behavior.
Knowing how CSP restricts content sources complements HSTS's role in enforcing secure connections.
Human Immune System
HSTS acts like an immune memory that remembers past infections and blocks future attacks.
Seeing HSTS as a memory-based defense helps understand its role in preventing repeated security breaches.
Common Pitfalls
#1Sending HSTS header only on HTTP responses.
Wrong approach:server { listen 80; add_header Strict-Transport-Security "max-age=31536000"; }
Correct approach:server { listen 443 ssl; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; }
Root cause:Misunderstanding that HSTS headers must be sent over HTTPS to be effective.
#2Setting a very long max-age without testing first.
Wrong approach:add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
Correct approach:add_header Strict-Transport-Security "max-age=60; includeSubDomains" always; # Test with short max-age first
Root cause:Not realizing that a long max-age can lock users into HTTPS even if misconfiguration occurs.
#3Enabling preload without submitting to the preload list.
Wrong approach:add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
Correct approach:add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; # Add preload only after submitting and approval
Root cause:Confusing the preload directive with automatic inclusion in browser preload lists.
Key Takeaways
HSTS is a security header that forces browsers to use HTTPS, protecting users from insecure connections.
It works by telling browsers to remember to only connect securely for a set time, including optionally all subdomains.
Proper configuration and testing are essential to avoid locking users out or causing access problems.
The preload list enforces HSTS before the first visit but requires careful preparation and submission.
HSTS complements other security measures but does not replace the need for valid certificates and secure server setups.

Practice

(1/5)
1. What is the main purpose of the Strict-Transport-Security (HSTS) header in nginx?
easy
A. To force browsers to use HTTPS instead of HTTP for the site
B. To redirect HTTP requests to a different domain
C. To enable caching of static files in the browser
D. To compress responses sent to the client

Solution

  1. Step 1: Understand HSTS header purpose

    The HSTS header tells browsers to only use HTTPS for the site, improving security.
  2. Step 2: Compare options with HSTS function

    Only To force browsers to use HTTPS instead of HTTP for the site matches this purpose; others describe unrelated features.
  3. Final Answer:

    To force browsers to use HTTPS instead of HTTP for the site -> Option A
  4. Quick Check:

    HSTS = Force HTTPS [OK]
Hint: HSTS means browsers must use HTTPS always [OK]
Common Mistakes:
  • Confusing HSTS with redirects
  • Thinking HSTS controls caching
  • Assuming HSTS compresses data
2. Which of the following is the correct nginx syntax to add an HSTS header that lasts for 1 year and applies to all subdomains?
easy
A. add_header Strict-Transport-Security max-age=31536000 includeSubDomains always;
B. add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
C. add_header Strict-Transport-Security "max-age=31536000 includeSubDomains";
D. add_header Strict-Transport-Security max-age=31536000; includeSubDomains always;

Solution

  1. Step 1: Check correct syntax for add_header

    The header value must be a quoted string with directives separated by semicolons, and 'always;' ensures it is added on all responses.
  2. Step 2: Validate option formatting

    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; correctly quotes the value and uses semicolon between directives with 'always;'. Others miss quotes or semicolons or misplace 'always'.
  3. Final Answer:

    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; -> Option B
  4. Quick Check:

    Quotes + semicolon + always = add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; [OK]
Hint: Use quotes and semicolons inside add_header value [OK]
Common Mistakes:
  • Missing quotes around header value
  • Forgetting semicolon between directives
  • Placing 'always' inside quotes
3. Given this nginx config snippet:
add_header Strict-Transport-Security "max-age=86400; includeSubDomains" always;

What is the effect on browsers visiting the site?
medium
A. Browsers will enforce HTTPS for 1 day on the site and all subdomains
B. Browsers will enforce HTTPS for 1 year on the site only
C. Browsers will ignore the header because max-age is too low
D. Browsers will enforce HTTPS for 1 day on the site only

Solution

  1. Step 1: Interpret max-age and includeSubDomains

    max-age=86400 means 86400 seconds = 1 day. includeSubDomains applies to all subdomains.
  2. Step 2: Understand browser behavior

    Browsers will enforce HTTPS for 1 day on the site and all its subdomains as per header.
  3. Final Answer:

    Browsers will enforce HTTPS for 1 day on the site and all subdomains -> Option A
  4. Quick Check:

    86400 seconds = 1 day + includeSubDomains = Browsers will enforce HTTPS for 1 day on the site and all subdomains [OK]
Hint: max-age in seconds; 86400 = 1 day [OK]
Common Mistakes:
  • Confusing seconds with days
  • Ignoring includeSubDomains effect
  • Assuming max-age too low disables HSTS
4. You added this line in nginx:
add_header Strict-Transport-Security max-age=31536000 includeSubDomains always;

Why is the HSTS header not sent to clients?
medium
A. includeSubDomains is not a valid directive
B. The 'always' directive must be inside the quotes
C. max-age value is too large and rejected by nginx
D. The header value is missing quotes, causing syntax error

Solution

  1. Step 1: Check syntax for add_header directive

    The header value must be enclosed in quotes. Missing quotes cause nginx to ignore the header.
  2. Step 2: Validate other parts

    'always' must be outside quotes, max-age=31536000 is valid, includeSubDomains is valid directive.
  3. Final Answer:

    The header value is missing quotes, causing syntax error -> Option D
  4. Quick Check:

    Quotes missing = header not sent [OK]
Hint: Always quote header values in add_header [OK]
Common Mistakes:
  • Placing 'always' inside quotes
  • Not quoting header value
  • Misunderstanding valid directives
5. You want to preload your site in browsers' HSTS preload list. Which nginx header configuration is correct to achieve this for 6 months including subdomains?
hard
A. add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
B. add_header Strict-Transport-Security "max-age=15768000; preload" always;
C. add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload" always;
D. add_header Strict-Transport-Security "max-age=15768000; includeSubDomains" always;

Solution

  1. Step 1: Calculate max-age for 6 months

    6 months ≈ 15768000 seconds (6 * 30 * 24 * 3600).
  2. Step 2: Include required directives for preload

    Preload requires max-age, includeSubDomains, and preload directive all present.
  3. Step 3: Verify syntax correctness

    add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload" always; correctly quotes the value, uses semicolons, includes all directives, and uses 'always;'.
  4. Final Answer:

    add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload" always; -> Option C
  5. Quick Check:

    Preload + includeSubDomains + 6 months = add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload" always; [OK]
Hint: Preload needs max-age, includeSubDomains, preload keywords [OK]
Common Mistakes:
  • Using wrong max-age for 6 months
  • Omitting preload directive
  • Not quoting header value
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard