Man In The Middle with Bearer Tokens
How Man In The Middle Manifests in Bearer Tokens
A Man-In-The-Middle (MITM) attack against Bearer Tokens occurs when an attacker can intercept, read, or modify the token while it travels between client and server. Because Bearer Tokens are typically sent in the Authorization: Bearer <token> header, any compromise of the transport layer directly exposes the token.
- Unencrypted HTTP: If the API endpoint is reachable over plain HTTP, an attacker on the same network can sniff packets and extract the token. Once obtained, the attacker can replay requests with full privileges.
- Token leakage via redirects or referrer headers: Some implementations mistakenly place the token in the query string or in the
Locationheader during a redirect. Network observers or malicious third‑party sites can capture it from theRefererheader. - Improper logging: Development or debugging code that logs the full
Authorizationheader writes the token to log files or monitoring systems. If those logs are accessible (e.g., via log aggregation services with weak ACLs), an insider or compromised system can harvest tokens. - Proxy or TLS termination misconfiguration: When a reverse proxy terminates TLS and forwards traffic to the backend over HTTP, the token is exposed inside the data center. An attacker who gains access to the internal network can capture it.
These patterns map to OWASP API Security Top 10 2023 API2:2023 Broken Authentication (token exposure) and the broader class of Insufficient Transport Layer Protection. Real‑world incidents include CVE‑2020-13943, where a misconfigured API gateway forwarded tokens over internal HTTP, allowing internal attackers to hijack sessions.
Bearer Tokens-Specific Detection
Detecting MITM risks for Bearer Tokens involves checking both the transport security and the way the token is handled in requests and responses. middleBrick performs these checks automatically as part of its 12‑point scan.
- Transport validation: The scanner verifies that the target endpoint is only reachable via HTTPS and that HTTP requests are redirected (or rejected). It also checks for HSTS headers (
Strict-Transport-Security) that enforce TLS use. - Token exposure in URLs: middleBrick scans response bodies, headers, and redirect locations for the presence of the Bearer token in query strings, fragments, or custom headers that could be leaked via
Referer. - Logging and error messages: By probing error endpoints, the tool looks for messages that echo back the
Authorizationheader or token fragments, which would indicate risky logging. - Cookie flags (if token stored in a cookie): Although Bearer Tokens are usually header‑based, some implementations mirror them in cookies. The scanner ensures any such cookie is marked
SecureandHttpOnly.
Example of using the middleBrick CLI to scan an API for these issues:
# Install the CLI (npm)
npm i -g middlebrick
# Scan a target endpoint
middlebrick scan https://api.example.com/orders
The output includes a severity rating for each check. If the transport is insecure, you will see a finding under the Authentication category with a description like:
"API endpoint accessible over plain HTTP; Bearer Token transmitted without TLS protection. Potential MITM exposure."
Similarly, if a token appears in a redirect location, the scanner flags a Data Exposure finding. These findings give you actionable guidance without requiring agents, credentials, or configuration.
Bearer Tokens-Specific Remediation
Fixing MITM vulnerabilities for Bearer Tokens focuses on guaranteeing confidentiality and integrity of the token in transit and limiting its exposure elsewhere. The following code snippets illustrate native language‑level mitigations.
Enforce HTTPS and HSTS (Node.js/Express)
const express = require('express');
const helmet = require('helmet');
const app = express();
// Helper: redirect HTTP to HTTPS
app.all('*', (req, res, next) => {
if (req.headers['x-forwarded-proto'] !== 'https') {
return res.redirect(301, `https://${req.headers.host}${req.url}`);
}
next();
});
// Helmet sets HSTS and other safe defaults
app.use(helmet({
hsts: {
maxAge: 31536000, // 1 year
includeSubDomains: true,
preload: true
}
}));
// Example protected route
app.get('/api/orders', (req, res) => {
const auth = req.headers.authorization;
if (!auth || !auth.startsWith('Bearer ')) {
return res.status(401).json({ error: 'Missing token' });
}
const token = auth.split(' ')[1];
// Verify token (signature, expiry, audience, etc.)
// ...
res.json({ msg: 'Orders data' });
});
app.listen(3000);
Avoid logging the Authorization header (Python/Flask)
from flask import Flask, request, jsonify
import logging
app = Flask(__name__)
# Suppress logging of Authorization header
class TokenFilter(logging.Filter):
def filter(self, record):
if hasattr(record, 'args') and isinstance(record.args, dict):
record.args.pop('Authorization', None)
return True
logging.getLogger('werkzeug').addFilter(TokenFilter())
@app.route('/api/orders')
def orders():
auth = request.headers.get('Authorization')
if not auth or not auth.startswith('Bearer '):
return jsonify(error='Missing token'), 401
token = auth.split(' ')[1]
# Validate token (signature, claims, etc.)
# ...
return jsonify(msg='Orders data')
if __name__ == '__main__':
# In production run behind a TLS‑terminating proxy
app.run(host='0.0.0.0', port=8000, debug=False)
Short‑lived tokens and audience validation
Even if an attacker intercepts a token, limiting its lifetime reduces the window of misuse. Additionally, verifying the aud (audience) claim ensures the token was issued for your specific API.
// Node.js jsonwebtoken example
const jwt = require('jsonwebtoken');
function verifyBearerToken(token) {
try {
const payload = jwt.verify(token, process.env.JWT_PUBLIC_KEY, {
algorithms: ['RS256'],
audience: 'https://api.example.com/',
issuer: 'https://auth.example.com/'
});
return payload; // valid
} catch (err) {
throw new Error('Invalid token');
}
}
// Middleware
function authMiddleware(req, res, next) {
const auth = req.headers.authorization;
if (!auth || !auth.startsWith('Bearer ')) {
return res.status(401).json({ error: 'Missing token' });
}
const token = auth.split(' ')[1];
try {
req.user = verifyBearerToken(token);
next();
} catch (e) {
return res.status(401).json({ error: e.message });
}
}
By combining transport‑level protections (HTTPS+HSTS), careful token handling (no logging, no URL exposure), and strong token validation (short life, audience/issuer checks), you eliminate the practical avenues for a MITM attacker to steal or reuse a Bearer Token.