Task 26: Implement HTTPS-Only Cookies
Role
DevOpsOverview
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
Cookie Security Requirements
Required Cookie Attributes
| Attribute | Value | Purpose |
|---|---|---|
| Secure | true | Only transmit over HTTPS |
| HttpOnly | true | Prevent JavaScript access (XSS protection) |
| SameSite | Strict or Lax | CSRF protection |
| Domain | .micdots.com | Allow subdomain access |
| Path | / | Available site-wide |
| MaxAge | 3600 (1 hour) | Token expiration |
Cookie Configuration
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
1. Configure Cookie Policy (ASP.NET Core)
// 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
Cookie Security
- 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
Related Content
Related Tasks
- Task 27: Add CSRF Protection (Coming Soon)
- Task 30: Add Security Headers
- Task 18: Create Authentication API Endpoint