/health divulguait le message brut du pilote
L'endpoint n'est pas authentifie et renvoyait f'error: {str(e)}'. Les
exceptions psycopg contiennent regulierement l'hote, le port, le nom de
la base et l'utilisateur. Le detail part desormais dans les journaux,
la reponse ne porte plus qu'un statut.
Filtre nl2br non echappant
Markup('<br>'.join(...)) marquait le texte comme sur sans l'echapper.
Le filtre n'etant utilise dans aucun gabarit, la faille etait latente :
elle se serait ouverte au premier usage. Corrige en Markup('<br>').join(),
qui echappe chaque segment. Verifie : nl2br('<script>alert(1)</script>')
rend desormais <script>alert(1)</script>.
Filtre de redaction des secrets sans effet
SensitiveDataFilter n'inspectait que record.msg. Or le code journalise
en style parametre ('...: %s', valeur) : record.msg ne contient que la
chaine de format, et la donnee sensible vit dans record.args, ignore.
La redaction ne s'appliquait donc pratiquement jamais. Le record est
desormais rendu avant filtrage, puis args vide.
Sortie console conditionnee a FLASK_DEBUG
En production, l'application n'ecrivait rien sur stdout, precisement ou
regarde la console Pterodactyl. Le handler devient inconditionnel, seul
son niveau varie.
Journaux du bot Discord perdus
discord_bot.py utilise getLogger(__name__), soit 'app.discord_bot'.
Aucun handler n'etait attache a la hierarchie 'app' : les INFO etaient
jetes et les WARNING+ tombaient sur le handler de dernier recours, sans
format. Les handlers sont desormais rattaches au logger de paquet.
X-XSS-Protection retire (app.py et nginx.conf)
En-tete deprecie, l'auditeur vise a ete supprime des navigateurs
courants et ses dernieres implementations introduisaient elles-memes
des vulnerabilites.
Co-Authored-By: Claude Opus 5 <[email protected]>
168 lines
6.4 KiB
Nginx Configuration File
168 lines
6.4 KiB
Nginx Configuration File
# Team Tryouts - Production Nginx Configuration (Windows)
|
|
#
|
|
# This configuration provides:
|
|
# - HTTP to HTTPS redirect
|
|
# - TLS 1.2/1.3 with strong ciphers
|
|
# - HSTS enforcement
|
|
# - Request size limits
|
|
# - gzip compression
|
|
# - Proxy to Waitress (Flask)
|
|
# - Security headers (reinforced at reverse proxy level)
|
|
|
|
worker_processes auto;
|
|
|
|
events {
|
|
worker_connections 1024;
|
|
multi_accept on;
|
|
}
|
|
|
|
http {
|
|
# =========================================================================
|
|
# Basic Settings
|
|
# =========================================================================
|
|
server_tokens off; # Hide Nginx version
|
|
sendfile on;
|
|
tcp_nopush on;
|
|
tcp_nodelay on;
|
|
keepalive_timeout 65;
|
|
types_hash_max_size 2048;
|
|
client_max_body_size 16M; # Max upload size (matches Flask MAX_CONTENT_LENGTH)
|
|
client_body_buffer_size 128k;
|
|
client_header_buffer_size 1k;
|
|
large_client_header_buffers 4 8k;
|
|
|
|
include mime.types;
|
|
default_type application/octet-stream;
|
|
|
|
# =========================================================================
|
|
# Logging
|
|
# =========================================================================
|
|
access_log logs/access.log;
|
|
error_log logs/error.log warn;
|
|
|
|
# =========================================================================
|
|
# Gzip Compression
|
|
# =========================================================================
|
|
gzip on;
|
|
gzip_vary on;
|
|
gzip_proxied any;
|
|
gzip_comp_level 6;
|
|
gzip_min_length 256;
|
|
gzip_types
|
|
text/plain
|
|
text/css
|
|
text/xml
|
|
text/javascript
|
|
application/javascript
|
|
application/json
|
|
application/xml
|
|
application/rss+xml
|
|
image/svg+xml
|
|
font/ttf
|
|
font/otf;
|
|
|
|
# =========================================================================
|
|
# HTTP → HTTPS Redirect
|
|
# =========================================================================
|
|
server {
|
|
listen 80;
|
|
server_name _;
|
|
|
|
# Redirect all HTTP traffic to HTTPS
|
|
return 301 https://$host$request_uri;
|
|
}
|
|
|
|
# =========================================================================
|
|
# HTTPS Server
|
|
# =========================================================================
|
|
server {
|
|
listen 443 ssl http2;
|
|
server_name _;
|
|
|
|
# ---------------------------------------------------------------------
|
|
# SSL/TLS Configuration
|
|
# ---------------------------------------------------------------------
|
|
# Paths to SSL certificate and key (update these for your deployment)
|
|
ssl_certificate C:/nginx/certs/fullchain.pem;
|
|
ssl_certificate_key C:/nginx/certs/privkey.pem;
|
|
|
|
# Strong TLS configuration
|
|
ssl_protocols TLSv1.2 TLSv1.3;
|
|
ssl_prefer_server_ciphers on;
|
|
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
|
|
|
|
# SSL session settings
|
|
ssl_session_cache shared:SSL:10m;
|
|
ssl_session_timeout 10m;
|
|
ssl_session_tickets off;
|
|
|
|
# OCSP Stapling (uncomment when running on a proper domain)
|
|
# ssl_stapling on;
|
|
# ssl_stapling_verify on;
|
|
# ssl_trusted_certificate C:/nginx/certs/chain.pem;
|
|
|
|
# Diffie-Hellman parameters (generate with: openssl dhparam -out dhparam.pem 2048)
|
|
# ssl_dhparam C:/nginx/certs/dhparam.pem;
|
|
|
|
# ---------------------------------------------------------------------
|
|
# Security Headers (defense-in-depth with Flask's own headers)
|
|
# ---------------------------------------------------------------------
|
|
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
|
|
add_header X-Content-Type-Options "nosniff" always;
|
|
add_header X-Frame-Options "DENY" always;
|
|
# X-XSS-Protection intentionally omitted: deprecated, removed from
|
|
# current browsers, and harmful in its last implementations.
|
|
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
|
add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), interest-cohort=()" always;
|
|
add_header Cross-Origin-Opener-Policy "same-origin" always;
|
|
|
|
# ---------------------------------------------------------------------
|
|
# Proxy to Waitress (Flask)
|
|
# ---------------------------------------------------------------------
|
|
location / {
|
|
proxy_pass http://127.0.0.1:5000;
|
|
|
|
# Proxy headers
|
|
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;
|
|
proxy_set_header X-Forwarded-Host $host;
|
|
proxy_set_header X-Forwarded-Port $server_port;
|
|
|
|
# Timeouts
|
|
proxy_connect_timeout 30s;
|
|
proxy_send_timeout 30s;
|
|
proxy_read_timeout 30s;
|
|
|
|
# Buffer settings
|
|
proxy_buffering on;
|
|
proxy_buffer_size 4k;
|
|
proxy_buffers 8 4k;
|
|
proxy_busy_buffers_size 8k;
|
|
}
|
|
|
|
# ---------------------------------------------------------------------
|
|
# Static Files (served directly by Nginx for performance)
|
|
# Uncomment and adjust path if you want Nginx to serve static files
|
|
# ---------------------------------------------------------------------
|
|
# location /static/ {
|
|
# alias C:/path/to/team-tryouts/static/;
|
|
# expires 30d;
|
|
# add_header Cache-Control "public, immutable";
|
|
# access_log off;
|
|
# }
|
|
|
|
# ---------------------------------------------------------------------
|
|
# Rate Limiting
|
|
# ---------------------------------------------------------------------
|
|
# Define rate limit zones (uncomment when rate limiting at Nginx level)
|
|
# limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
|
|
# limit_req_zone $binary_remote_addr zone=global:10m rate=100r/m;
|
|
|
|
# location /auth/login {
|
|
# limit_req zone=login burst=5 nodelay;
|
|
# proxy_pass http://127.0.0.1:5000;
|
|
# }
|
|
}
|
|
} |