| name | security-environment-standards |
| description | Security and environment configuration standards for web applications, including environment variable management, secure coding practices, and production deployment security. Use when setting up environments, configuring security, or deploying applications. |
Security Environment Standards
Core Security Principles
- Defense in depth: Multiple layers of security controls
- Principle of least privilege: Minimal access rights for users and systems
- Secure by default: Security features enabled by default
- Regular security updates: Keep dependencies and systems updated
- Environment isolation: Separate development, staging, and production environments
Environment Configuration
1. Environment Variables
DATABASE_URL=postgresql://user:password@localhost/dbname
DATABASE_SSL_MODE=require
SECRET_KEY=your-secret-key-here
AZURE_COSMOS_KEY=your-cosmos-db-key
OPENAI_API_KEY=your-openai-key
CLAUDE_API_KEY=your-claude-key
DEBUG=False
FLASK_ENV=production
ALLOWED_HOSTS=yourdomain.com,www.yourdomain.com
REDIS_URL=redis://localhost:6379
ELASTICSEARCH_URL=https://localhost:9200
CSRF_SECRET_KEY=csrf-secret-key
SESSION_COOKIE_SECURE=True
SESSION_COOKIE_HTTPONLY=True
2. Environment-Specific Configuration
import os
from dotenv import load_dotenv
load_dotenv()
class Config:
"""Base configuration."""
SECRET_KEY = os.environ.get('SECRET_KEY')
if not SECRET_KEY:
raise ValueError("SECRET_KEY environment variable is required")
DATABASE_URL = os.environ.get('DATABASE_URL')
REDIS_URL = os.environ.get('REDIS_URL')
SECURITY_HEADERS = {
'Strict-Transport-Security': 'max-age=31536000; includeSubDomains',
'X-Content-Type-Options': 'nosniff',
'X-Frame-Options': 'DENY',
'X-XSS-Protection': '1; mode=block',
'Referrer-Policy': 'strict-origin-when-cross-origin'
}
class DevelopmentConfig(Config):
"""Development configuration."""
DEBUG = True
TESTING = False
DATABASE_URL = os.environ.get('DEV_DATABASE_URL') or 'sqlite:///dev.db'
class ProductionConfig(Config):
"""Production configuration."""
DEBUG = False
TESTING = False
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SAMESITE =
PERMANENT_SESSION_LIFETIME =
SQLALCHEMY_ENGINE_OPTIONS = {
: ,
: ,
: ,
:
}
():
TESTING =
DATABASE_URL =
WTF_CSRF_ENABLED =
Security Implementation
1. Input Validation and Sanitization
from flask_wtf import FlaskForm
from wtforms import StringField, TextAreaField
from wtforms.validators import DataRequired, Length, ValidationError
import re
import bleach
class ChuukesesTranslationForm(FlaskForm):
"""Secure form for translation input."""
chuukese_text = TextAreaField(
'Chuukese Text',
validators=[
DataRequired(message="Chuukese text is required"),
Length(min=1, max=5000, message="Text must be between 1 and 5000 characters")
]
)
def validate_chuukese_text(self, field):
"""Custom validation for Chuukese text."""
allowed_pattern = r'^[a-zA-ZáéíóúāēīōūcfghjklmnprstwxCFGHJKLMNPRSTWX\s.,!?\-\'"\n\r]+$'
if not re.match(allowed_pattern, field.data):
raise ValidationError("Text contains invalid characters")
cleaned_text = bleach.clean(field.data, tags=[], strip=True)
if cleaned_text != field.data:
raise ValidationError("Text contains potentially unsafe content")
def sanitize_user_input(text):
"""Sanitize user input for safe storage and display."""
if text:
cleaned = bleach.clean(
text,
tags=[],
attributes={},
strip=
)
safe_pattern =
cleaned = .join(re.findall(safe_pattern, cleaned))
cleaned.strip()
2. Authentication and Authorization
from flask_login import UserMixin, login_required
from werkzeug.security import generate_password_hash, check_password_hash
import secrets
from datetime import datetime, timedelta
class User(UserMixin):
"""Secure user model."""
def __init__(self, username, email):
self.username = username
self.email = email
self.password_hash = None
self.is_active = True
self.created_at = datetime.utcnow()
self.last_login = None
self.failed_login_attempts = 0
self.account_locked_until = None
def set_password(self, password):
"""Set password with secure hashing."""
if len(password) < 8:
raise ValueError("Password must be at least 8 characters long")
if not re.search(r'[A-Z]', password):
raise ValueError("Password must contain at least one uppercase letter")
if not re.search(, password):
ValueError()
re.search(, password):
ValueError()
.password_hash = generate_password_hash(password, method=, salt_length=)
():
.is_account_locked():
is_correct = check_password_hash(.password_hash, password)
is_correct:
.failed_login_attempts =
.last_login = datetime.utcnow()
:
.failed_login_attempts +=
.failed_login_attempts >= :
.account_locked_until = datetime.utcnow() + timedelta(minutes=)
is_correct
():
.account_locked_until datetime.utcnow() < .account_locked_until:
():
():
():
role current_user.has_role(role):
abort()
f(*args, **kwargs)
decorated_function
decorator
3. Database Security
from sqlalchemy import text
from sqlalchemy.orm import validates
class SecureDatabaseOperations:
"""Secure database operation patterns."""
@staticmethod
def secure_query(session, query_template, parameters):
"""Execute parameterized queries to prevent SQL injection."""
try:
result = session.execute(text(query_template), parameters)
return result.fetchall()
except Exception as e:
logger.error(f"Database security error: {type(e).__name__}")
raise ValueError("Invalid query parameters")
@staticmethod
def validate_chuukese_word(word):
"""Validate Chuukese word before database insertion."""
if not word or len(word.strip()) == 0:
raise ValueError("Word cannot be empty")
if len(word) > 200:
raise ValueError("Word exceeds maximum length")
valid_pattern = r'^[a-zA-ZáéíóúāēīōūcfghjklmnprstwxCFGHJKLMNPRSTWX\-\']+$'
re.(valid_pattern, word.strip()):
ValueError()
word.strip()
():
__tablename__ =
= Column(Integer, primary_key=)
chuukese_word = Column(String(), nullable=)
english_definition = Column(Text, nullable=)
():
SecureDatabaseOperations.validate_chuukese_word(word)
():
definition (definition.strip()) == :
ValueError()
cleaned_definition = bleach.clean(definition, tags=[], strip=)
(cleaned_definition) > :
ValueError()
cleaned_definition
4. API Security
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
import jwt
from datetime import datetime, timedelta
limiter = Limiter(
app,
key_func=get_remote_address,
default_limits=["200 per day", "50 per hour"]
)
class APISecurityManager:
"""API security utilities."""
@staticmethod
def generate_api_token(user_id, expires_in=3600):
"""Generate secure API token."""
payload = {
'user_id': user_id,
'exp': datetime.utcnow() + timedelta(seconds=expires_in),
'iat': datetime.utcnow(),
'jti': secrets.token_urlsafe(32)
}
return jwt.encode(payload, current_app.config['SECRET_KEY'], algorithm='HS256')
@staticmethod
def verify_api_token(token):
"""Verify and decode API token."""
try:
payload = jwt.decode(
token,
current_app.config['SECRET_KEY'],
algorithms=['HS256'],
options={'verify_exp': True}
)
return payload
except jwt.ExpiredSignatureError:
raise ValueError("Token has expired")
jwt.InvalidTokenError:
ValueError()
():
auth_header = request.headers.get()
auth_header auth_header.startswith():
jsonify({: }),
:
token = auth_header.split()[]
payload = APISecurityManager.verify_api_token(token)
user_id = payload[]
ValueError e:
jsonify({: (e)}),
data = request.get_json()
data data:
jsonify({: }),
:
text = sanitize_user_input(data[])
(text) > :
jsonify({: }),
result = translate_text(text)
jsonify(result)
Exception e:
logger.error()
jsonify({: }),
Production Deployment Security
1. HTTPS and SSL/TLS
# nginx.conf - Force HTTPS
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name yourdomain.com www.yourdomain.com;
# SSL Configuration
ssl_certificate /path/to/certificate.crt;
ssl_certificate_key /path/to/private.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
# Security Headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';" always;
location / {
proxy_pass http://localhost:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
2. Docker Security
# Dockerfile with security best practices
FROM python:3.11-slim as base
# Create non-root user
RUN adduser --disabled-password --gecos '' --shell /bin/bash appuser
# Set working directory
WORKDIR /app
# Copy requirements and install dependencies as root
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy application code
COPY . .
# Change ownership to non-root user
RUN chown -R appuser:appuser /app
# Switch to non-root user
USER appuser
# Expose port
EXPOSE 5000
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
CMD curl -f http://localhost:5000/health || exit 1
# Run application
CMD ["python", "app.py"]
Security Monitoring
1. Logging Security Events
import logging
from flask import request
import json
security_logger = logging.getLogger('security')
security_handler = logging.FileHandler('security.log')
security_formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
security_handler.setFormatter(security_formatter)
security_logger.addHandler(security_handler)
security_logger.setLevel(logging.INFO)
def log_security_event(event_type, details, severity='INFO'):
"""Log security-related events."""
event_data = {
'event_type': event_type,
'timestamp': datetime.utcnow().isoformat(),
'ip_address': request.remote_addr,
'user_agent': request.user_agent.string,
'details': details
}
if severity == 'WARNING':
security_logger.warning(json.dumps(event_data))
elif severity == 'ERROR':
security_logger.error(json.dumps(event_data))
else:
security_logger.info(json.dumps(event_data))
@app.before_request
def log_requests():
"""Log suspicious request patterns."""
suspicious_patterns = [
'script>',
'javascript:',
'onload=',
'onerror=',
'../../../',
'passwd',
'etc/shadow'
]
request_data = str(request.get_data())
for pattern suspicious_patterns:
pattern request_data.lower():
log_security_event(
,
{: pattern, : request_data[:]},
)
2. Security Headers Implementation
from flask import Flask
from flask_talisman import Talisman
app = Flask(__name__)
Talisman(app, {
'strict_transport_security': True,
'strict_transport_security_max_age': 31536000,
'content_security_policy': {
'default-src': "'self'",
'script-src': ["'self'", "'unsafe-inline'"],
'style-src': ["'self'", "'unsafe-inline'"],
'img-src': ["'self'", "data:", "https:"],
'font-src': ["'self'", "https:"],
'connect-src': ["'self'"],
'frame-ancestors': "'none'"
},
'referrer_policy': 'strict-origin-when-cross-origin'
})
Best Practices
1. Environment Management
- Never commit secrets to version control
- Use separate environments for development, staging, and production
- Rotate API keys and secrets regularly
- Use environment-specific configuration files
2. Regular Security Updates
- Keep all dependencies updated
- Monitor security advisories for used packages
- Implement automated security scanning in CI/CD
- Regular security audits and penetration testing
3. Data Protection
- Encrypt sensitive data at rest
- Use HTTPS for all communications
- Implement proper session management
- Regular database backups with encryption
4. Access Control
- Implement principle of least privilege
- Use strong authentication mechanisms
- Regular access reviews and cleanup
- Proper error handling without information disclosure
Dependencies
flask-limiter: API rate limiting
flask-talisman: Security headers
python-jose: JWT token handling
bleach: HTML sanitization
cryptography: Encryption utilities
Validation Criteria
Security implementation should:
- ✅ Use HTTPS in production environments
- ✅ Implement proper input validation and sanitization
- ✅ Use parameterized queries for database operations
- ✅ Include comprehensive logging of security events
- ✅ Implement rate limiting on API endpoints
- ✅ Use secure session and cookie configuration
- ✅ Follow security headers best practices