Missing Tls in Flask with Hmac Signatures
Missing Tls in Flask with Hmac Signatures — how this specific combination creates or exposes the vulnerability
Transport Layer Security (TLS) is the baseline network protection that ensures confidentiality and integrity between a client and a Flask service. When TLS is missing or misconfigured, all traffic traverses the network in plaintext. This is especially critical when the API uses Hmac Signatures for request authentication, because the security model depends on the assumption that the shared secret never traverses the network.
In a Flask API that relies on Hmac Signatures, the client typically computes a signature over selected request components (often the request body and a timestamp) using a shared secret, and sends the signature in a header (e.g., X-Signature). The server recomputes the signature using the same shared secret and compares it in constant time. If TLS is absent, an on-path attacker can observe the plaintext request, including headers and body, and the signature itself. Although the signature does not directly reveal the secret, the attacker can perform replay attacks or manipulate requests in transit. Without TLS, there is no channel binding to prevent tampering, so the integrity guarantees of the Hmac scheme are undermined at the transport layer.
The combination is particularly risky when the API accepts unauthenticated or weakly authenticated endpoints that still perform sensitive operations. For example, an endpoint that uses Hmac Signatures but does not enforce TLS might allow an attacker to capture a valid signed request and replay it, because there is no transport-level confidentiality or freshness binding. In regulated contexts, missing TLS can also cause failures in compliance mappings such as OWASP API Security Top 10 (2023) A02:2023 — Cryptographic Failures, and standards like PCI-DSS and SOC2 that require encryption in transit. middleBrick scans for such transport weaknesses as part of its Data Exposure and Encryption checks and maps findings to these frameworks, providing prioritized remediation guidance.
Hmac Signatures-Specific Remediation in Flask — concrete code fixes
Remediation centers on enforcing TLS and ensuring signature verification is robust. The primary fix is to deploy Flask behind a TLS-terminating proxy or use a production WSGI server configured for HTTPS. For local development, you can use tools like mkcert or Flask’s built-in support with a self-signed certificate to validate behavior, but production must use certificates from a trusted CA.
Below are concrete, working Flask examples that show Hmac Signature verification with an enforced requirement for TLS in production. These examples do not implement automatic fixing — they provide patterns to help you secure the endpoint and integrate scanning in your workflow using middleBrick’s CLI, GitHub Action, or MCP Server.
Example 1: Basic Hmac verification with timestamp replay protection
import time
import hmac
import hashlib
import json
from flask import Flask, request, abort, jsonify
app = Flask(__name__)
SHARED_SECRET = b'your-secure-secret-from-env' # Load from environment in production
MAX_AGE_SECONDS = 300 # 5 minutes
def verify_hmac_signature(request_body: bytes, timestamp: str, signature_header: str) -> bool:
"""Verify Hmac signature with replay protection based on timestamp age."""
try:
ts = int(timestamp)
except ValueError:
return False
if abs(time.time() - ts) > MAX_AGE_SECONDS:
return False
payload = f'{ts}'.encode() + b'.' + request_body
expected = hmac.new(SHARED_SECRET, payload, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature_header)
@app.route('/api/order', methods=['POST'])
def create_order():
request_body = request.get_data()
timestamp = request.headers.get('X-Timestamp')
signature = request.headers.get('X-Signature')
if not all([timestamp, signature]):
abort(400, description='Missing timestamp or signature')
if not verify_hmac_signature(request_body, timestamp, signature):
abort(401, description='Invalid signature')
payload = json.loads(request_body)
# Business logic here
return jsonify({'status': 'ok', 'order_id': 123}), 200
Example 2: Enforce HTTPS in production via a before_request guard
import os
from flask import Flask, request, abort
app = Flask(__name__)
@app.before_request
def enforce_https():
"""Reject non-TLS requests in production."""
env = os.getenv('FLASK_ENV', 'production')
if env == 'production' and not request.is_secure:
abort(403, description='TLS required')
@app.route('/api/data', methods=['GET'])
def get_data():
return {'data': 'safe over TLS'}, 200
In practice, you should store SHARED_SECRET in environment variables or a secrets manager, and rotate keys periodically. Use strict header parsing and constant-time comparisons to avoid timing attacks. middleBrick’s CLI can be run as middlebrick scan <url> to validate that your endpoints require TLS and that signature verification logic is exercised during scans. For automated checks, add the GitHub Action to fail builds if the risk score drops below your threshold, or use the MCP Server to scan APIs directly from your IDE while developing these routes.
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 |