Man In The Middle in Django with Dynamodb
Man In The Middle in Django with Dynamodb — how this specific combination creates or exposes the vulnerability
A Man In The Middle (MitM) risk arises in a Django application using Dynamodb when communication between Django and the AWS endpoint is not strictly protected. If TLS is not enforced or certificate validation is bypassed, an attacker on the network path can intercept or alter requests and responses. This is especially relevant when AWS SDK clients are configured without explicit verification of server certificates or when using HTTP instead of HTTPS.
In a typical Django + Dynamodb setup, the application calls Dynamodb operations (such as GetItem or Query) using the AWS SDK. If the SDK is instantiated without disabling endpoint verification (e.g., verify=True) or if the endpoint URL is constructed with http://, credentials and data can be exposed. Django settings that leak AWS access keys or secret keys—such as storing them in settings files or environment variables without rotation—increase exposure. Additionally, if the application does not enforce HTTPS for any custom proxy or load balancer in front of Dynamodb, an attacker who can position themselves on the network may tamper with IAM-signed requests, leading to unauthorized data reads or writes.
Django middleware or custom HTTP clients that intercept requests for logging or transformation can inadvertently weaken TLS if they do not properly validate certificates. For example, using requests.Session() with verify=False when relaying to Dynamodb endpoints disables certificate checks and opens the channel to interception. Similarly, misconfigured AWS SDK clients that do not pin endpoints or use default AWS endpoints susceptible to SSRF can allow an attacker to redirect traffic to a malicious proxy. This combination—Django as the application layer, Dynamodb as the data store, and weak transport security—creates conditions where sensitive operations and credentials traverse an untrusted path, enabling credential theft, data manipulation, or replay attacks.
Dynamodb-Specific Remediation in Django — concrete code fixes
Remediation focuses on enforcing TLS, validating server certificates, and ensuring AWS SDK clients are configured securely within Django. Always use HTTPS endpoints and avoid disabling certificate verification. Use IAM policies and short-lived credentials rather than long-term keys, and rotate credentials regularly.
Below are concrete, secure code examples for a Django project using Dynamodb with the AWS SDK for Python (Boto3).
Secure Dynamodb client configuration
Initialize the Boto3 Dynamodb resource with explicit HTTPS and certificate verification. Do not set verify=False.
import boto3
from botocore.exceptions import ClientError
def get_dynamodb_resource():
# Use default AWS credential chain and HTTPS with strict TLS verification
return boto3.resource(
'dynamodb',
region_name='us-east-1',
endpoint_url='https://dynamodb.us-east-1.amazonaws.com',
# verify=True is default; never set verify=False
)
def get_item_secure(table_name, key):
dynamodb = get_dynamodb_resource()
table = dynamodb.Table(table_name)
try:
response = table.get_item(Key=key)
return response.get('Item')
except ClientError as e:
# Log securely without exposing secrets
raise RuntimeError(f'Dynamodb error: {e.response["Error"]["Code"]}') from e
Django settings and secure credential handling
Store AWS credentials using environment variables or a secrets manager, not in settings.py. Use django-environ or dj-database-url style patterns for safe injection.
# settings.py
import os
AWS_ACCESS_KEY_ID = os.environ.get('AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY')
AWS_SESSION_TOKEN = os.environ.get('AWS_SESSION_TOKEN') # if using temporary credentials
AWS_REGION = 'us-east-1'
AWS_ENDPOINT_URL = 'https://dynamodb.us-east-1.amazonaws.com'
Requests session with certificate pinning (optional advanced pattern)
If you use a custom proxy or HTTP client, enforce certificate pinning and avoid disabling verification.
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
session = requests.Session()
retry = Retry(total=3, backoff_factor=0.3)
adapter = HTTPAdapter(max_retries=retry)
session.mount('https://', adapter)
# Ensure verify points to a CA bundle; do not use verify=False
response = session.get('https://dynamodb.us-east-1.amazonaws.com', verify='/path/to/ca-bundle.crt')
Middleware and logging precautions
Avoid middleware that overrides HTTPS settings or logs raw authorization headers. Configure Django logging to redact sensitive fields.
# settings.py snippet for safe logging
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'filters': {
'require_debug_false': {
'()': 'django.utils.log.RequireDebugFalse',
},
},
'handlers': {
'console': {
'class': 'logging.StreamHandler',
},
},
'loggers': {
'django.request': {
'handlers': ['console'],
'level': 'ERROR',
'propagate': True,
'filters': ['require_debug_false'],
},
},
}