Security Middleware
Comprehensive security middleware for Armature - inspired by Helmet for Express.js.
Table of Contents
- Overview
- Features
- Installation
- Quick Start
- Configuration
- Security Headers
- Best Practices
- API Reference
Overview
The Armature Security middleware provides a collection of security headers and protections that help secure your web applications against common vulnerabilities. It's inspired by Helmet for Express.js and provides similar functionality for Rust/Armature applications.
Features
โ Content Security Policy (CSP) - Prevent XSS attacks โ HTTP Strict Transport Security (HSTS) - Force HTTPS โ X-Frame-Options - Prevent clickjacking โ X-Content-Type-Options - Prevent MIME sniffing โ X-XSS-Protection - Enable browser XSS filters โ Referrer Policy - Control referrer information โ DNS Prefetch Control - Control DNS prefetching โ Expect-CT - Certificate Transparency โ X-Download-Options - Prevent IE download execution โ X-Permitted-Cross-Domain-Policies - Control Flash/PDF policies โ Hide X-Powered-By - Remove server fingerprinting
Installation
Add to your Cargo.toml:
[dependencies]
armature-framework = { version = "0.1", features = ["security"] }
Quick Start
Adding to Middleware Chain (Recommended)
The preferred way to use security middleware is to add it to your application's middleware chain:
use armature_framework::prelude::*;
use armature_framework::{MiddlewareChain, SecurityHeadersMiddleware};
use armature_security::SecurityMiddleware;
// Create your middleware chain
let mut middleware_chain = MiddlewareChain::new();
// Add security middleware (recommended to be early in the chain)
middleware_chain.use_middleware(SecurityMiddleware::default());
// Add other middleware
middleware_chain.use_middleware(SecurityHeadersMiddleware::new());
// Define your module
#[module(
providers: [MyService],
controllers: [MyController]
)]
#[derive(Default)]
struct AppModule;
Full Application Example
use armature_framework::prelude::*;
use armature_framework::{MiddlewareChain, LoggerMiddleware, CorsMiddleware};
use armature_security::{
SecurityMiddleware,
content_security_policy::CspConfig,
hsts::HstsConfig,
frame_guard::FrameGuard,
};
#[injectable]
#[derive(Clone, Default)]
struct ApiService;
#[controller("/api")]
#[derive(Default, Clone)]
struct ApiController;
impl ApiController {
#[get("/data")]
async fn get_data() -> Result<Json<serde_json::Value>, Error> {
Ok(Json(serde_json::json!({ "status": "ok" })))
}
}
#[module(
providers: [ApiService],
controllers: [ApiController]
)]
#[derive(Default)]
struct AppModule;
#[tokio::main]
async fn main() {
// Build middleware chain with security
let mut middleware_chain = MiddlewareChain::new();
// 1. Logging (first to capture all requests)
middleware_chain.use_middleware(LoggerMiddleware::new());
// 2. CORS (handle preflight early)
middleware_chain.use_middleware(
CorsMiddleware::new()
.allow_origin("https://example.com")
.allow_credentials(true)
);
// 3. Security headers (apply to all responses)
middleware_chain.use_middleware(
SecurityMiddleware::new()
.with_hsts(HstsConfig::new(31536000).include_subdomains(true))
.with_frame_guard(FrameGuard::Deny)
.with_csp(CspConfig::new().default_src(vec!["'self'".to_string()]))
.hide_powered_by(true)
);
println!("Server running with security middleware enabled");
}
Custom Configuration
use armature_security::{
SecurityMiddleware,
content_security_policy::CspConfig,
hsts::HstsConfig,
frame_guard::FrameGuard,
referrer_policy::ReferrerPolicy,
};
let security = SecurityMiddleware::new()
.with_csp(CspConfig::default())
.with_hsts(HstsConfig::new(31536000)) // 1 year
.with_frame_guard(FrameGuard::Deny)
.with_referrer_policy(ReferrerPolicy::NoReferrer)
.hide_powered_by(true);
// Add to middleware chain
middleware_chain.use_middleware(security);
Configuration
Enable All Features (Recommended)
// All security features with 1-year HSTS
let security = SecurityMiddleware::enable_all(31536000);
Start from Scratch
// No protections - configure manually
let security = SecurityMiddleware::new()
.with_frame_guard(FrameGuard::SameOrigin)
.hide_powered_by(true);
Security Headers
Content Security Policy (CSP)
Prevents XSS attacks by declaring which dynamic resources are allowed to load.
use armature_security::content_security_policy::CspConfig;
let csp = CspConfig::new()
.default_src(vec!["'self'".to_string()])
.script_src(vec![
"'self'".to_string(),
"https://cdn.example.com".to_string()
])
.style_src(vec![
"'self'".to_string(),
"'unsafe-inline'".to_string()
])
.img_src(vec![
"'self'".to_string(),
"data:".to_string(),
"https:".to_string()
]);
let security = SecurityMiddleware::new().with_csp(csp);
Output Header:
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; ...
HTTP Strict Transport Security (HSTS)
Forces browsers to use HTTPS.
use armature_security::hsts::HstsConfig;
let hsts = HstsConfig::new(31536000) // 1 year in seconds
.include_subdomains(true)
.preload(true);
let security = SecurityMiddleware::new().with_hsts(hsts);
Output Header:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
X-Frame-Options
Prevents clickjacking by controlling if your site can be framed.
use armature_security::frame_guard::FrameGuard;
// Deny all framing
let security = SecurityMiddleware::new()
.with_frame_guard(FrameGuard::Deny);
// Allow same origin
let security = SecurityMiddleware::new()
.with_frame_guard(FrameGuard::SameOrigin);
// Allow specific origin
let security = SecurityMiddleware::new()
.with_frame_guard(FrameGuard::AllowFrom("https://example.com".to_string()));
Output Header:
X-Frame-Options: DENY
X-Frame-Options: SAMEORIGIN
X-Frame-Options: ALLOW-FROM https://example.com
Referrer Policy
Controls how much referrer information is sent with requests.
use armature_security::referrer_policy::ReferrerPolicy;
let security = SecurityMiddleware::new()
.with_referrer_policy(ReferrerPolicy::NoReferrer);
// Other options:
// - NoReferrer
// - NoReferrerWhenDowngrade
// - Origin
// - OriginWhenCrossOrigin
// - SameOrigin
// - StrictOrigin
// - StrictOriginWhenCrossOrigin
// - UnsafeUrl
Output Header:
Referrer-Policy: no-referrer
X-XSS-Protection
Enables the browser's XSS filtering.
use armature_security::xss_filter::XssFilter;
// Enable with blocking
let security = SecurityMiddleware::new()
.with_xss_filter(XssFilter::EnabledBlock);
// Just enable (don't block)
let security = SecurityMiddleware::new()
.with_xss_filter(XssFilter::Enabled);
// Disable
let security = SecurityMiddleware::new()
.with_xss_filter(XssFilter::Disabled);
Output Header:
X-XSS-Protection: 1; mode=block
DNS Prefetch Control
Controls browser DNS prefetching.
use armature_security::dns_prefetch_control::DnsPrefetchControl;
// Disable DNS prefetching (more privacy)
let security = SecurityMiddleware::new()
.with_dns_prefetch_control(DnsPrefetchControl::Off);
// Enable DNS prefetching (better performance)
let security = SecurityMiddleware::new()
.with_dns_prefetch_control(DnsPrefetchControl::On);
Output Header:
X-DNS-Prefetch-Control: off
Expect-CT
Helps detect misissued certificates.
use armature_security::expect_ct::ExpectCtConfig;
let expect_ct = ExpectCtConfig::new(86400) // 1 day
.enforce(true)
.report_uri("https://example.com/report".to_string());
let security = SecurityMiddleware::new().with_expect_ct(expect_ct);
Output Header:
Expect-CT: max-age=86400, enforce, report-uri="https://example.com/report"
Hide X-Powered-By
Removes the X-Powered-By header to prevent server fingerprinting.
let security = SecurityMiddleware::new()
.hide_powered_by(true);
Result: X-Powered-By header is removed from responses.
Best Practices
1. Use Default Settings for Production
// Recommended for most applications
let security = SecurityMiddleware::default();
2. Customize for Your Needs
// Example: API server with custom CSP
let security = SecurityMiddleware::new()
.with_csp(
CspConfig::new()
.default_src(vec!["'self'".to_string()])
.connect_src(vec!["'self'".to_string(), "https://api.example.com".to_string()])
)
.with_hsts(HstsConfig::new(31536000))
.hide_powered_by(true);
3. Test in Development
Use browser developer tools to verify headers are applied:
# Chrome/Firefox: Network tab โ Select request โ Headers section
4. HSTS Considerations
- Start with a shorter
max-age(e.g., 300 seconds) in testing - Gradually increase to 1 year (31536000 seconds) in production
- Only enable
preloadafter testing thoroughly
5. CSP Development
- Start with
report-onlymode:let csp = CspConfig::default().report_only(true); - Monitor violations before enforcing
- Gradually tighten policies
API Reference
SecurityMiddleware
Main security middleware struct.
Methods
new()- Create with no protectionsdefault()- Create with recommended settingsenable_all(max_age: u64)- Enable all protectionswith_csp(config: CspConfig)- Add CSPwith_hsts(config: HstsConfig)- Add HSTSwith_frame_guard(guard: FrameGuard)- Set frame optionswith_referrer_policy(policy: ReferrerPolicy)- Set referrer policywith_xss_filter(filter: XssFilter)- Set XSS filterwith_dns_prefetch_control(control: DnsPrefetchControl)- Control DNS prefetchwith_expect_ct(config: ExpectCtConfig)- Add Expect-CThide_powered_by(hide: bool)- Hide X-Powered-By headerapply(response: HttpResponse) -> HttpResponse- Apply headers to response
Submodules
content_security_policy- CSP configurationhsts- HSTS configurationframe_guard- X-Frame-Optionsreferrer_policy- Referrer-Policyxss_filter- X-XSS-Protectiondns_prefetch_control- X-DNS-Prefetch-Controlexpect_ct- Expect-CTcontent_type_options- X-Content-Type-Optionsdownload_options- X-Download-Optionspermitted_cross_domain_policies- X-Permitted-Cross-Domain-Policies
Examples
Complete Application with Middleware Chain
use armature_framework::prelude::*;
use armature_framework::{
MiddlewareChain, LoggerMiddleware, CorsMiddleware,
RequestIdMiddleware, TimeoutMiddleware
};
use armature_security::{
SecurityMiddleware,
content_security_policy::CspConfig,
hsts::HstsConfig,
frame_guard::FrameGuard,
referrer_policy::ReferrerPolicy,
};
#[injectable]
#[derive(Clone, Default)]
struct UserService;
impl UserService {
fn get_users(&self) -> Vec<String> {
vec!["Alice".to_string(), "Bob".to_string()]
}
}
#[controller("/api/users")]
#[derive(Default, Clone)]
struct UserController;
impl UserController {
#[get("/")]
async fn list_users() -> Result<Json<Vec<String>>, Error> {
let service = UserService::default();
Ok(Json(service.get_users()))
}
#[get("/:id")]
async fn get_user(req: HttpRequest) -> Result<Json<String>, Error> {
let id = req.params.get("id").unwrap_or(&"0".to_string()).clone();
Ok(Json(format!("User {}", id)))
}
}
#[module(
providers: [UserService],
controllers: [UserController]
)]
#[derive(Default)]
struct AppModule;
#[tokio::main]
async fn main() {
println!("๐ Secure API Server");
println!("====================\n");
// Build comprehensive middleware stack
let mut middleware = MiddlewareChain::new();
// Request tracking
middleware.use_middleware(RequestIdMiddleware);
middleware.use_middleware(LoggerMiddleware::new());
// CORS for cross-origin requests
middleware.use_middleware(
CorsMiddleware::new()
.allow_origin("https://myapp.com")
.allow_methods("GET, POST, PUT, DELETE")
.allow_headers("Content-Type, Authorization")
.allow_credentials(true)
);
// Security headers - comprehensive protection
middleware.use_middleware(
SecurityMiddleware::new()
.with_hsts(
HstsConfig::new(31536000)
.include_subdomains(true)
.preload(true)
)
.with_frame_guard(FrameGuard::Deny)
.with_referrer_policy(ReferrerPolicy::StrictOriginWhenCrossOrigin)
.with_csp(
CspConfig::new()
.default_src(vec!["'self'".to_string()])
.script_src(vec!["'self'".to_string()])
.style_src(vec!["'self'".to_string(), "'unsafe-inline'".to_string()])
.img_src(vec!["'self'".to_string(), "data:".to_string(), "https:".to_string()])
.connect_src(vec!["'self'".to_string(), "https://api.example.com".to_string()])
)
.hide_powered_by(true)
);
// Request timeout
middleware.use_middleware(TimeoutMiddleware::new(30));
println!("Middleware stack configured:");
println!(" โ Request ID tracking");
println!(" โ Request logging");
println!(" โ CORS protection");
println!(" โ Security headers (HSTS, CSP, Frame-Options, etc.)");
println!(" โ 30 second timeout");
println!();
println!("Server running on http://localhost:3000");
}
API-Only Configuration (Minimal)
use armature_framework::prelude::*;
use armature_framework::MiddlewareChain;
use armature_security::{SecurityMiddleware, frame_guard::FrameGuard};
// For API servers that don't serve HTML, use a minimal config
let mut middleware = MiddlewareChain::new();
middleware.use_middleware(
SecurityMiddleware::new()
.with_frame_guard(FrameGuard::Deny) // Prevent embedding
.hide_powered_by(true) // Hide server info
// Skip CSP for API-only servers
);
Development vs Production
use armature_security::{SecurityMiddleware, hsts::HstsConfig};
fn create_security_middleware(is_production: bool) -> SecurityMiddleware {
if is_production {
// Full security for production
SecurityMiddleware::new()
.with_hsts(HstsConfig::new(31536000).preload(true))
.hide_powered_by(true)
} else {
// Relaxed for development
SecurityMiddleware::new()
.with_hsts(HstsConfig::new(300)) // Short HSTS for testing
.hide_powered_by(false) // Keep for debugging
}
}
// Usage
let is_prod = std::env::var("ENVIRONMENT").map(|v| v == "production").unwrap_or(false);
middleware_chain.use_middleware(create_security_middleware(is_prod));
Summary
The Armature Security middleware provides comprehensive protection against common web vulnerabilities:
- โ
Easy to use -
SecurityMiddleware::default()for most cases - โ Highly customizable - Configure each feature individually
- โ Production-ready - Based on industry best practices
- โ Well-tested - 21+ unit tests covering all features
- โ Type-safe - Full Rust type safety
For more examples, see examples/security_example.rs in the repository.