Missing Tls in Flask with Api Keys
Missing Tls in Flask with Api Keys — how this specific combination creates or exposes the vulnerability
Serving API keys over unencrypted HTTP in a Flask application exposes both the transport and the secret itself. Without TLS, an attacker on the same network can observe or modify traffic between the client and the server. Because API keys are typically static bearer tokens, interception grants immediate unauthorized access to the associated API or service.
Consider a Flask route that returns a stored API key or expects it in a request header:
from flask import Flask, request, jsonify
app = Flask(__name__)
# Example: storing keys in memory for illustration only
API_KEYS = {
"service_a": "ak_live_abc123",
"service_b": "ak_live_xyz789",
}
@app.route("/v1/resource")
def get_resource():
key = request.headers.get("X-API-Key")
if not key or key not in API_KEYS.values():
return jsonify({"error": "unauthorized"}), 401
return jsonify({"data": "sensitive"}), 200
If this endpoint is reachable over HTTP, any party on the network path can capture the key from request headers or responses. The risk is compounded when the same key is used across multiple services or environments, as a single interception may lead to lateral movement. In a typical man-in-the-middle scenario, the attacker passively collects keys and can then reuse them until rotation occurs.
middleBrick’s unauthenticated scans include checks for encryption (TLS) and inspect how API keys are handled during transmission. When TLS is missing, findings in the Data Exposure and Authentication categories highlight the exposure of static credentials in transit. Because API keys function as long-lived bearer tokens, the absence of encryption effectively undermines their intended confidentiality.
Additionally, without TLS, there is no integrity guarantee. An attacker can modify requests or responses, potentially injecting malicious payloads or altering authorization decisions. This intersects with Authentication and Input Validation checks, as the server may accept tampered headers without detecting manipulation. The combination of static API keys and missing transport protection therefore creates a high-impact attack surface where credential theft and request forgery become trivial.
Api Keys-Specific Remediation in Flask — concrete code fixes
Remediation focuses on enforcing transport confidentiality and reducing the exposure and impact of API keys. The primary step is to serve all endpoints over HTTPS with a valid certificate, ensuring encryption in transit. Below are concrete Flask patterns that integrate API keys safely under TLS.
1. Enforce HTTPS in Flask
Use a production WSGI server (e.g., Gunicorn) terminated by a TLS-terminating proxy or load balancer. In development, you can enforce redirect to HTTPS:
from flask import Flask, request, jsonify, redirect
app = Flask(__name__)
@app.before_request
def enforce_https():
if not request.is_secure:
url = request.url.replace("http://", "https://", 1)
return redirect(url, code=301)
API_KEYS = {
"service_a": "ak_live_abc123",
}
@app.route("/v1/resource")
def get_resource():
key = request.headers.get("X-API-Key")
if not key or key not in API_KEYS.values():
return jsonify({"error": "unauthorized"}), 401
return jsonify({"data": "sensitive"}), 200
Note: In production, rely on your infrastructure’s TLS termination rather than Flask’s built-in server. The above is for development guidance only.
2. Store and compare keys securely
Avoid storing raw keys in code or global variables. Use environment variables and constant-time comparison to prevent timing attacks:
import os
import hmac
from flask import Flask, request, jsonify
app = Flask(__name__)
# Load expected key from environment (set outside source code)
EXPECTED_KEY = os.environ.get("API_KEY")
@app.route("/v1/resource")
def get_resource():
provided = request.headers.get("X-API-Key")
if not provided or not EXPECTED_KEY or not hmac.compare_digest(provided, EXPECTED_KEY):
return jsonify({"error": "unauthorized"}), 401
return jsonify({"data": "sensitive"}), 200
3. Rotate keys and avoid long-lived static keys
While code can mitigate transport risks, static keys remain high value. Integrate key rotation and scope limitation (per-service, per-client). For short-lived access, consider issuing tokens via an authorization server rather than long-lived API keys.
4. Use middleware for key validation
Centralize validation to avoid repetitive checks and reduce human error:
from flask import Flask, request, jsonify
app = Flask(__name__)
def require_api_key(view_func):
def wrapper(*args, **kwargs):
if request.headers.get("X-API-Key") != "REPLACE_WITH_VALID_KEY":
return jsonify({"error": "forbidden"}), 403
return view_func(*args, **kwargs)
return wrapper
@app.route("/v1/resource")
@require_api_key
def get_resource():
return jsonify({"data": "protected"}), 200
These patterns, combined with mandatory TLS, reduce the likelihood of key interception and misuse. middleBrick’s scans can verify the presence of encryption and flag endpoints that transmit API keys in cleartext, enabling teams to remediate findings before exposure in production.
Related CWEs: encryption
| CWE ID | Name | Severity |
|---|---|---|
| CWE-319 | Cleartext Transmission of Sensitive Information | HIGH |
| CWE-295 | Improper Certificate Validation | HIGH |
| CWE-326 | Inadequate Encryption Strength | HIGH |
| CWE-327 | Use of a Broken or Risky Cryptographic Algorithm | HIGH |
| CWE-328 | Use of Weak Hash | HIGH |
| CWE-330 | Use of Insufficiently Random Values | HIGH |
| CWE-338 | Use of Cryptographically Weak PRNG | MEDIUM |
| CWE-693 | Protection Mechanism Failure | MEDIUM |
| CWE-757 | Selection of Less-Secure Algorithm During Negotiation | HIGH |
| CWE-261 | Weak Encoding for Password | HIGH |