diff --git a/api/app_factory.py b/api/app_factory.py index c3920487..e26509a8 100644 --- a/api/app_factory.py +++ b/api/app_factory.py @@ -43,6 +43,14 @@ async def dispatch(self, request: Request, call_next): return JSONResponse(status_code=403, content={"detail": "Forbidden"}) response = await call_next(request) + + # Add HSTS header to prevent man-in-the-middle attacks + # max-age=31536000: 1 year in seconds + # includeSubDomains: apply to all subdomains + # preload: eligible for browser HSTS preload lists + hsts_value = "max-age=31536000; includeSubDomains; preload" + response.headers["Strict-Transport-Security"] = hsts_value + return response diff --git a/tests/test_hsts_header.py b/tests/test_hsts_header.py new file mode 100644 index 00000000..51a5d0f0 --- /dev/null +++ b/tests/test_hsts_header.py @@ -0,0 +1,43 @@ +""" +Test for HSTS header presence in responses. +""" +import pytest +from fastapi.testclient import TestClient +from api.index import app + + +class TestHSTSHeader: + """Test HSTS security header.""" + + @pytest.fixture + def client(self): + """Create a test client.""" + return TestClient(app) + + def test_hsts_header_present(self, client): + """Test that the HSTS header is present in responses.""" + # Make a request to the root endpoint + response = client.get("/") + + # Verify HSTS header is present + assert "strict-transport-security" in response.headers + + # Verify header value contains required directives + hsts_header = response.headers["strict-transport-security"] + assert "max-age=31536000" in hsts_header + assert "includeSubDomains" in hsts_header + assert "preload" in hsts_header + + def test_hsts_header_on_api_endpoints(self, client): + """Test that the HSTS header is present on API endpoints.""" + # Test on graphs endpoint + response = client.get("/graphs") + + # Verify HSTS header is present + assert "strict-transport-security" in response.headers + + # Verify header value contains required directives + hsts_header = response.headers["strict-transport-security"] + assert "max-age=31536000" in hsts_header + assert "includeSubDomains" in hsts_header + assert "preload" in hsts_header