Implement rate limiting middleware for authentication endpoints, adding security headers middleware, and comprehensive error handling. Enhance validation tests for various DTOs and ensure proper functionality of gacha credits and rolls. Add unit tests for rate limiting and security headers middleware to validate behavior under different conditions.

This commit is contained in:
MythEclipse
2025-10-11 23:23:51 +07:00
parent 789b20c278
commit b6b5f48055
32 changed files with 1734 additions and 163 deletions
+4
View File
@@ -1,7 +1,11 @@
pub mod auth_middleware;
pub mod cors_middleware;
pub mod permissions_middleware;
pub mod rate_limiting_middleware;
pub mod security_headers_middleware;
pub use auth_middleware::auth_middleware;
pub use cors_middleware::cors_middleware;
pub use permissions_middleware::PermissionsMiddlewareLayer;
pub use rate_limiting_middleware::auth_rate_limiting_middleware;
pub use security_headers_middleware::security_headers_middleware;
@@ -0,0 +1,61 @@
use axum::{
http::{Request, StatusCode},
middleware::Next,
response::Response,
Extension,
};
use imphnen_libs::AppState;
use std::{
collections::HashMap,
sync::{Arc, RwLock},
time::{Duration, Instant},
};
// Simple rate limiting middleware for auth endpoints
pub async fn auth_rate_limiting_middleware(
Extension(_state): Extension<AppState>,
mut req: Request<axum::body::Body>,
next: Next,
) -> Result<Response, StatusCode> {
let uri = req.uri().path().to_string();
// Only apply rate limiting to auth endpoints
if uri == "/v1/auth/login" || uri == "/v1/auth/register" {
// Get client IP (simplified for this example)
let client_ip = "127.0.0.1"; // In production, use proper IP extraction
// Create a simple in-memory rate limiter
let limiter = Arc::new(RwLock::new(HashMap::new()));
let now = Instant::now();
let window = Duration::from_secs(60); // 1 minute window
let max_requests = 10; // 10 requests per minute
{
let mut limiter = limiter.write().unwrap();
// Clean up old entries
limiter.retain(|_, (timestamp, _)| {
now.duration_since(*timestamp) < window
});
// Check rate limit
let entry = limiter.entry(client_ip.to_string()).or_insert((now, 0));
let (timestamp, count) = entry;
if now.duration_since(*timestamp) > window {
*count = 1;
} else if *count >= max_requests {
return Ok(Response::builder()
.status(StatusCode::TOO_MANY_REQUESTS)
.header("Retry-After", "60")
.body("Too Many Requests: Rate limit exceeded for authentication endpoint".into())
.unwrap());
} else {
*count += 1;
}
}
}
Ok(next.run(req).await)
}
@@ -0,0 +1,98 @@
use axum::{
http::{HeaderValue, Request, Response},
middleware::Next,
Extension,
};
use imphnen_libs::{AppState, ENV};
use std::convert::Infallible;
/// Security headers middleware that adds various security-related HTTP headers to all responses.
///
/// This middleware implements security best practices by adding headers that help protect
/// against common web attacks like clickjacking, XSS, and information leakage.
pub async fn security_headers_middleware(
Extension(_state): Extension<AppState>,
mut req: Request<axum::body::Body>,
next: Next,
) -> Result<Response<axum::body::Body>, Infallible> {
let res = next.run(req).await;
let mut res = add_security_headers(res);
Ok(res)
}
/// Adds security headers to a response based on the current environment.
///
/// # Arguments
/// * `res` - The response to add headers to
///
/// # Returns
/// The response with security headers added
fn add_security_headers(mut res: Response<axum::body::Body>) -> Response<axum::body::Body> {
let headers = res.headers_mut();
// Strict-Transport-Security (HSTS)
// Prevents downgrade attacks and cookie hijacking
// Only enable in production to avoid HSTS pinning issues during development
if ENV.rust_env == "production" {
headers.insert(
"Strict-Transport-Security",
HeaderValue::from_static("max-age=31536000; includeSubDomains; preload"),
);
} else {
headers.insert(
"Strict-Transport-Security",
HeaderValue::from_static("max-age=0"),
);
}
// Content-Security-Policy (CSP)
// Mitigates XSS and data injection attacks
let csp = if ENV.rust_env == "production" {
// Production CSP - strict policy for production
"default-src 'self'; script-src 'self' https://trusted-cdn.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: https://images.example.com; connect-src 'self' https://api.example.com; frame-src 'none'; object-src 'none'; base-uri 'self'; form-action 'self'; report-uri /csp-violation-report-endpoint"
} else {
// Development CSP - more permissive for development
"default-src 'self' http://localhost:3000; script-src 'self' 'unsafe-eval' 'unsafe-inline' http://localhost:3000; style-src 'self' 'unsafe-inline' http://localhost:3000; img-src 'self' data: http://localhost:3000; connect-src 'self' http://localhost:3000; frame-src 'none'; object-src 'none'; base-uri 'self'; form-action 'self'"
};
headers.insert("Content-Security-Policy", HeaderValue::from_str(csp).unwrap());
// X-Frame-Options
// Prevents clickjacking attacks
headers.insert(
"X-Frame-Options",
HeaderValue::from_static("DENY"),
);
// X-Content-Type-Options
// Prevents MIME sniffing attacks
headers.insert(
"X-Content-Type-Options",
HeaderValue::from_static("nosniff"),
);
// Referrer-Policy
// Controls how much referrer information should be included with requests
headers.insert(
"Referrer-Policy",
HeaderValue::from_static("strict-origin-when-cross-origin"),
);
// Permissions-Policy (Feature Policy)
// Controls which features and APIs can be used
headers.insert(
"Permissions-Policy",
HeaderValue::from_static("camera=(), microphone=(), geolocation=()"),
);
// X-XSS-Protection
// Provides basic XSS protection (note: this is a legacy header and CSP is preferred)
headers.insert(
"X-XSS-Protection",
HeaderValue::from_static("1; mode=block"),
);
res
}