Python Requests Session with HTTP Vulnerability

Medium Risk Insecure Transport
PythonRequestsHTTPInsecure TransportSessionEncryptionData Security

What it is

Application uses requests.Session() to make HTTP (unencrypted) connections, exposing sensitive data to eavesdropping, man-in-the-middle attacks, and data interception.

import requests class APIClient: def __init__(self): self.session = requests.Session() # Vulnerable: No security configuration def fetch_user_data(self, user_id): # Vulnerable: HTTP request with session url = f'http://api.service.com/users/{user_id}' response = self.session.get(url) return response.json() def authenticate(self, username, password): # Very dangerous: Credentials over HTTP auth_data = {'username': username, 'password': password} response = self.session.post( 'http://auth.service.com/login', json=auth_data ) return response.json() @app.route('/api_proxy/') def api_proxy(endpoint): # Vulnerable: Dynamic HTTP requests session = requests.Session() base_url = 'http://internal-api.local' # No validation of transport security response = session.get(f'{base_url}/{endpoint}') return response.text # Vulnerable: Session with HTTP endpoints def bulk_api_calls(endpoints): session = requests.Session() results = [] for endpoint in endpoints: # Dangerous: Multiple HTTP calls url = f'http://api.example.com/{endpoint}' response = session.get(url) results.append(response.json()) return results
import requests from urllib.parse import urlparse import ssl class SecureAPIClient: def __init__(self, base_url=None): self.session = self._create_secure_session() self.base_url = self._validate_base_url(base_url) def _create_secure_session(self): """Create a session with security configurations.""" session = requests.Session() # Enforce SSL/TLS verification session.verify = True # Set secure headers session.headers.update({ 'User-Agent': 'SecureClient/1.0', 'Accept': 'application/json', 'X-Requested-With': 'SecureAPIClient' }) # Mount adapter that blocks HTTP session.mount('http://', HTTPSOnlyAdapter()) return session def _validate_base_url(self, url): """Validate that base URL uses HTTPS.""" if not url: return 'https://api.service.com' # Default secure URL parsed = urlparse(url) if parsed.scheme != 'https': raise ValueError('Only HTTPS base URLs are allowed') return url def fetch_user_data(self, user_id): """Securely fetch user data.""" if not isinstance(user_id, (int, str)) or not str(user_id).isalnum(): raise ValueError('Invalid user ID format') url = f'{self.base_url}/users/{user_id}' try: response = self.session.get( url, timeout=10, verify=True ) response.raise_for_status() return response.json() except requests.exceptions.RequestException as e: raise RuntimeError(f'Failed to fetch user data: {str(e)}') def authenticate(self, username, password): """Securely authenticate user.""" # Validate input if not username or not password: raise ValueError('Username and password required') # Use secure authentication endpoint auth_url = f'{self.base_url}/auth/login' auth_data = { 'username': str(username)[:50], # Limit length 'password': str(password)[:100] } try: response = self.session.post( auth_url, json=auth_data, timeout=15, verify=True ) response.raise_for_status() return response.json() except requests.exceptions.RequestException as e: raise RuntimeError(f'Authentication failed: {str(e)}') class HTTPSOnlyAdapter(requests.adapters.HTTPAdapter): """Adapter that blocks HTTP connections.""" def send(self, request, **kwargs): if request.url.startswith('http://'): raise requests.exceptions.InvalidURL( 'HTTP connections are not allowed. Use HTTPS instead.' ) return super().send(request, **kwargs) @app.route('/api_proxy/') def api_proxy(endpoint): """Secure API proxy with validation.""" # Validate endpoint parameter if not endpoint or '..' in endpoint or endpoint.startswith('/'): return {'error': 'Invalid endpoint'}, 400 # Allowlist of permitted endpoints allowed_endpoints = ['users', 'products', 'orders', 'status'] base_endpoint = endpoint.split('/')[0] if base_endpoint not in allowed_endpoints: return {'error': 'Endpoint not allowed'}, 403 try: client = SecureAPIClient('https://internal-api.secure.local') # Make secure request url = f'{client.base_url}/{endpoint}' response = client.session.get( url, timeout=10, verify=True ) response.raise_for_status() return response.json() except (ValueError, RuntimeError) as e: return {'error': str(e)}, 400 except requests.exceptions.RequestException as e: return {'error': f'Request failed: {str(e)}'}, 500 def secure_bulk_api_calls(endpoints, base_url='https://api.example.com'): """Perform bulk API calls securely.""" # Validate base URL parsed = urlparse(base_url) if parsed.scheme != 'https': raise ValueError('Only HTTPS base URLs allowed') # Limit number of endpoints to prevent abuse if len(endpoints) > 10: raise ValueError('Too many endpoints requested') client = SecureAPIClient(base_url) results = [] for endpoint in endpoints: # Validate each endpoint if not isinstance(endpoint, str) or '..' in endpoint: results.append({'error': f'Invalid endpoint: {endpoint}'}) continue try: url = f'{base_url}/{endpoint}' response = client.session.get( url, timeout=5, verify=True ) response.raise_for_status() results.append(response.json()) except requests.exceptions.RequestException as e: results.append({'error': f'Request failed for {endpoint}: {str(e)}'}) return results # Additional security: Connection pool configuration def create_enterprise_session(): """Create session with enterprise security settings.""" session = requests.Session() # SSL/TLS configuration session.verify = True # Connection pool settings adapter = requests.adapters.HTTPAdapter( pool_connections=10, pool_maxsize=20, max_retries=3 ) # Mount only for HTTPS session.mount('https://', adapter) # Block HTTP entirely session.mount('http://', HTTPSOnlyAdapter()) return session

💡 Why This Fix Works

See fix suggestions for detailed explanation.

Why it happens

Code initializes sessions for HTTP: session = requests.Session(); response = session.get('http://api.example.com'). HTTP protocol transmits unencrypted data. Credentials, API keys, sensitive information exposed. Network attackers intercept traffic. Session objects maintain state across insecure HTTP connections.

Root causes

Creating requests.Session() with HTTP URLs

Code initializes sessions for HTTP: session = requests.Session(); response = session.get('http://api.example.com'). HTTP protocol transmits unencrypted data. Credentials, API keys, sensitive information exposed. Network attackers intercept traffic. Session objects maintain state across insecure HTTP connections.

Not Validating URL Protocols in Session Requests

Session methods called without protocol checks: session.post(endpoint, data=payload). Endpoint URLs from configuration, databases, or user input may be HTTP. No validation ensuring HTTPS. Applications trust external URL sources without verification. Missing protocol validation enables insecure transport.

Using Session Retry Logic with HTTP Fallback

Retry mechanisms falling back to HTTP: try: session.get('https://api.com'); except: session.get('http://api.com'). HTTPS failures silently downgrade to HTTP. Network issues or certificate problems trigger insecure fallback. Fallback logic compromises security for availability.

Session Cookies Sent Over HTTP Connections

Session state includes cookies without Secure flag: session.cookies.set('token', value). Cookies sent to HTTP and HTTPS. Authentication tokens transmitted unencrypted. Session fixation or hijacking through cookie interception. HTTP connections expose session cookies to network eavesdropping.

Using HTTP for Internal or Development API Calls in Production

Internal services accessed via HTTP: session.get('http://internal-api'). Assumption of network security. Internal networks not inherently secure. Lateral movement after initial compromise. Development patterns using HTTP deployed to production. Internal APIs should use HTTPS like external services.

Fixes

1

Always Use HTTPS for All Session Requests

Use HTTPS exclusively: session = requests.Session(); session.get('https://api.example.com'). Never use http:// URLs. For all external and internal APIs, enforce HTTPS. Session should only make secure requests. HTTPS provides encryption and authentication for all session communications.

2

Validate URL Schemes Before Every Session Request

Check HTTPS before requests: from urllib.parse import urlparse; if urlparse(url).scheme != 'https': raise ValueError('HTTPS required'). Validate URLs from all sources. Reject HTTP schemes. Apply to all session methods: get, post, put, delete. Protocol validation prevents insecure connections.

3

Never Implement HTTP Fallback Logic

Fail on HTTPS errors rather than downgrade: try: session.get(https_url, timeout=10); except RequestException as e: logger.error(e); raise. No fallback to HTTP. Investigate and fix certificate or connectivity issues. Availability through insecurity unacceptable. HTTPS failures require proper resolution, not HTTP bypass.

4

Set Secure and HttpOnly Flags on All Session Cookies

Configure secure cookies: session.cookies.set('token', value, secure=True, httponly=True). Secure flag prevents transmission over HTTP. HttpOnly prevents JavaScript access. For session management, use secure cookie configuration. Combined with HTTPS, protects session tokens from interception.

5

Use HTTPS for Internal Services and APIs

Internal services with HTTPS: session.get('https://internal-api.local'). Use internal CA for certificates. mTLS for service-to-service authentication. Zero-trust networking assumes no inherent network security. Internal HTTPS prevents lateral movement and eavesdropping within network perimeter.

6

Implement Certificate Pinning for Critical APIs

Pin certificates for sensitive services: session.get(url, verify='/path/to/cert.pem'). Use public key pinning with requests-toolbelt. Prevents man-in-the-middle with compromised CAs. Critical for authentication, payment, or sensitive data APIs. Pinning adds defense-in-depth to HTTPS.

Detect This Vulnerability in Your Code

Sourcery automatically identifies python requests session with http vulnerability and many other security issues in your codebase.