Broken Authentication in Flask with Bearer Tokens
Broken Authentication in Flask with Bearer Tokens — how this specific combination creates or exposes the vulnerability
Broken Authentication in Flask when using Bearer Tokens typically arises from misconfiguration and insecure handling of token transmission, storage, and validation. Flask itself is minimal and does not enforce authentication; developers add behavior by integrating token-based mechanisms such as bearer tokens. If tokens are transmitted over unencrypted channels, stored insecurely, or validated with weak logic, the authentication boundary breaks.
One common pattern is defining a route that reads an Authorization header and trusts a static or predictable token. For example:
from flask import Flask, request, jsonify
app = Flask(__name__)
# Insecure: static bearer token, no transport or storage protections
VALID_TOKEN = 'secret123'
@app.route('/profile')
def profile():
auth = request.headers.get('Authorization', '')
if auth.startswith('Bearer ') and auth.split(' ')[1] == VALID_TOKEN:
return jsonify(user='alice', role='admin')
return jsonify(error='Unauthorized'), 401
if __name__ == '__main__':
app.run(debug=True) # Debug mode can expose tokens in error pages
This approach is vulnerable because the token is hardcoded and equivalent to a shared secret; if leaked, an attacker can impersonate any user. Transport weaknesses occur when the token is sent over HTTP rather than HTTPS, enabling on-path interception. Storage flaws arise if tokens are logged, cached, or persisted in client-side storage without adequate protection. Validation weaknesses include accepting any string as a bearer token without verifying scope, revocation, or cryptographic integrity, making token replay or tampering feasible.
Another vulnerability pattern involves insufficient scope checks after authentication. An API may issue a bearer token but fail to enforce per-endpoint authorization, allowing a token with read-only permissions to execute privileged actions. This is often a symptom of missing or misconfigured authorization tied to the authentication layer. Additionally, tokens with long lifetimes increase the window for abuse if they are stolen. Without short expiration, revocation mechanisms, or binding to a particular client context, the authentication boundary remains fragile.
Middleware or proxy configurations can inadvertently weaken bearer token security. For instance, terminating TLS at a load balancer while forwarding requests to Flask over HTTP may expose headers, including the Authorization header, to internal networks. Flask applications must validate that tokens are only accepted over secure channels and that internal routing preserves integrity. Without explicit enforcement, the framework’s minimal defaults do not protect against these deployment-level risks.
Insecure deserialization or improper parsing of the Authorization header can also lead to authentication bypass. For example, an implementation that splits on spaces and takes the second element without strict validation may accept malformed inputs or multiple bearer-like strings. Attackers can craft ambiguous headers to bypass intended checks. Robust implementations should strictly parse the scheme, reject malformed inputs, and avoid custom token formats that deviate from standards.
Bearer Tokens-Specific Remediation in Flask — concrete code fixes
Remediation focuses on secure transmission, proper validation, scope enforcement, and operational hygiene. Always serve Flask over HTTPS using a trusted TLS termination point, and ensure the Authorization header is never logged or exposed in error messages. Prefer standard token formats (e.g., JWT) with verifiable signatures instead of static bearer strings.
Use environment variables for secrets and validate token structure rigorously. Below is a more secure example using bearer tokens with JWT verification:
import os
import jwt
from flask import Flask, request, jsonify
app = Flask(__name__)
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY')
SEVER_PUBLIC_KEY = os.environ.get('PUBLIC_KEY')
@app.route('/profile')
def profile():
auth = request.headers.get('Authorization', '')
if not auth.startswith('Bearer '):
return jsonify(error='Unauthorized'), 401
token = auth.split(' ')[1]
try:
payload = jwt.decode(token, PUBLIC_KEY, algorithms=['RS256'], audience='api', issuer='auth-service')
# Enforce scope for this endpoint
if 'read:profile' not in payload.get('scope', '').split():
return jsonify(error='Insufficient scope'), 403
return jsonify(user=payload.get('sub'), role=payload.get('role'))
except jwt.ExpiredSignatureError:
return jsonify(error='Token expired'), 401
except jwt.InvalidTokenError:
return jsonify(error='Invalid token'), 401
if __name__ == '__main__':
# In production, use a WSGI server and TLS termination at the edge
app.run(ssl_context='adhoc') # adhoc仅用于演示;生产环境应使用可信证书
This approach validates the token signature, checks audience and issuer, and enforces scope-based authorization. Environment variables keep secrets out of source code, and JWT expiration reduces the impact of token leakage. For non-JWT bearer tokens, store token hashes in a server-side revocation list and validate against it on each request.
Implement short token lifetimes and refresh workflows to limit exposure. Use HTTP-only, Secure cookies for refresh tokens if browser clients are involved, and avoid embedding bearer tokens in URLs. Apply consistent security headers and ensure logging practices exclude Authorization header values. Regularly rotate signing keys and monitor for anomalous usage patterns to detect compromised tokens early.
Related CWEs: authentication
| CWE ID | Name | Severity |
|---|---|---|
| CWE-287 | Improper Authentication | CRITICAL |
| CWE-306 | Missing Authentication for Critical Function | CRITICAL |
| CWE-307 | Brute Force | HIGH |
| CWE-308 | Single-Factor Authentication | MEDIUM |
| CWE-309 | Use of Password System for Primary Authentication | MEDIUM |
| CWE-347 | Improper Verification of Cryptographic Signature | HIGH |
| CWE-384 | Session Fixation | HIGH |
| CWE-521 | Weak Password Requirements | MEDIUM |
| CWE-613 | Insufficient Session Expiration | MEDIUM |
| CWE-640 | Weak Password Recovery | HIGH |