Source code for duck.http.middlewares.security.header
"""
Module for header middlewares.
"""
import re
from duck.http.middlewares import BaseMiddleware
from duck.http.middlewares.security.modules.header_injection import check_header_injection
from duck.http.response import HttpBadRequestResponse, HttpForbiddenRequestResponse
from duck.settings import SETTINGS
[docs]
class HostMiddleware(BaseMiddleware):
"""
Host Middleware class mitigating against requests from
unknown sources and other host header issues.
"""
allowed_hosts = SETTINGS["ALLOWED_HOSTS"]
debug_message: str = "Host Middleware: Host invalid/unrecognized"
[docs]
@classmethod
def get_error_response(cls, request) -> HttpBadRequestResponse:
"""
Return the error response upon errors.
"""
from duck.contrib.responses import make_response
host = request.get_header("host")
body = None
if SETTINGS["DEBUG"]:
body = f"<p>Host invalid/unrecognized</p>"
if hasattr(request, "host_error_msg"):
if request.host_error_msg:
body = f"<p>{request.host_error_msg}</p>"
# Generate response.
response = make_response(HttpForbiddenRequestResponse, body=body)
return response
[docs]
@classmethod
def process_request(cls, request):
"""
Process and incoming response.
"""
from duck.utils.net import is_valid_host
from duck.utils.wildcard import process_wildcards
host = request.get_header("host", "").strip()
valid, reason = is_valid_host(host)
if not valid:
request.host_error_msg = reason
cls.debug_message = "Host Middleware: Host invalid: %s"%(host)
return cls.request_bad
for allowed_host in cls.allowed_hosts:
if "]:" in host:
host = host.rsplit("]:", 1)[0]
else:
host = host.split(':', 1)[0] if host.count(':') == 1 else host
if process_wildcards(allowed_host, [host]):
# host is allowed
return cls.request_ok
# Add reference to errors and return final state
request.host_error_msg = f"Disallowed host, you may need to add {host} in ALLOWED_HOSTS"
cls.debug_message = "Host Middleware: Host invalid/unrecognized: %s"%(host)
return cls.request_bad
[docs]
class HeaderInjectionMiddleware(BaseMiddleware):
"""
HeaderInjectionMiddleware class mitigating against various
header injection attacks like `Potential Session Fixation` (Multiple Cookies),
`XSS` (Script Tag Detected), `Potential Open Redirect` (External URL),
`Potential Cache Poisoning` (Anti-Caching Headers).
"""
debug_message: str = "Header Injection Middleware: Potential header injection"
[docs]
@classmethod
def get_error_response(cls, request) -> HttpBadRequestResponse:
"""
Return necessary error response.
"""
from duck.contrib.responses import make_response
body = None
if SETTINGS["DEBUG"]:
# In debug, add attack type for debug purposes.
attack_type = getattr(request, "header_injection_attack_type", None)
if attack_type is not None:
body = f"<p>{attack_type.title()}</p>"
# Return the final response.
response = make_response(HttpBadRequestResponse, body=body)
return response
[docs]
@classmethod
def process_request(cls, request):
"""
Process an incoming request for potential header injection.
"""
headers = request.headers
# Check for header injection
result, attack_type = check_header_injection(headers)
if result:
# Potential header injection attack
# Set header injection type
request.header_injection_attack_type = attack_type
return cls.request_bad
return cls.request_ok