Dns Rebinding in Fastapi with Dynamodb
Dns Rebinding in Fastapi with Dynamodb — how this specific combination creates or exposes the vulnerability
DNS rebinding is a client-side attack that abuses DNS and TTL behavior to make a browser believe a malicious domain resolves to a trusted internal IP. In a Fastapi application that accepts user-controlled identifiers and uses them to query Amazon DynamoDB, this can turn an apparently public endpoint into a pivot for unauthorized data access.
Consider a Fastapi endpoint that receives an account_id from the caller and uses it to build a DynamoDB key:
from fastapi import FastAPI, HTTPException
import boto3
app = FastAPI()
dynamodb = boto3.resource('dynamodb', region_name='us-east-1')
table = dynamodb.Table('Accounts')
If the application constructs the request like table.get_item(Key={'account_id': account_id}) without strict validation, an attacker can supply a hostname that initially resolves to a public IP (allowing the request to reach the service) and then rebinds to a private IP such as 127.0.0.1 or 169.254.169.254 (the EC2 metadata service). Because the check occurs server-side in Fastapi, the request appears legitimate; the malicious client controls resolution timing via short TTLs to switch IPs mid-flow.
In the context of DynamoDB, the impact is data exposure or unauthorized mutation. If the application inadvertently uses instance metadata credentials (common on EC2 without explicit credential configuration), rebinding to 169.254.169.254 can make the Fastapi service use the instance’s IAM role to issue DynamoDB operations. An attacker can craft requests that cause the server to fetch or modify items it should not, effectively bypassing intended tenant isolation. This becomes critical when combined with trusting user input for table names or secondary indexes, as malformed or rebinding-driven requests can probe for misconfigured resource policies or overly permissive IAM statements.
Because middleBrick tests unauthenticated attack surfaces, it can surface endpoints where input directly influences DynamoDB key construction without strict type and format checks. Findings often highlight missing validation on identifiers and overly broad IAM permissions that amplify rebinding risks. Remediation guidance emphasizes strict input validation and avoiding reliance on network-level perimeter controls alone.
Dynamodb-Specific Remediation in Fastapi — concrete code fixes
To mitigate DNS rebinding in Fastapi when working with DynamoDB, enforce strict validation on all identifiers, avoid dynamic table names derived from user input, and use defensive coding patterns that do not rely on IP-based trust.
1. Validate and constrain identifiers. Treat any user-supplied value as untrusted. Use length checks, regex patterns, and explicit allow-lists where possible:
import re
from fastapi import FastAPI, HTTPException
app = FastAPI()
ACCOUNT_PATTERN = re.compile(r'^[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}$')
def validate_account_id(account_id: str) -> None:
if not ACCOUNT_PATTERN.match(account_id):
raise HTTPException(status_code=400, detail='Invalid account_id')
# Usage in route
def get_account(account_id: str):
validate_account_id(account_id)
# proceed with DynamoDB call
2. Use fixed table names or a controlled mapping. Do not concatenate user input into table names. If multi-tenancy is required, map validated identifiers to pre-approved table names or use partition keys scoped by tenant:
TABLE_NAME = 'Accounts'
Always reference the constant instead of building names dynamically.
3. Apply resource-based scoping in DynamoDB requests. Even when data is in a shared table, enforce partition key constraints so that one account cannot read another’s items:
import boto3
from fastapi import Depends
dynamodb = boto3.resource('dynamodb', region_name='us-east-1')
table = dynamodb.Table('Accounts')
def get_account_data(account_id: str, tenant_id: str):
validate_account_id(account_id)
response = table.get_item(
Key={
'account_id': account_id,
'tenant_id': tenant_id
}
)
item = response.get('Item')
if not item or item.get('tenant_id') != tenant_id:
raise HTTPException(status_code=404, detail='Not found')
return item
4. Configure AWS credentials defensively. Avoid relying on instance metadata when the service is exposed externally. Provide explicit credentials with least privilege via environment variables or secure configuration, and use IAM policies that restrict actions to specific resources:
# Environment-based configuration example
AWS_ACCESS_KEY_ID=xxx
AWS_SECRET_ACCESS_KEY=yyy
AWS_SESSION_TOKEN=zzz
AWS_REGION=us-east-1
5. Add runtime checks and logging. Detect improbable IP behavior (e.g., local requests from external origins) and log suspicious patterns without exposing sensitive data in responses. Combine these measures with regular scans using tools like middleBrick to validate that remediation reduces the attack surface.
| Remediation focus | Why it matters for DNS rebinding | DynamoDB-specific guidance |
|---|---|---|
| Input validation | Prevents attacker-controlled resolution from bypassing checks | Use strict regex for IDs; avoid raw user input in keys |
| Least-privilege IAM | Limits what an attacker can do if they trigger requests via rebinding | Scope actions to specific table ARNs and partition keys |
| Explicit credentials | Reduces reliance on instance metadata reachable via rebinding | Provide credentials via secure injection, not default chain |