Skip to content

Commit

Permalink
Fix: 4xx and 5xx responses from API Gateway cause Invicti findings (#154
Browse files Browse the repository at this point in the history
)
  • Loading branch information
dsotirho-ucsc committed Aug 21, 2024
1 parent d769f27 commit c1bfd01
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 0 deletions.
21 changes: 21 additions & 0 deletions src/azul/terraform.py
Original file line number Diff line number Diff line change
Expand Up @@ -800,11 +800,32 @@ def tf_config(self, app_name):
# Setting this property using AWS API Gateway extensions to the OpenAPI
# specification works around this issue.
#
# We also use AWS API extensions to set the API Gateway default
# responses since, unlike Terraform, it automatically triggers the
# deployment of the REST API when the Gateway responses are added and/or
# modified.
#
rest_api = resources['aws_api_gateway_rest_api'][app_name]
assert 'minimum_compression_size' not in rest_api, rest_api
assert 'aws_api_gateway_gateway_response' not in resources, resources
openapi_spec = json.loads(locals[app_name])
key = 'x-amazon-apigateway-minimum-compression-size'
openapi_spec[key] = config.minimum_compression_size
openapi_spec['x-amazon-apigateway-gateway-responses'] = {
f'DEFAULT_{response_type}': {
'responseParameters': {
f'gatewayresponse.header.{k}': v
for k, v in [
('Content-Security-Policy', "'default-src \'self\''"),
('X-Content-Type-Options', "'nosniff'"),
('X-Frame-Options', "'DENY'"),
('Referrer-Policy', "'strict-origin-when-cross-origin'"),
('Strict-Transport-Security', "'max-age=63072000; includeSubDomains; preload'"),
('X-XSS-Protection', "'1; mode=block'")
]
}
} for response_type in ['4XX', '5XX']
}
locals[app_name] = json.dumps(openapi_spec)

return {
Expand Down
15 changes: 15 additions & 0 deletions test/integration_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2093,3 +2093,18 @@ def test_response_security_headers(self):
response.raise_for_status()
expected = expected_headers | global_headers
self.assertIsSubset(expected.items(), response.headers.items())

def test_default_4xx_response_headers(self):
headers = {
'Content-Security-Policy': "default-src 'self'",
'X-Content-Type-Options': 'nosniff',
'X-Frame-Options': 'DENY',
'Referrer-Policy': 'strict-origin-when-cross-origin',
'Strict-Transport-Security': 'max-age=63072000; includeSubDomains; preload',
'X-XSS-Protection': '1; mode=block'
}
for endpoint in (config.service_endpoint, config.indexer_endpoint):
with self.subTest(endpoint=endpoint):
response = requests.get(str(endpoint / 'does-not-exist'))
self.assertEqual(403, response.status_code)
self.assertIsSubset(headers.items(), response.headers.items())

0 comments on commit c1bfd01

Please sign in to comment.