When using HTTPS (HTTP Secure), the entire HTTP request is encrypted, including:
- Headers
- Request body
- Query parameters
This means the URL path and query string (?mysecretstring=1234
) are encrypted during transmission between client and server.
Despite HTTPS encryption, sensitive data in URLs can be exposed through:
// Example of logging URL parameters (vulnerable to exposure)
const urlParams = new URLSearchParams(window.location.search);
console.log(urlParams.get('mysecretstring')); // Visible in browser console
Web servers typically log full URLs in access logs:
# Example Apache access log entry
127.0.0.1 - - [10/Oct/2023:14:32:10 +0000] "GET /?mysecretstring=1234 HTTP/1.1" 200 432
URLs remain visible in:
- Browser history
- Bookmarks
- Referrer headers when navigating to other sites
Click me
Instead of URL parameters, consider:
// Using POST requests with HTTPS
fetch('/api/endpoint', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ secret: '1234' })
});
// Using HTTP headers
fetch('/api/endpoint', {
headers: {
'Authorization': 'Bearer 1234'
}
});
URL parameters are fine for:
- Non-sensitive filters (
?category=books
) - Public identifiers (
?product_id=123
) - Session tokens (when using HttpOnly, Secure cookies)
# Nginx configuration to strip sensitive data from logs
map $request_uri $loggable_uri {
default $request_uri;
"^(.*?)\?mysecretstring=[^&]*(.*)$" $1?[FILTERED]$2;
}
server {
access_log /var/log/nginx/access.log combined uri=$loggable_uri;
}
When examining HTTPS security, it's crucial to understand what parts of the request are actually encrypted. The encryption covers:
- HTTP headers
- Request payload (POST body)
- Response content
- Cookies
However, the URL path and query parameters exist in a gray area. While the content of HTTPS requests is encrypted, certain metadata remains visible:
GET /search?q=confidential HTTP/1.1
Host: example.com
Several points in the request lifecycle expose URL parameters:
- Browser History: URLs remain in plaintext in browsing history
- Server Logs: Web servers typically log full request URLs
- Referrer Headers: When navigating between HTTPS sites
- Network Equipment: Proxies or load balancers might log URLs
Here's how you might sanitize sensitive data in Node.js:
const express = require('express');
const app = express();
// Middleware to check for sensitive params
app.use((req, res, next) => {
const sensitiveParams = ['token', 'password', 'secret'];
const hasSensitiveData = sensitiveParams.some(param => param in req.query);
if (hasSensitiveData) {
return res.status(400).json({
error: 'Sensitive parameters in URL are not allowed'
});
}
next();
});
app.get('/safe-endpoint', (req, res) => {
res.send('Secure endpoint reached');
});
For maximum security:
- Never put authentication tokens in URLs - use Authorization headers
- Use POST instead of GET for sensitive operations
- Implement CSRF protection for state-changing operations
- Configure Referrer-Policy headers
Proper OAuth flow avoids URL parameters for sensitive data:
// GOOD: Using POST with body
fetch('/auth/token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
client_id: 'your_client_id',
code: 'authorization_code',
redirect_uri: 'https://yoursite.com/callback'
})
});
// BAD: Using GET with params
window.location = https://authserver.com?client_id=xyz&secret=abc;
Consider these HTTP headers to enhance security:
Referrer-Policy: no-referrer
Cache-Control: no-store
Clear-Site-Data: "cache", "cookies", "storage"
Non-sensitive use cases for query parameters include:
- Search queries (q=term)
- Pagination (page=2)
- Sorting parameters (sort=date)
- Non-sensitive filters (category=books)