- Home
- Cookie Attributes
- Secure
Cookie Attribute
Secure
Learn how the Secure cookie attribute ensures cookies are only sent over HTTPS connections. Protect sensitive data from man-in-the-middle attacks.
TL;DR: Ensures cookies are only sent over HTTPS connections, never HTTP - essential for protecting sensitive data like session tokens from network interception.
What is the Secure Attribute?
The Secure attribute ensures cookies are only transmitted over encrypted HTTPS connections, never over plain HTTP. It’s like sending sensitive mail in a locked briefcase instead of a regular envelope - the cookie data is protected from eavesdropping during transmission.
This attribute is essential for protecting sensitive information from network-based attacks.
How It Works
Without Secure Attribute
Cookie sent over both HTTP and HTTPS:
Set-Cookie: sessionId=abc123
# Sent over: HTTP ✅ and HTTPS ✅
# Risk: Can be intercepted on HTTP
```text
### With Secure Attribute
Cookie only sent over HTTPS:
```http
Set-Cookie: sessionId=abc123; Secure
# Sent over: HTTP ❌ and HTTPS ✅
# Protected: Cannot be intercepted on HTTP
Security Benefits
Man-in-the-Middle Protection
Without Secure, cookies can be stolen:
User → HTTP → Router/ISP → Server
↑
Cookie visible in plain text!
sessionId=abc123 can be stolen
With Secure, cookies are encrypted:
User → HTTPS → Router/ISP → Server
↑
Cookie encrypted in TLS tunnel
Attacker sees only encrypted data
Network Eavesdropping Prevention
# ❌ Vulnerable: Sensitive data over HTTP
Set-Cookie: bankingSession=secret123
# ✅ Protected: Encrypted transmission
Set-Cookie: bankingSession=secret123; Secure
```text
## Real-World Examples
### User Authentication
Protect login sessions:
```http
Set-Cookie: sessionId=user123session; Secure; HttpOnly; SameSite=Strict; Max-Age=3600
Financial Applications
Maximum security for banking:
Set-Cookie: bankingToken=secure456; Secure; HttpOnly; SameSite=Strict; Max-Age=900
```text
### API Authentication
Protect API tokens:
```http
Set-Cookie: apiKey=bearer789; Secure; HttpOnly; Path=/api; Max-Age=86400
Admin Panel Access
Secure administrative sessions:
Set-Cookie: adminSession=admin123; Secure; HttpOnly; Path=/admin; SameSite=Strict; Max-Age=1800
```text
### E-commerce Checkout
Protect payment-related data:
```http
Set-Cookie: checkoutSession=payment456; Secure; HttpOnly; SameSite=Lax; Max-Age=3600
Remember Me Tokens
Long-term authentication:
Set-Cookie: rememberToken=longterm789; Secure; HttpOnly; SameSite=Strict; Max-Age=2592000
```javascript
## When to Use Secure
### ✅ Always Use For:
- Authentication sessions
- API tokens
- Payment information
- Personal data
- Admin access
- Any sensitive information
### ⚠️ Consider For:
- User preferences (if privacy is important)
- Shopping cart data
- Analytics data (depending on privacy policy)
### ❌ Not Required For:
- Public, non-sensitive data
- Development/testing (HTTP environments)
- Purely functional cookies with no security implications
## Implementation Examples
### Express.js
```javascript
// Production: Always use Secure
app.post('/login', (req, res) => {
res.cookie('sessionId', sessionId, {
secure: true, // HTTPS only
httpOnly: true, // No JavaScript access
sameSite: 'strict', // CSRF protection
maxAge: 24 * 60 * 60 * 1000 // 24 hours
})
})
// Environment-aware secure setting
const isProduction = process.env.NODE_ENV === 'production'
res.cookie('sessionId', sessionId, {
secure: isProduction, // Secure in production, allow HTTP in dev
httpOnly: true,
sameSite: 'strict'
})
Python Flask
@app.route('/login', methods=['POST'])
def login():
response = make_response({'success': True})
response.set_cookie(
'sessionId',
session_id,
secure=True, # HTTPS only
httponly=True, # No JavaScript access
samesite='Strict', # CSRF protection
max_age=3600 # 1 hour
)
return response
```text
### PHP
```php
// Secure session cookie
setcookie('sessionId', $sessionId, [
'expires' => time() + 3600,
'secure' => true, // HTTPS only
'httponly' => true, // No JavaScript access
'samesite' => 'Strict' // CSRF protection
]);
// Environment-aware
$isHttps = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on';
setcookie('sessionId', $sessionId, [
'secure' => $isHttps, // Secure if HTTPS available
'httponly' => true
]);
ASP.NET Core
// Secure authentication cookie
Response.Cookies.Append("sessionId", sessionId, new CookieOptions
{
Secure = true, // HTTPS only
HttpOnly = true, // No JavaScript access
SameSite = SameSiteMode.Strict, // CSRF protection
MaxAge = TimeSpan.FromHours(1) // 1 hour
});
```javascript
## Development vs Production
### Development Environment
```javascript
// Allow HTTP for local development
const isDevelopment = process.env.NODE_ENV === 'development'
res.cookie('sessionId', sessionId, {
secure: !isDevelopment, // Allow HTTP in development
httpOnly: true,
sameSite: 'strict'
})
Production Environment
// Always require HTTPS in production
if (process.env.NODE_ENV === 'production') {
app.use((req, res, next) => {
if (!req.secure && req.get('x-forwarded-proto') !== 'https') {
return res.redirect(301, `https://${req.get('host')}${req.url}`)
}
next()
})
}
// All cookies secure in production
res.cookie('sessionId', sessionId, {
secure: true, // Always true in production
httpOnly: true
})
```text
## HTTPS Enforcement
### Redirect HTTP to HTTPS
```javascript
// Express.js HTTPS redirect
app.use((req, res, next) => {
if (process.env.NODE_ENV === 'production' && !req.secure) {
return res.redirect(301, `https://${req.get('host')}${req.url}`)
}
next()
})
Strict Transport Security
// Force HTTPS for future requests
app.use((req, res, next) => {
if (req.secure) {
res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains')
}
next()
})
```javascript
### Load Balancer Considerations
```javascript
// Handle HTTPS termination at load balancer
app.set('trust proxy', 1) // Trust first proxy
app.use((req, res, next) => {
const isSecure = req.secure || req.get('x-forwarded-proto') === 'https'
res.secureCookie = (name, value, options = {}) => {
options.secure = isSecure
res.cookie(name, value, options)
}
next()
})
Security Best Practices
Layer Security Attributes
# Maximum security combination
Set-Cookie: sessionId=abc123; Secure; HttpOnly; SameSite=Strict; Max-Age=3600
```javascript
### Environment-Specific Configuration
```javascript
const cookieConfig = {
development: {
secure: false, // Allow HTTP for local dev
sameSite: 'lax' // Relaxed for testing
},
production: {
secure: true, // HTTPS only
sameSite: 'strict' // Maximum security
}
}
const config = cookieConfig[process.env.NODE_ENV] || cookieConfig.production
res.cookie('sessionId', sessionId, {
...config,
httpOnly: true,
maxAge: 24 * 60 * 60 * 1000
})
Certificate Validation
// Ensure valid HTTPS certificates
if (process.env.NODE_ENV === 'production') {
// Reject self-signed certificates
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '1'
}
```javascript
## Common Issues
### Mixed Content Problems
```javascript
// Problem: HTTPS page loading HTTP resources
// Secure cookies won't be sent to HTTP endpoints
// Solution: Ensure all resources use HTTPS
const apiUrl =
process.env.NODE_ENV === 'production' ? 'https://api.example.com' : 'http://localhost:3001'
Development Environment Issues
// Problem: Secure cookies don't work on localhost HTTP
Set-Cookie: sessionId=abc; Secure
// Won't work on http://localhost:3000
// Solution: Environment-aware configuration
const secure = process.env.NODE_ENV === 'production'
res.cookie('sessionId', sessionId, { secure })
```javascript
### Load Balancer SSL Termination
```javascript
// Problem: App thinks it's HTTP when behind HTTPS load balancer
// Solution: Trust proxy headers
app.set('trust proxy', 1)
const isSecure = req.secure || req.get('x-forwarded-proto') === 'https'
res.cookie('sessionId', sessionId, { secure: isSecure })
Testing Secure Cookies
Manual Testing
# Test HTTPS cookie setting
curl -v -X POST https://example.com/login \
-d "username=test&password=test" \
-c cookies.txt
# Verify Secure attribute in response
grep "Secure" cookies.txt
```javascript
### Automated Testing
```javascript
// Test that sensitive cookies are Secure
test('login should set secure session cookie', async () => {
const response = await request(app).post('/login').send({ username: 'test', password: 'test' })
const setCookieHeader = response.headers['set-cookie']
const sessionCookie = setCookieHeader.find((cookie) => cookie.startsWith('sessionId='))
expect(sessionCookie).toContain('Secure')
expect(sessionCookie).toContain('HttpOnly')
})
Related Attributes
Frequently Asked Questions
What is the Secure cookie attribute?
Secure ensures cookies are only sent over HTTPS connections. It prevents cookies from being transmitted over unencrypted HTTP, protecting against interception.
Should all cookies be Secure?
Yes, in production. All sensitive cookies (session, auth) must be Secure. Even non-sensitive cookies benefit from Secure to prevent tampering.
Can I set Secure cookies on localhost?
Browsers allow Secure cookies on localhost for development. In production, Secure cookies require HTTPS. Some browsers are stricter than others.
What happens if I access HTTP with Secure cookies?
Secure cookies are not sent over HTTP. The server will not receive them, potentially logging users out or breaking functionality. Always use HTTPS.