🔒 Implement comprehensive security and DDoS protection
### Security Features: - **Rate Limiting**: Redis-based IP tracking with configurable limits - General: 100 requests/minute (5min block) - Upload: 10 requests/5min (10min block) - Auth: 20 requests/15min (30min block) - **Request Validation**: Path length, header count, suspicious patterns - **Attack Detection**: Admin paths, script injections, bot patterns - **Enhanced JWT**: Format validation, length checks, character filtering - **IP Tracking**: X-Forwarded-For and X-Real-IP support ### Security Headers: - X-Content-Type-Options: nosniff - X-Frame-Options: DENY - X-XSS-Protection: 1; mode=block - Content-Security-Policy with strict rules - Strict-Transport-Security with includeSubDomains ### CORS Hardening: - Limited to specific domains: discours.io, new.discours.io - Restricted methods: GET, POST, OPTIONS only - Essential headers only ### Infrastructure: - Security middleware for all requests - Local cache + Redis for performance - Comprehensive logging and monitoring - Progressive blocking for repeat offenders ### Documentation: - Complete security guide (docs/security.md) - Configuration examples - Incident response procedures - Monitoring recommendations Version bump to 0.6.0 for major security enhancement.
This commit is contained in:
50
src/main.rs
50
src/main.rs
@@ -3,19 +3,21 @@ mod auth;
|
||||
mod handlers;
|
||||
mod lookup;
|
||||
mod s3_utils;
|
||||
mod security;
|
||||
mod thumbnail;
|
||||
|
||||
use actix_cors::Cors;
|
||||
use actix_web::{
|
||||
App, HttpServer,
|
||||
http::header::{self, HeaderName},
|
||||
middleware::Logger,
|
||||
http::header,
|
||||
middleware::{Logger, DefaultHeaders},
|
||||
web,
|
||||
};
|
||||
use app_state::AppState;
|
||||
use security::{SecurityConfig, security_middleware};
|
||||
|
||||
use handlers::universal_handler;
|
||||
use log::warn;
|
||||
use log::{warn, info};
|
||||
use std::env;
|
||||
use tokio::task::spawn_blocking;
|
||||
|
||||
@@ -37,27 +39,47 @@ async fn main() -> std::io::Result<()> {
|
||||
});
|
||||
});
|
||||
|
||||
// Конфигурация безопасности
|
||||
let security_config = SecurityConfig::default();
|
||||
info!("Security config: max_payload={} MB, upload_rate_limit={}/{}s",
|
||||
security_config.max_payload_size / (1024 * 1024),
|
||||
security_config.upload_rate_limit.max_requests,
|
||||
security_config.upload_rate_limit.window_seconds);
|
||||
|
||||
HttpServer::new(move || {
|
||||
// Настройка CORS middleware
|
||||
// Настройка CORS middleware - ограничиваем в продакшене
|
||||
let cors = Cors::default()
|
||||
.allow_any_origin() // TODO: ограничить конкретными доменами в продакшене
|
||||
.allowed_methods(vec!["GET", "POST", "PUT", "DELETE", "OPTIONS"])
|
||||
.allowed_origin("https://discours.io")
|
||||
.allowed_origin("https://new.discours.io")
|
||||
.allowed_origin("https://testing.discours.io")
|
||||
.allowed_origin("https://testing3.discours.io")
|
||||
.allowed_origin("http://localhost:3000") // для разработки
|
||||
.allowed_methods(vec!["GET", "POST", "OPTIONS"])
|
||||
.allowed_headers(vec![
|
||||
header::DNT,
|
||||
header::USER_AGENT,
|
||||
HeaderName::from_static("x-requested-with"),
|
||||
header::IF_MODIFIED_SINCE,
|
||||
header::CACHE_CONTROL,
|
||||
header::CONTENT_TYPE,
|
||||
header::RANGE,
|
||||
header::AUTHORIZATION,
|
||||
header::IF_NONE_MATCH,
|
||||
header::CACHE_CONTROL,
|
||||
])
|
||||
.expose_headers(vec![header::CONTENT_LENGTH, header::CONTENT_RANGE])
|
||||
.expose_headers(vec![header::CONTENT_LENGTH, header::ETAG])
|
||||
.supports_credentials()
|
||||
.max_age(1728000); // 20 дней
|
||||
.max_age(86400); // 1 день вместо 20
|
||||
|
||||
// Заголовки безопасности
|
||||
let security_headers = DefaultHeaders::new()
|
||||
.add(("X-Content-Type-Options", "nosniff"))
|
||||
.add(("X-Frame-Options", "DENY"))
|
||||
.add(("X-XSS-Protection", "1; mode=block"))
|
||||
.add(("Referrer-Policy", "strict-origin-when-cross-origin"))
|
||||
.add(("Content-Security-Policy", "default-src 'self'; img-src 'self' data: https:; object-src 'none';"))
|
||||
.add(("Strict-Transport-Security", "max-age=31536000; includeSubDomains"));
|
||||
|
||||
App::new()
|
||||
.app_data(web::Data::new(app_state.clone()))
|
||||
.app_data(web::PayloadConfig::new(security_config.max_payload_size))
|
||||
.app_data(web::JsonConfig::default().limit(1024 * 1024)) // 1MB для JSON
|
||||
.wrap(actix_web::middleware::from_fn(security_middleware))
|
||||
.wrap(security_headers)
|
||||
.wrap(cors)
|
||||
.wrap(Logger::default())
|
||||
.default_service(web::to(universal_handler))
|
||||
|
||||
Reference in New Issue
Block a user