fix(security): add security response headers and request body size limit
- Add Content-Security-Policy, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, and Strict-Transport-Security response headers - Set explicit 5 MB request body size limit via RequestBodyLimitLayer - Enable tower-http "limit" and "set-header" features
This commit is contained in:
parent
d35e1792da
commit
85946ba9a4
2 changed files with 36 additions and 3 deletions
|
|
@ -33,7 +33,7 @@ tracing = "0.1"
|
||||||
tracing-subscriber = { version = "0.3", features = ["env-filter", "json", "fmt"] }
|
tracing-subscriber = { version = "0.3", features = ["env-filter", "json", "fmt"] }
|
||||||
tower = "0.4"
|
tower = "0.4"
|
||||||
tower-cookies = "0.10"
|
tower-cookies = "0.10"
|
||||||
tower-http = { version = "0.6", features = ["trace"] }
|
tower-http = { version = "0.6", features = ["limit", "set-header", "trace"] }
|
||||||
slug = "0.1.6"
|
slug = "0.1.6"
|
||||||
url = "2"
|
url = "2"
|
||||||
uuid = { version = "1", features = ["v4"] }
|
uuid = { version = "1", features = ["v4"] }
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,12 @@ pub mod support;
|
||||||
pub(crate) use app::auth::is_authenticated;
|
pub(crate) use app::auth::is_authenticated;
|
||||||
|
|
||||||
use askama::Template;
|
use askama::Template;
|
||||||
use axum::http::StatusCode;
|
use axum::http::{HeaderValue, StatusCode};
|
||||||
use axum::response::Html;
|
use axum::response::Html;
|
||||||
use tower::ServiceBuilder;
|
use tower::ServiceBuilder;
|
||||||
use tower_cookies::CookieManagerLayer;
|
use tower_cookies::CookieManagerLayer;
|
||||||
|
use tower_http::limit::RequestBodyLimitLayer;
|
||||||
|
use tower_http::set_header::SetResponseHeaderLayer;
|
||||||
use tower_http::trace::{DefaultMakeSpan, DefaultOnResponse, TraceLayer};
|
use tower_http::trace::{DefaultMakeSpan, DefaultOnResponse, TraceLayer};
|
||||||
use tracing::Level;
|
use tracing::Level;
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
|
|
@ -17,6 +19,9 @@ use crate::application::state::AppState;
|
||||||
|
|
||||||
use crate::presentation::web::templates::render_template;
|
use crate::presentation::web::templates::render_template;
|
||||||
|
|
||||||
|
/// 5 MB request body limit.
|
||||||
|
const BODY_LIMIT_BYTES: usize = 5 * 1024 * 1024;
|
||||||
|
|
||||||
pub fn app_router(state: AppState) -> axum::Router {
|
pub fn app_router(state: AppState) -> axum::Router {
|
||||||
axum::Router::new()
|
axum::Router::new()
|
||||||
.merge(app::router())
|
.merge(app::router())
|
||||||
|
|
@ -29,7 +34,35 @@ pub fn app_router(state: AppState) -> axum::Router {
|
||||||
.make_span_with(DefaultMakeSpan::new().level(Level::INFO))
|
.make_span_with(DefaultMakeSpan::new().level(Level::INFO))
|
||||||
.on_response(DefaultOnResponse::new().level(Level::INFO)),
|
.on_response(DefaultOnResponse::new().level(Level::INFO)),
|
||||||
)
|
)
|
||||||
.layer(CookieManagerLayer::new()),
|
.layer(CookieManagerLayer::new())
|
||||||
|
.layer(RequestBodyLimitLayer::new(BODY_LIMIT_BYTES))
|
||||||
|
.layer(SetResponseHeaderLayer::overriding(
|
||||||
|
axum::http::header::X_CONTENT_TYPE_OPTIONS,
|
||||||
|
HeaderValue::from_static("nosniff"),
|
||||||
|
))
|
||||||
|
.layer(SetResponseHeaderLayer::overriding(
|
||||||
|
axum::http::header::X_FRAME_OPTIONS,
|
||||||
|
HeaderValue::from_static("DENY"),
|
||||||
|
))
|
||||||
|
.layer(SetResponseHeaderLayer::overriding(
|
||||||
|
axum::http::header::REFERRER_POLICY,
|
||||||
|
HeaderValue::from_static("strict-origin-when-cross-origin"),
|
||||||
|
))
|
||||||
|
.layer(SetResponseHeaderLayer::overriding(
|
||||||
|
axum::http::header::CONTENT_SECURITY_POLICY,
|
||||||
|
HeaderValue::from_static(
|
||||||
|
"default-src 'self'; \
|
||||||
|
script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.jsdelivr.net; \
|
||||||
|
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; \
|
||||||
|
font-src 'self' https://fonts.gstatic.com; \
|
||||||
|
img-src 'self' data:; \
|
||||||
|
frame-ancestors 'none'",
|
||||||
|
),
|
||||||
|
))
|
||||||
|
.layer(SetResponseHeaderLayer::overriding(
|
||||||
|
axum::http::header::STRICT_TRANSPORT_SECURITY,
|
||||||
|
HeaderValue::from_static("max-age=63072000; includeSubDomains"),
|
||||||
|
)),
|
||||||
)
|
)
|
||||||
.with_state(state)
|
.with_state(state)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue