1个稳定版本
| 1.0.0 | 2021年2月18日 |
|---|
#9 in #session-keys
45KB
869 代码行
LiteSession
创建抵抗滥用和劫持的会话令牌
lib.rs:
LiteSession是一个安全令牌生成器,可用于HTTP认证头、cookie、Json Web Tokens的替代品、物联网以及其他需要客户端和服务器之间通信安全令牌的任何地方。它提供带有关联客户端数据的密钥哈希消息认证码,以加密(默认设置)或未加密的形式。
算法的一般形式是
identifier | issued | expiry | (data)k | nonce | ConfidentialityMode | Blake3HMAC( username | issued | expiration | data | session key, k)
where `k = Blake3HMAC(user | issued | expiry | ConfidentialityMode, sk)`
涉及步骤包括
-
生成一个
随机标识符 -
生成一个
发行时间和过期时间,精确到纳秒 -
生成用于加密令牌数据部分的
加密密钥。使用算法k = Blake3HMAC(identifier | issued | expiry | ConfidentialityMode, sk)- 创建一个空的字符串
encryption_key - 将
identifier添加到encryption_key - 将
issued添加到encryption_key - 将
expiry添加到encryption_key - 将
ConfidentialityMode添加到encryption_key - 使用键控模式的Blake3和
server_key作为密钥对encryption_key执行HMAC函数 - 以
hex或作为string返回上述Blake3操作的结果
- 创建一个空的字符串
-
使用上述Blake3Hash作为加密密钥,使用
ChaCha8加密加密数据 -
返回加密数据和
nonce -
对
identifier | issued | expiry | (data)k | nonce | ConfidentialityMode执行Blake3Hmac -
生成令牌
- 创建一个名为
token的空字符串 - 将
identifier添加到token - 将
issued添加到token - 将
expiry添加到token - 将加密数据
encrypted data添加到token - 将
nonce添加到token - 将
ConfidentialityMode添加到token - 将
Blake3Hmac添加到token - 以字符串或十六进制形式返回token。生成的token格式为
identifier⊕issued⊕expiry⊕ciphertext⊕nonce⊕confidentiality⊕hmac
- 创建一个名为
验证token的步骤如下
- 检查token结构是否有效
- 将token解构为其组件字段
- 将
expiry与服务器的当前时间进行比较,并返回SessionExpired作为TokenOutcome - 计算加密密钥如下:
k=HMAC(identifier | issued | expiry | ConfidentialityMode, sk) - 使用
k解密加密数据。 - 计算
Blake3HMAC(identifier | issued | expiry | ciphertext | nonce | ConfidentialityMode | session key, k) - 如果token匹配,则返回
TokenOutcome::TokenAuthetic;如果token不匹配,则返回TokenOutcome::TokenRejected
在 keyed 模式下使用 Blake3 算法,密钥长度为 32byte/256bit。 ChaCha8 算法需要一个 32byte/256bit 的密钥和一个 12byte/96bit 的nonce。使用 International Atomic Time(TAI) 来保证纳秒级精度,且无需处理闰秒和时区问题。使用 session key 可以防止 volume 和 Denning-Sacco 攻击
用法
创建token
use lite_session::{LiteSessionToken, LiteSessionError, ConfidentialityMode, LiteSessionData, Role, LiteSessionMode};
use core::time::Duration;
fn main() -> Result<(), LiteSessionError> {
let mut token = LiteSessionToken::default();
let expiry = 60*60_u64;
token.expiry(expiry);
let mut data = LiteSessionData::default();
data.username("foo_user");
data.role(Role::SuperUser);
data.tag("Foo-Tag");
data.add_acl("Network-TCP");
data.add_acl("Network-UDP");
token.hmac_data(data);
token.confidential(true);
token.mode(LiteSessionMode::SessionID("foobarbaz".into()));
let server_key = [0_u8; 32];
let session_token = token.build_secure(&server_key)?;
Ok(())
}
验证token
use lite_session::{LiteSessionToken, LiteSessionError, ConfidentialityMode, LiteSessionData, LiteSessionMode};
fn main() -> Result<(), LiteSessionError> {
let server_key = [0_u8; 32];
let mut destructured = LiteSessionToken::default();
let session_token = "5tl726krvgmhoe1pyc4jadqs3fw09bi8⊕40000000602e51ab3a8e2d17⊕40000000603013ab3a8e2d17⊕3cf157bed212d5b34122a713ea860ec373800e5004bff1a195d603305bd5b7921d1017e70ef599bc1f7ed949bd3c66c696d74a16487f95a3f6fd⊕jrzapflsi618⊕ConfidentialityMode::High⊕4faab373d7247dfb2d50e213e5cb66e415afc22066f71c2b966fdeabb11cac64";
let outcome = destructured.from_string(&server_key, &session_token)?;
Ok(())
}
依赖项
~2.5MB
~59K SLoC