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