csrf fixes
This commit is contained in:
@@ -117,16 +117,6 @@ pub async fn logout(Extension(session): Extension<SessionHandle>) -> Response {
|
|||||||
Redirect::to("/login").into_response()
|
Redirect::to("/login").into_response()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn csrf_error_page(
|
|
||||||
State(state): State<AppState>,
|
|
||||||
Extension(session): Extension<SessionHandle>,
|
|
||||||
) -> Response {
|
|
||||||
let ctx = base_context(&session, None);
|
|
||||||
let mut resp = render(&state, "csrf_error.html", &ctx);
|
|
||||||
*resp.status_mut() = StatusCode::FORBIDDEN;
|
|
||||||
resp
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn root_redirect() -> Response {
|
pub async fn root_redirect() -> Response {
|
||||||
Redirect::to("/ui/buckets").into_response()
|
Redirect::to("/ui/buckets").into_response()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -304,8 +304,7 @@ pub fn create_ui_router(state: state::AppState) -> Router {
|
|||||||
|
|
||||||
let public = Router::new()
|
let public = Router::new()
|
||||||
.route("/login", get(ui::login_page).post(ui::login_submit))
|
.route("/login", get(ui::login_page).post(ui::login_submit))
|
||||||
.route("/logout", post(ui::logout).get(ui::logout))
|
.route("/logout", post(ui::logout).get(ui::logout));
|
||||||
.route("/csrf-error", get(ui::csrf_error_page));
|
|
||||||
|
|
||||||
let session_state = middleware::SessionLayerState {
|
let session_state = middleware::SessionLayerState {
|
||||||
store: state.sessions.clone(),
|
store: state.sessions.clone(),
|
||||||
@@ -317,7 +316,10 @@ pub fn create_ui_router(state: state::AppState) -> Router {
|
|||||||
protected
|
protected
|
||||||
.merge(public)
|
.merge(public)
|
||||||
.fallback(ui::not_found_page)
|
.fallback(ui::not_found_page)
|
||||||
.layer(axum::middleware::from_fn(middleware::csrf_layer))
|
.layer(axum::middleware::from_fn_with_state(
|
||||||
|
state.clone(),
|
||||||
|
middleware::csrf_layer,
|
||||||
|
))
|
||||||
.layer(axum::middleware::from_fn_with_state(
|
.layer(axum::middleware::from_fn_with_state(
|
||||||
session_state,
|
session_state,
|
||||||
middleware::session_layer,
|
middleware::session_layer,
|
||||||
|
|||||||
@@ -90,7 +90,11 @@ pub async fn session_layer(
|
|||||||
resp
|
resp
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn csrf_layer(req: Request, next: Next) -> Response {
|
pub async fn csrf_layer(
|
||||||
|
State(state): State<crate::state::AppState>,
|
||||||
|
req: Request,
|
||||||
|
next: Next,
|
||||||
|
) -> Response {
|
||||||
const CSRF_HEADER_ALIAS: &str = "x-csrftoken";
|
const CSRF_HEADER_ALIAS: &str = "x-csrftoken";
|
||||||
|
|
||||||
let method = req.method().clone();
|
let method = req.method().clone();
|
||||||
@@ -169,7 +173,32 @@ pub async fn csrf_layer(req: Request, next: Next) -> Response {
|
|||||||
header_present = header_token.is_some(),
|
header_present = header_token.is_some(),
|
||||||
"CSRF token mismatch"
|
"CSRF token mismatch"
|
||||||
);
|
);
|
||||||
(StatusCode::FORBIDDEN, "Invalid CSRF token").into_response()
|
|
||||||
|
let accept = parts
|
||||||
|
.headers
|
||||||
|
.get(header::ACCEPT)
|
||||||
|
.and_then(|v| v.to_str().ok())
|
||||||
|
.unwrap_or("");
|
||||||
|
let is_form_submit = content_type.starts_with("application/x-www-form-urlencoded")
|
||||||
|
|| content_type.starts_with("multipart/form-data");
|
||||||
|
let wants_json = accept.contains("application/json")
|
||||||
|
|| content_type.starts_with("application/json");
|
||||||
|
|
||||||
|
if is_form_submit && !wants_json {
|
||||||
|
let ctx = crate::handlers::ui::base_context(&handle, None);
|
||||||
|
let mut resp = crate::handlers::ui::render(&state, "csrf_error.html", &ctx);
|
||||||
|
*resp.status_mut() = StatusCode::FORBIDDEN;
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut resp = (
|
||||||
|
StatusCode::FORBIDDEN,
|
||||||
|
[(header::CONTENT_TYPE, "application/json")],
|
||||||
|
r#"{"error":"Invalid CSRF token"}"#,
|
||||||
|
)
|
||||||
|
.into_response();
|
||||||
|
*resp.status_mut() = StatusCode::FORBIDDEN;
|
||||||
|
resp
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_multipart_token(content_type: &str, body: &[u8]) -> Option<String> {
|
fn extract_multipart_token(content_type: &str, body: &[u8]) -> Option<String> {
|
||||||
|
|||||||
Reference in New Issue
Block a user