Skip to main content

Task 26: Implement HTTPS-Only Cookies

Role

DevOps

Overview

Configure secure cookie settings for JWT tokens and session management, ensuring all authentication cookies are transmitted only over HTTPS and protected from common web vulnerabilities.

Objectives

  • Enable HTTPS-only cookie transmission
  • Set secure cookie attributes (HttpOnly, Secure, SameSite)
  • Configure cookie domains and paths correctly
  • Prevent cookie theft and CSRF attacks
  • Ensure cookies work correctly across environments
AttributeValuePurpose
SecuretrueOnly transmit over HTTPS
HttpOnlytruePrevent JavaScript access (XSS protection)
SameSiteStrict or LaxCSRF protection
Domain.micdots.comAllow subdomain access
Path/Available site-wide
MaxAge3600 (1 hour)Token expiration
public class SecureCookieOptions
{
public string Name { get; set; } = "micdots_auth";
public bool HttpOnly { get; set; } = true;
public bool Secure { get; set; } = true;
public SameSiteMode SameSite { get; set; } = SameSiteMode.Strict;
public string Domain { get; set; } = ".micdots.com";
public string Path { get; set; } = "/";
public int MaxAgeSeconds { get; set; } = 3600;
}

Implementation

// Startup.cs or Program.cs
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => false; // No consent banner for auth cookies
options.MinimumSameSitePolicy = SameSiteMode.Strict;
options.HttpOnly = HttpOnlyPolicy.Always;
options.Secure = CookieSecurePolicy.Always; // Require HTTPS
});

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.Cookie.Name = "micdots_auth";
options.Cookie.HttpOnly = true;
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
options.Cookie.SameSite = SameSiteMode.Strict;
options.Cookie.Domain = ".micdots.com";
options.Cookie.Path = "/";
options.ExpireTimeSpan = TimeSpan.FromHours(1);
options.SlidingExpiration = true;
});
}

public void Configure(IApplicationBuilder app)
{
app.UseCookiePolicy();
app.UseAuthentication();
app.UseAuthorization();
}

2. Set Cookies in Authentication Response

[HttpPost("login")]
public async Task<IActionResult> Login([FromBody] LoginRequest request)
{
var result = await _authService.AuthenticateAsync(request.Email, request.Password);

if (!result.Success)
{
return Unauthorized();
}

// Set access token cookie
Response.Cookies.Append("micdots_auth", result.AccessToken, new CookieOptions
{
HttpOnly = true,
Secure = true,
SameSite = SameSiteMode.Strict,
Domain = ".micdots.com",
Path = "/",
MaxAge = TimeSpan.FromHours(1),
IsEssential = true // Exempt from GDPR consent
});

// Set refresh token cookie
Response.Cookies.Append("micdots_refresh", result.RefreshToken, new CookieOptions
{
HttpOnly = true,
Secure = true,
SameSite = SameSiteMode.Strict,
Domain = ".micdots.com",
Path = "/api/v1/auth/refresh", // Only accessible to refresh endpoint
MaxAge = TimeSpan.FromDays(7)
});

return Ok(new { success = true, user = result.User });
}

3. Environment-Specific Configuration

// appsettings.Development.json
{
"CookieSettings": {
"Secure": false, // Allow HTTP in development
"Domain": "localhost",
"SameSite": "Lax"
}
}

// appsettings.Production.json
{
"CookieSettings": {
"Secure": true, // Require HTTPS in production
"Domain": ".micdots.com",
"SameSite": "Strict"
}
}
// Load from configuration
services.Configure<SecureCookieOptions>(Configuration.GetSection("CookieSettings"));

Infrastructure Configuration

1. Enable HTTPS in Web Server

Nginx Configuration

server {
listen 443 ssl http2;
server_name micdots.com www.micdots.com;

ssl_certificate /etc/letsencrypt/live/micdots.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/micdots.com/privkey.pem;

# SSL Configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers HIGH:!aNULL:!MD5;

# HSTS Header
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

# Proxy to application
location / {
proxy_pass http://localhost:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}

# Redirect HTTP to HTTPS
server {
listen 80;
server_name micdots.com www.micdots.com;
return 301 https://$server_name$request_uri;
}

Docker Compose Configuration

version: '3.8'

services:
app:
image: micdots-app:latest
environment:
- ASPNETCORE_ENVIRONMENT=Production
- ASPNETCORE_URLS=https://+:443;http://+:80
- ASPNETCORE_Kestrel__Certificates__Default__Path=/app/certs/cert.pfx
- ASPNETCORE_Kestrel__Certificates__Default__Password=${CERT_PASSWORD}
ports:
- "443:443"
- "80:80"
volumes:
- ./certs:/app/certs

2. SSL Certificate Setup (Let's Encrypt)

# Install Certbot
sudo apt-get update
sudo apt-get install certbot python3-certbot-nginx

# Obtain SSL certificate
sudo certbot --nginx -d micdots.com -d www.micdots.com

# Auto-renewal (cron job)
sudo crontab -e
0 0 * * * certbot renew --quiet --post-hook "systemctl reload nginx"

3. Test HTTPS Configuration

# Test SSL/TLS configuration
curl -I https://micdots.com

# Check certificate validity
openssl s_client -connect micdots.com:443 -servername micdots.com

# Verify HSTS header
curl -I https://micdots.com | grep Strict-Transport-Security

# Test cookie attributes
curl -v -c cookies.txt https://micdots.com/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"client01@micdots.com","password":"Mic1234!"}'

# View cookie file
cat cookies.txt

Security Verification Checklist

  • Cookies are only sent over HTTPS (Secure flag)
  • Cookies are not accessible via JavaScript (HttpOnly flag)
  • CSRF protection enabled (SameSite=Strict)
  • Cookie domain is correctly set
  • Cookie path is restrictive where appropriate
  • MaxAge/Expires is set appropriately
  • Sensitive cookies use different expiration times

HTTPS Configuration

  • Valid SSL certificate installed
  • Certificate auto-renewal configured
  • HTTP automatically redirects to HTTPS
  • HSTS header is set
  • TLS 1.2+ only (no TLS 1.0/1.1)
  • Strong cipher suites configured
  • SSL Labs test scores A or A+

Testing

  • Cookies work in production environment
  • Cookies work across subdomains (if needed)
  • Browser console shows no cookie warnings
  • Developer tools show correct cookie attributes
  • Cross-browser testing completed
  • Mobile browser testing completed

Acceptance Criteria

  • All cookies use Secure flag in production
  • All cookies use HttpOnly flag
  • SameSite attribute set to Strict or Lax
  • HTTPS enforced on all environments (except local dev)
  • Valid SSL certificate installed
  • HSTS header configured
  • HTTP→HTTPS redirect working
  • Cookies persist across page refreshes
  • Cookies expire correctly
  • Cookie domain configuration correct
  • Works in all major browsers
  • Documentation updated
  • Configuration externalized
  • Environment-specific settings work

Testing Checklist

Manual Testing

  • Login and verify cookie is set with correct attributes
  • Check cookie in browser DevTools
  • Verify cookie is not accessible via JavaScript console
  • Test logout clears cookies
  • Test cookie expiration
  • Test on different browsers (Chrome, Firefox, Safari, Edge)
  • Test on mobile devices

Security Testing

  • Run SSL Labs test (https://www.ssllabs.com/ssltest/)
  • Verify no mixed content warnings
  • Test CSRF protection
  • Attempt XSS cookie theft (should fail)
  • Test cookie replay attacks

Automated Testing

# Security headers test
curl -I https://micdots.com | grep -E 'Strict-Transport-Security|X-Frame-Options|X-Content-Type-Options'

# Cookie security test
curl -v https://micdots.com/api/v1/auth/login 2>&1 | grep -E 'Set-Cookie.*Secure|HttpOnly|SameSite'

Estimated Time

1 day (8 hours)

Dependencies

  • Valid SSL certificate
  • Domain DNS configured
  • Load balancer/reverse proxy configured
  • Task 18: Auth endpoint implemented

External Resources