Vývoj autorizační služby v Rustu: od tokenů po orchestrace
Vytvoření spolehlivé autorizační služby v Rustu vyžaduje hluboké porozumění kryptografie, správy tokenů a návrhu abstrakcí. Tento materiál rozebírá praktické zkušenosti z vývoje, včetně generování JWT a opaque-tokenů, jejich ověřování a ukládání v Redis.
Architektura tokenů a jejich generování
Služba využívá dva typy tokenů: access (JWT) a refresh (opaque). Access-tokeny zajišťují krátkodobý přístup, zatímco refresh-tokeny slouží k jejich obnovení bez opakované autentizace uživatele.
Pro generování JWT-tokenů se používá asymetrické šifrování s algoritmem RS256. To vyžaduje pár klíčů: soukromý pro podepisování a veřejný pro ověřování. Opaque-tokeny se generují jako náhodné řetězce base64, které nenesou informace pro klienta, což zvyšuje bezpečnost.
Klíčové komponenty generování
- JwtTokenProvider: trait pro generování JWT s využitím claims a soukromého klíče.
- OpaqueTokenProvider: trait pro vytváření nepřehledných tokenů prostřednictvím náhodných bajtů.
- Struktura claims: zahrnuje standardní pole, jako je sub (identifikátor uživatele), jti (identifikátor tokenu), iat (čas vytvoření) a exp (doba platnosti).
Příklad implementace JwtTokenProvider:
pub trait IJwtTokenProvider {
type Claims: Send + Sync;
type Error;
fn generate(&self, claims: &Self::Claims, pem: &str) -> Result<String, Self::Error>;
}
Ověřování a validace tokenů
Ověřování JWT-tokenů probíhá přes veřejný klíč, což zabraňuje použití kompromitovaných soukromých klíčů. K tomu je implementován trait IJwtTokenValidator, který kontroluje podpis a integritu tokenu.
Specifika validace
- Využití formátu PEM: klíče jsou uloženy v PEM-souborech, podporujících certifikáty a řetězce důvěry.
- Šifrovací algoritmy: služba podporuje jak symetrické (např. HSA), tak asymetrické (např. RSA) metody, s preferencí těch asymetrických pro vyšší bezpečnost.
- Konverze claims: doménové modely claims jsou převedeny pro kompatibilitu s knihovnami, například konverze DateTime na usize.
Příklad kódu pro ověření:
pub trait IJwtTokenValidator {
type Claims: Send + Sync;
type Error;
fn verify(&self, token: &str, pem: &str) -> Result<Self::Claims, Self::Error>;
}
Ukládání a orchestrace tokenů
Pro správu tokenů a klíčů jsou vyvinuty TokenManager a KeyManager. TokenManager zodpovídá za generování, ověřování a ukládání tokenů v Redis, využívající abstrakce pro flexibilitu.
Implementace RedisIO
Modul RedisIO zjednodušuje práci s úložištěm, poskytuje metody setex, get a delete. To snižuje boilerplate-kód a zlepšuje čitelnost.
Příklad implementace:
impl<Storage> RedisIO<Storage>
where Storage: redis::AsyncCommands + Send + Sync
{
pub async fn setex(&mut self, key: &str, data: &str, exp: u64) -> Result<(), redis::RedisError> {
self.redis_storage.set_ex::<&str, String, (>(&key, data.to_string(), exp).await?;
Ok(())
}
}
Funkcionalita TokenManager
TokenManager využívá generické typy pro poskytovatele a validátory, což umožňuje snadnou výměnu komponent. Hlavní metody:
- generate_pair: vytváří pár access- a refresh-tokenů, ukládá je v Redis se stanovenou dobou života.
- verify_access: kontroluje platnost access-tokenu a jeho existenci v úložišti.
Příklad použití:
pub async fn generate_pair(&mut self, claims: &Claims, pem: &str) -> Result<(String, String), TokenManagerError> {
let access_token = self.access_provider.generate(&claims, &pem)?;
let refresh_token = self.refresh_provider.generate();
// Logika uložení v Redis
Ok((access_token, refresh_token))
}
Co je důležité
- Použití asymetrického šifrování (RS256) pro JWT zvyšuje bezpečnost oproti symetrickým metodám.
- Opaque-tokeny jsou generovány jako náhodné řetězce base64, což ztěžuje jejich padělání.
- Abstrakce prostřednictvím traits umožňují snadné testování a modifikace komponent služby.
- Ukládání tokenů v Redis s TTL zajišťuje správu session a snižuje zátěž databáze.
- Správné oddělení soukromých a veřejných klíčů je klíčové pro prevenci zranitelností.
Potenciální problémy a jejich řešení
Během vývoje bylo identifikováno několik zranitelností a obtíží:
- Růst velikosti base64: při kódování 32 bajtů do base64 se řetězec zvětší na 43 bajtů, což může vést k neočekávaným chybám v logice ukládání.
- Chyby v správě klíčů: použití soukromého klíče místo veřejného pro ověřování narušuje bezpečnost.
- Obtíže s datovými typy: konverze mezi DateTime a usize vyžaduje dodatečnou validaci.
Pro jejich odstranění se doporučuje:
- Testovat hraniční případy s různými velikostmi dat.
- Implementovat přísné kontroly typů a formátů klíčů.
- Využívat knihovny s podporou standardů JWT a kryptografie.
— Editorial Team
Zatím žádné komentáře.