|
| 1 | +""" |
| 2 | +Security Configuration Module |
| 3 | +Centralized security settings and best practices for the SQLBot application |
| 4 | +""" |
| 5 | + |
| 6 | +from pydantic import BaseModel, Field |
| 7 | +from typing import Optional |
| 8 | + |
| 9 | + |
| 10 | +class SecurityConfig(BaseModel): |
| 11 | + """Security configuration settings""" |
| 12 | + |
| 13 | + # SSL/TLS Settings |
| 14 | + verify_ssl_certificates: bool = Field( |
| 15 | + default=True, |
| 16 | + description="Enable SSL certificate verification for external requests" |
| 17 | + ) |
| 18 | + |
| 19 | + ssl_cert_path: Optional[str] = Field( |
| 20 | + default=None, |
| 21 | + description="Path to custom CA bundle for SSL verification" |
| 22 | + ) |
| 23 | + |
| 24 | + # JWT Settings |
| 25 | + jwt_verify_signature: bool = Field( |
| 26 | + default=True, |
| 27 | + description="Enable JWT signature verification" |
| 28 | + ) |
| 29 | + |
| 30 | + jwt_verify_expiration: bool = Field( |
| 31 | + default=True, |
| 32 | + description="Enable JWT expiration verification" |
| 33 | + ) |
| 34 | + |
| 35 | + # Request Timeout Settings |
| 36 | + default_request_timeout: int = Field( |
| 37 | + default=30, |
| 38 | + description="Default timeout for HTTP requests in seconds" |
| 39 | + ) |
| 40 | + |
| 41 | + database_connection_timeout: int = Field( |
| 42 | + default=10, |
| 43 | + description="Default timeout for database connections in seconds" |
| 44 | + ) |
| 45 | + |
| 46 | + # Password Security |
| 47 | + min_password_length: int = Field( |
| 48 | + default=8, |
| 49 | + description="Minimum password length" |
| 50 | + ) |
| 51 | + |
| 52 | + require_password_uppercase: bool = Field( |
| 53 | + default=True, |
| 54 | + description="Require at least one uppercase letter in passwords" |
| 55 | + ) |
| 56 | + |
| 57 | + require_password_lowercase: bool = Field( |
| 58 | + default=True, |
| 59 | + description="Require at least one lowercase letter in passwords" |
| 60 | + ) |
| 61 | + |
| 62 | + require_password_digit: bool = Field( |
| 63 | + default=True, |
| 64 | + description="Require at least one digit in passwords" |
| 65 | + ) |
| 66 | + |
| 67 | + require_password_special: bool = Field( |
| 68 | + default=True, |
| 69 | + description="Require at least one special character in passwords" |
| 70 | + ) |
| 71 | + |
| 72 | + # Rate Limiting |
| 73 | + enable_rate_limiting: bool = Field( |
| 74 | + default=True, |
| 75 | + description="Enable rate limiting for API endpoints" |
| 76 | + ) |
| 77 | + |
| 78 | + rate_limit_per_minute: int = Field( |
| 79 | + default=60, |
| 80 | + description="Maximum requests per minute per user" |
| 81 | + ) |
| 82 | + |
| 83 | + # SQL Injection Prevention |
| 84 | + use_parameterized_queries: bool = Field( |
| 85 | + default=True, |
| 86 | + description="Always use parameterized queries to prevent SQL injection" |
| 87 | + ) |
| 88 | + |
| 89 | + # XSS Prevention |
| 90 | + sanitize_html_input: bool = Field( |
| 91 | + default=True, |
| 92 | + description="Sanitize HTML input to prevent XSS attacks" |
| 93 | + ) |
| 94 | + |
| 95 | + # CSRF Protection |
| 96 | + enable_csrf_protection: bool = Field( |
| 97 | + default=True, |
| 98 | + description="Enable CSRF protection for state-changing requests" |
| 99 | + ) |
| 100 | + |
| 101 | + # Logging and Monitoring |
| 102 | + log_security_events: bool = Field( |
| 103 | + default=True, |
| 104 | + description="Log security-related events" |
| 105 | + ) |
| 106 | + |
| 107 | + log_failed_auth_attempts: bool = Field( |
| 108 | + default=True, |
| 109 | + description="Log failed authentication attempts" |
| 110 | + ) |
| 111 | + |
| 112 | + max_failed_auth_attempts: int = Field( |
| 113 | + default=5, |
| 114 | + description="Maximum failed authentication attempts before account lockout" |
| 115 | + ) |
| 116 | + |
| 117 | + account_lockout_duration_minutes: int = Field( |
| 118 | + default=15, |
| 119 | + description="Duration of account lockout in minutes" |
| 120 | + ) |
| 121 | + |
| 122 | + |
| 123 | +# Default security configuration |
| 124 | +DEFAULT_SECURITY_CONFIG = SecurityConfig() |
| 125 | + |
| 126 | + |
| 127 | +def get_security_config() -> SecurityConfig: |
| 128 | + """Get the current security configuration""" |
| 129 | + return DEFAULT_SECURITY_CONFIG |
| 130 | + |
| 131 | + |
| 132 | +def validate_password_strength(password: str, config: SecurityConfig = DEFAULT_SECURITY_CONFIG) -> tuple[bool, str]: |
| 133 | + """ |
| 134 | + Validate password strength based on security configuration |
| 135 | + |
| 136 | + Args: |
| 137 | + password: The password to validate |
| 138 | + config: Security configuration to use |
| 139 | + |
| 140 | + Returns: |
| 141 | + Tuple of (is_valid, error_message) |
| 142 | + """ |
| 143 | + if len(password) < config.min_password_length: |
| 144 | + return False, f"Password must be at least {config.min_password_length} characters long" |
| 145 | + |
| 146 | + if config.require_password_uppercase and not any(c.isupper() for c in password): |
| 147 | + return False, "Password must contain at least one uppercase letter" |
| 148 | + |
| 149 | + if config.require_password_lowercase and not any(c.islower() for c in password): |
| 150 | + return False, "Password must contain at least one lowercase letter" |
| 151 | + |
| 152 | + if config.require_password_digit and not any(c.isdigit() for c in password): |
| 153 | + return False, "Password must contain at least one digit" |
| 154 | + |
| 155 | + if config.require_password_special: |
| 156 | + special_chars = "!@#$%^&*()_+-=[]{}|;:,.<>?" |
| 157 | + if not any(c in special_chars for c in password): |
| 158 | + return False, "Password must contain at least one special character" |
| 159 | + |
| 160 | + return True, "" |
0 commit comments