CSRF
Browser sinyalleri, session binding ve token kontrolüyle CSRF korumasını kurun.
CSRF koruması varsayılan olarak kapalıdır. Önce uygulamanızın session modelini, ardından hangi CSRF profilini kullanacağını seçin.
Profil seçimi#
| Profil | Kontrol | Uygulamanın sağlaması gereken |
|---|---|---|
cross_origin() |
Origin ve Fetch Metadata | Browser sinyalleri |
signed_double_submit(secret, binding) |
Session’a bağlı signed token | Secret ve binding |
defense_in_depth(secret, binding) |
Origin ve signed token | Secret ve binding |
synchronizer(secret, binding, store) |
Server-side token | CsrfTokenStore implementation’ı |
synchronizer_defense_in_depth(...) |
Origin ve server-side token | Binding, secret ve store |
cross_origin() profilinde hem Origin hem Sec-Fetch-Site yoksa unsafe istek kabul edilebilir. Token doğrulaması isteyen uygulamada token içeren bir profil seçin.
Session binding ve kurulum#
Session middleware’ın doğruladığı session ID’yi CsrfSessionId::new(...) ile request-local state’e koyun. Aşağıdaki composition parçasında secret ve middleware uygulamaya aittir:
let policy = CsrfPolicy::defense_in_depth(
CsrfSecret::new(application_secret)?,
CsrfRequestLocalBinding::new(),
)
.trust_origins(["https://app.example.com"])
.token_header("x-csrf-token")
.token_ttl(std::time::Duration::from_secs(3600));
let builder = AppBuilder::new("127.0.0.1:8080")
.session_middleware::<ApplicationSessionMiddleware>()
.csrf(policy);CsrfSessionCookieBinding::new(name) alternatifinde cookie değeri binding olarak alınır. Bu yol session store’a gidip oturumun geçerliliğini kendiliğinden denetlemez.
Global veya route kapsamı#
.csrf(policy) unsafe isteklerde global koruma uygular; exact bypass(method, path) istisnaları seçilebilir. .csrf_route_scoped(policy) yalnız #[guard(CsrfGuard)] action’larını korur. Session yayımlayan route guard’ı varsa CsrfGuard’dan önce gelmelidir.
İki mod birlikte kullanılamaz. Policy olmadan CsrfGuard, global modla birlikte CsrfGuard veya hiçbir CsrfGuard kullanmayan route-scoped kurulum build hatasıdır.
Token endpoint’i#
Önce policy ve session binding kurulmuş olmalıdır. serde_json = "1" ekleyin. Bu controller token’ı JSON olarak verir:
use std::sync::Arc;
use lilyrs::http_api::{
controller, Controller, ControllerInitError, ControllerTrait, CsrfService,
Extensions, HttpApiError, Request, Response, Service,
};
#[derive(Controller)]
#[base_path("/security")]
struct SecurityController;
#[lilyrs::http_api::async_trait::async_trait]
impl ControllerTrait for SecurityController {
async fn new(_: Arc<Extensions>) -> Result<Self, ControllerInitError> { Ok(Self) }
}
#[controller]
impl SecurityController {
#[get("/csrf")]
async fn csrf_token(
&self, Service(csrf): Service<CsrfService>,
request: &mut Request, response: &mut Response,
) -> Result<(), HttpApiError> {
let token = csrf.issue(request, response).await.map_err(|_| {
HttpApiError::ServiceUnavailable("CSRF token unavailable".into())
})?;
response.try_insert_header("content-type", "application/json")
.map_err(|_| HttpApiError::ResponseEncodingError("header rejected".into()))?;
response.try_insert_header("cache-control", "no-store")
.map_err(|_| HttpApiError::ResponseEncodingError("header rejected".into()))?;
let body = serde_json::to_vec(&serde_json::json!({ "token": token.as_str() }))
.map_err(|_| HttpApiError::ResponseEncodingError("JSON failed".into()))?;
response.set_body_vec(body)?;
Ok(())
}
}Manual response, signed profilin yazdığı Set-Cookie’yi korur. Browser token’ı JSON’dan alıp unsafe istekte x-csrf-token header’ıyla gönderir. HTTP-only cookie JavaScript’ten okunmaz. Cross-origin akışta CORS credentials ve browser credentials ayarlarını da tamamlayın.
Rotation ve store#
rotate, clear, previous_verification_key, cookie_policy, token_ttl ve URL-encoded form için allow_form_field seçenekleri vardır. Signed profilde session ID değişince yeni binding’e token verin. Synchronizer profilde eski binding’in state’ini ID değişmeden temizleyin.
CsrfTokenStore load-or-insert, rotate ve revoke işlemlerinin atomiklik sözleşmesini uygulamalıdır. Birden fazla instance varsa yalnız process belleğinde tutulan map yeterli ortak store olmaz.
Bu sayfanın kaynakları v0.1.0
Anlatım, incelenen framework commit’ine dayanır.