diff --git a/app.py b/app.py index 6a541ed..0b08ebe 100644 --- a/app.py +++ b/app.py @@ -138,6 +138,14 @@ def is_allowed(self, identifier: str, max_requests: int, window_seconds: int) -> self._requests[identifier].append(now) return True + def remaining(self, identifier: str, max_requests: int, window_seconds: int) -> int: + with self._lock: + now = time.time() + window_start = now - window_seconds + while self._requests[identifier] and self._requests[identifier][0] < window_start: + self._requests[identifier].popleft() + return max_requests - len(self._requests[identifier]) + # Initialize global components metrics = ApplicationMetrics() rate_limiter = RateLimiter() @@ -158,17 +166,28 @@ def decorated_function(*args, **kwargs): client_ip = get_client_ip() if not rate_limiter.is_allowed( - client_ip, - app.config['RATE_LIMIT_MAX_REQUESTS'], + client_ip, + app.config['RATE_LIMIT_MAX_REQUESTS'], app.config['RATE_LIMIT_WINDOW'] ): logger.warning(f"Rate limit exceeded for IP: {client_ip}") - return jsonify({ + resp = jsonify({ 'error': 'Rate limit exceeded', 'message': f'Maximum {app.config["RATE_LIMIT_MAX_REQUESTS"]} requests per hour allowed' - }), 429 - - return f(*args, **kwargs) + }) + resp.status_code = 429 + resp.headers['Retry-After'] = str(app.config['RATE_LIMIT_WINDOW']) + return resp + + response = f(*args, **kwargs) + if hasattr(response, 'headers'): + remaining = rate_limiter.remaining( + client_ip, + app.config['RATE_LIMIT_MAX_REQUESTS'], + app.config['RATE_LIMIT_WINDOW'] + ) + response.headers['X-RateLimit-Remaining'] = str(remaining) + return response return decorated_function def security_headers(f): @@ -291,10 +310,13 @@ def too_large(e): def ratelimit_handler(e): """Handle rate limit exceeded""" metrics.record_error() - return jsonify({ + resp = jsonify({ 'error': 'Rate limit exceeded', 'message': 'Too many requests. Please try again later.' - }), 429 + }) + resp.status_code = 429 + resp.headers['Retry-After'] = str(app.config['RATE_LIMIT_WINDOW']) + return resp @app.errorhandler(500) def internal_error(e): diff --git a/scanner.py b/scanner.py index 45eb7fb..ea6c60d 100644 --- a/scanner.py +++ b/scanner.py @@ -231,6 +231,17 @@ def _initialize_advanced_patterns(self) -> Dict[str, List[Dict]]: 'cwe_id': 'CWE-295', 'recommendation': 'Always verify SSL certificates or use custom CA bundle if needed', 'category': 'crypto' + }, + { + 'pattern': r'requests\.(get|post|put|delete)\s*\([^)]*[\'\"]http://', + 'issue': 'Insecure HTTP Request', + 'severity': 'Medium', + 'description': 'HTTP used instead of HTTPS for network request', + 'confidence': 0.7, + 'owasp_category': 'A08:2021-Software and Data Integrity Failures', + 'cwe_id': 'CWE-319', + 'recommendation': 'Use HTTPS and verify certificates for all requests', + 'category': 'insecure_transport' } ], @@ -317,6 +328,17 @@ def _initialize_advanced_patterns(self) -> Dict[str, List[Dict]]: 'recommendation': 'Use crypto.getRandomValues() for cryptographic random numbers', 'category': 'crypto' }, + { + 'pattern': r'(fetch|axios\.get)\s*\([^)]*[\'\"]http://', + 'issue': 'Insecure HTTP Request', + 'severity': 'Medium', + 'description': 'HTTP used instead of HTTPS for network request', + 'confidence': 0.7, + 'owasp_category': 'A08:2021-Software and Data Integrity Failures', + 'cwe_id': 'CWE-319', + 'recommendation': 'Use HTTPS for all remote requests', + 'category': 'insecure_transport' + }, # URL Manipulation { @@ -355,6 +377,17 @@ def _initialize_advanced_patterns(self) -> Dict[str, List[Dict]]: 'cwe_id': 'CWE-20', 'recommendation': 'Use proper TypeScript types and input validation instead of any', 'category': 'type_safety' + }, + { + 'pattern': r'(fetch|axios\.get)\s*\([^)]*[\'\"]http://', + 'issue': 'Insecure HTTP Request', + 'severity': 'Medium', + 'description': 'HTTP used instead of HTTPS for network request', + 'confidence': 0.7, + 'owasp_category': 'A08:2021-Software and Data Integrity Failures', + 'cwe_id': 'CWE-319', + 'recommendation': 'Use HTTPS for all remote requests', + 'category': 'insecure_transport' } ], diff --git a/templates/index.html b/templates/index.html index 5c6d5c5..bf23524 100644 --- a/templates/index.html +++ b/templates/index.html @@ -1528,6 +1528,12 @@

Platform Metrics

{ pattern: /Math\.random\s*\(\)/gi, severity: 'Medium', description: 'Weak random number generation' }, { pattern: /rand\s*\(\)/gi, severity: 'Medium', description: 'Weak random number generation' } ], + + // Insecure Transport + insecureTransport: [ + { pattern: /(fetch|axios\.get)\s*\([^)]*['"]http:\/\//gi, severity: 'Medium', description: 'HTTP used instead of HTTPS for network request' }, + { pattern: /requests\.(get|post|put|delete)\s*\([^)]*['"]http:\/\//gi, severity: 'Medium', description: 'Python HTTP request without HTTPS' } + ], // Path Traversal pathTraversal: [ @@ -1919,7 +1925,8 @@

Platform Metrics

'Private key in source code': 'Private Key Exposure', 'Weak cryptographic hash MD5 usage': 'Weak Cryptography (MD5)', 'Path traversal pattern detected': 'Path Traversal Vulnerability', - 'Python pickle deserialization vulnerability': 'Insecure Deserialization' + 'Python pickle deserialization vulnerability': 'Insecure Deserialization', + 'HTTP used instead of HTTPS for network request': 'Insecure HTTP Request' }; return titles[description] || description; @@ -2246,6 +2253,12 @@

Platform Metrics

codeExample: 'import bcrypt\nhashed = bcrypt.hashpw(password.encode(), bcrypt.gensalt())', resources: ['https://owasp.org/www-project-cheat-sheets/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html'] }, + 'insecureTransport': { + description: 'Unencrypted HTTP traffic exposes sensitive data to interception.', + recommendation: 'Use HTTPS for all network requests and enforce TLS across your applications.', + codeExample: 'fetch("https://example.com/api")\nrequests.get("https://example.com")', + resources: ['https://owasp.org/www-project-top-ten/2017/A3_2017-Sensitive_Data_Exposure'] + }, 'pathTraversal': { description: 'Path traversal attacks allow access to files and directories outside the intended scope.', recommendation: 'Validate file paths, use absolute paths, implement proper access controls and sandboxing.', @@ -2524,6 +2537,7 @@

Platform Metrics

'commandInjection': 'Command Injection', 'credentials': 'Credential Exposure', 'crypto': 'Cryptographic Issues', + 'insecureTransport': 'Insecure Transport', 'pathTraversal': 'Path Traversal', 'deserialization': 'Insecure Deserialization', 'ssrf': 'Server-Side Request Forgery',