webhook: compare secret in constant time
payload.secret != expected_secret short-circuits on the first differing byte, which leaks timing information about how many leading bytes of a guess are correct. Use subtle::ConstantTimeEq instead.
This commit is contained in:
parent
85369069c3
commit
1473e726f3
2 changed files with 5 additions and 1 deletions
|
|
@ -18,6 +18,7 @@ reqwest = {
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
sha2 = "0.10"
|
sha2 = "0.10"
|
||||||
|
subtle = "2"
|
||||||
sqlx = {
|
sqlx = {
|
||||||
version = "0.8",
|
version = "0.8",
|
||||||
features = [
|
features = [
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use axum::{extract::State, http::StatusCode, response::IntoResponse};
|
use axum::{extract::State, http::StatusCode, response::IntoResponse};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
use subtle::ConstantTimeEq;
|
||||||
|
|
||||||
use crate::AppState;
|
use crate::AppState;
|
||||||
|
|
||||||
|
|
@ -28,7 +29,9 @@ pub async fn receive(
|
||||||
.into_response();
|
.into_response();
|
||||||
};
|
};
|
||||||
|
|
||||||
if payload.secret != expected_secret {
|
let secret_matches = payload.secret.as_bytes().ct_eq(expected_secret.as_bytes());
|
||||||
|
|
||||||
|
if !bool::from(secret_matches) {
|
||||||
tracing::warn!("received webhook with invalid secret");
|
tracing::warn!("received webhook with invalid secret");
|
||||||
|
|
||||||
return (StatusCode::UNAUTHORIZED, "invalid webhook secret").into_response();
|
return (StatusCode::UNAUTHORIZED, "invalid webhook secret").into_response();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue