Dangling Dns in Flask with Basic Auth
Dangling Dns in Flask with Basic Auth — how this specific combination creates or exposes the vulnerability
A dangling DNS record occurs when a hostname (for example, legacy.api.example.com) points to an IP that no longer hosts the intended service, yet the DNS entry remains. In a Flask application that uses HTTP Basic Auth, this combination can expose internal or unintended endpoints if the application resolves the dangling name at runtime and uses the result for routing or authorization decisions.
Consider a Flask app that validates incoming requests by checking a hostname against a Basic Auth credential. If the app resolves a user-supplied host header or a configured backend hostname (e.g., via socket.gethostbyname or a reverse proxy that forwards to the dangling record), the request may be directed to an unexpected server. That server might have a relaxed security posture, different authentication handling, or even be controlled by an attacker who has registered the now-dangling IP. Because Basic Auth sends credentials in an easily decodable header, an attacker who can influence DNS resolution could redirect authentication traffic and potentially observe or manipulate credentials or session tokens.
In practice, this risk arises when:
- Flask uses a hardcoded or configuration-derived hostname that later becomes dangling, and the app does not validate or sanitize host inputs.
- Reverse proxies or load balancers forward requests based on a header like
Hostwithout strict hostname allowlists, enabling host header attacks that exploit the dangling record. - Service discovery or internal routing relies on DNS names that are not actively maintained, causing the app to route authenticated requests to unpredictable endpoints.
Because the scan checks for Authentication weaknesses and Input Validation issues in parallel, middleBrick will flag this as a finding under both categories. The scanner tests whether the application resolves hostnames dynamically and whether Basic Auth is applied consistently to all routes, highlighting cases where dangling DNS could lead to authorization bypass or credential exposure.
Basic Auth-Specific Remediation in Flask — concrete code fixes
To mitigate risks related to dangling DNS in Flask when using HTTP Basic Auth, focus on removing dynamic hostname resolution, enforcing strict host validation, and ensuring credentials are protected in transit. Below are concrete, safe patterns.
1. Avoid dynamic DNS lookups for authentication
Do not resolve hostnames at runtime to decide access control. Instead, use explicit IPs or stable, verified endpoints. If you must use host-based routing, validate against a strict allowlist.
2. Validate the Host header
Use a before-request hook to reject requests with unexpected hostnames. This prevents host header attacks that could exploit dangling records.
from flask import Flask, request, abort
app = Flask(__name__)
ALLOWED_HOSTS = {"api.example.com", "www.example.com"}
@app.before_request
def validate_host():
if request.host not in ALLOWED_HOSTS:
abort(400, "Host not allowed")
3. Use Basic Auth safely with explicit credentials
Check credentials directly without relying on external resolution. Use environment variables for secrets and enforce HTTPS to protect the credentials in transit.
from flask import Flask, request, abort
import os
app = Flask(__name__)
VALID_USERNAME = os.environ.get("API_USER")
VALID_PASSWORD = os.environ.get("API_PASS")
@app.route("/secure")
def secure():
auth = request.authorization
if not auth or auth.username != VALID_USERNAME or auth.password != VALID_PASSWORD:
return abort(401, "Authentication required")
return "OK"
4. Enforce HTTPS
Basic Auth transmits credentials in base64, which is easily reversible if intercepted. Always use TLS. In production, terminate TLS at a reverse proxy or load balancer and configure Flask to require secure cookies and HSTS where applicable.
# Example configuration for production-grade security
if __name__ == "__main__":
# Do not use this in production; use a WSGI server with TLS termination
app.run(ssl_context="adhoc") # adhoc仅用于测试,生产环境应使用有效证书
5. Use a production-grade auth mechanism
For new projects, prefer token-based authentication (e.g., OAuth 2.0, JWT) over Basic Auth. If you must keep Basic Auth, ensure credentials are stored server-side (e.g., hashed in a database) and never passed in URLs or logs.
# Example token validation instead of Basic Auth
from flask import request, abort
def require_token(token):
VALID_TOKENS = {os.environ.get("API_TOKEN")}
return token in VALID_TOKENS
@app.route("/token-secure")
def token_secure():
token = request.args.get("token")
if not require_token(token):
return abort(403, "Invalid token")
return "OK"
6. Scan and monitor with middleBrick
Use the middlebrick CLI to validate your authentication and input validation posture:
middlebrick scan https://api.example.com/secure
In CI/CD, add the GitHub Action to fail builds if the security score drops below your chosen threshold. For ongoing assurance, the Pro plan provides continuous monitoring and Slack/Teams alerts.