7 个版本
0.3.2 | 2024年1月1日 |
---|---|
0.3.1 |
|
0.2.9 | 2022年10月17日 |
0.1.0 |
|
#276 in 加密学
每月55次下载
115KB
2K SLoC
ncryptf-rs
Rust 绑定 ncryptf
rust ncryptf 绑定旨在与其它语言的绑定具有相似的 API,以方便阅读。
安装
您可以通过 cargo 将 ncryptf 添加到您的项目中的 Cargo.toml
ncryptf-rs = { git = "github.com/ncryptf/ncryptf-rs" }
Ncryptf 支持 2 个可选功能
rocket
用于 rocket.rs 绑定client
提供一个reqwest
客户端,您可以使用它来与 ncryptf 交互。
导出
ncryptf 为了便利和必要性重新导出了一些额外的库。
Rocket
Ncryptf 使用了修改版的 rocket.rs (0.5.0-rc: see https://github.com/charlesportwoodii/rocket.rs/tree/peek_buffer) 来获取请求数据,以使用 Rocket.rs 进行身份验证。强烈建议将这个版本的 rocket (及其他重新导出的库) 存储在一个 common
工作区中,以消除在每个工作区成员中添加相同的 cargo 依赖项的需要。
如果您在 main.rs
中使用 rocket.rs 的 proc_macro
,您仍然需要导入该宏。
rocket = { features = ["tls", "secrets", "json"] }
库映射
当使用 ncryptf 的默认重新导出时,导入的结构体名称将位于 ncryptf::<lib>
命名空间下,这对 rust-analyzer 和开发者来说可能会有些困惑。为了使 rust-analyzer 和编译器更加合理,请考虑使用一个 common
工作区,该工作区重新导出 ncryptf、rocket 和任何其他功能。
示例
common
\ - mod.rs
- ncryptflib.rs
在您的 mod.rs
或 lib.rs
中有以下内容
pub mod ncryptflib
然后在您的 ncryptflib.rs 中有以下内容
pub use ncryptf::{
auth,
client,
ek_route,
rocket,
Authorization,
Keypair,
NcryptfError,
Request,
Response,
Token,
randombytes_buf
};
然后您可以在代码的其他地方使用 pub use ncryptflib as ncryptf
,以便在不冲突的情况下,在标准命名空间下使用标准库。
HMAC+HKDF 身份验证
HMAC+HKDF身份验证是一种身份验证方法,它确保请求在传输过程中未被篡改。这不仅为网络层操作提供了弹性,还能抵御中间人攻击。
从高层次来看,HMAC签名是根据原始请求体、HTTP方法、URI(如果有查询参数)以及当前日期创建的。除了确保请求在传输过程中不会被篡改之外,它还确保了请求被时间限制,有效地防止重放攻击。
可以通过导入以下结构体来提供库本身:
支持API的将返回以下负载,其中至少包含以下信息。
{
"access_token": "7XF56VIP7ZQQOLGHM6MRIK56S2QS363ULNB5UKNFMJRQVYHQH7IA",
"refresh_token": "MA2JX5FXWS57DHW4OIHHQDCJVGS3ZKKFCL7XM4GNOB567I6ER4LQ",
"ikm": "bDEyECRvKKE8w81fX4hz/52cvHsFPMGeJ+a9fGaVvWM=",
"signing": "7v/CdiGoEI7bcj7R2EyDPH5nrCd2+7rHYNACB+Kf2FMx405und2KenGjNpCBPv0jOiptfHJHiY3lldAQTGCdqw==",
"expires_at": 1472678411
}
使用此令牌,您可以授权对支持API的以下请求:
use ncryptf::*;
match Token::from_json(json) {
Err(_) => {},
Ok(token) => {
let auth = Authorization::from(
"POST".to_string(),
"/api/v1/test".to_string(),
token,
chrono::offset::Utc::now(),
None,
None
);
// make a reqwest with Authorization: auth.get_header()
}
}
请查阅第1版头部信息的库文档和其他ncryptf库。
加密请求与响应
此库使客户端能够在TLS层之上建立并信任的加密会话,同时(且独立地)提供通过HMAC+HKDF风格的身份验证来认证和识别客户端的能力。
此功能的原因包括但不限于:
- 需要额外的安全层
- 对网络或TLS本身缺乏信任(参见https://blog.cloudflare.com/incident-report-on-memory-leak-caused-by-cloudflare-parser-bug/)
- 需要确保为HMAC+HKDF身份验证提供的初始密钥材料(IKM)的机密性
- 需要确保向API提交的用户凭证的机密性
您可能想要与API本身建立加密会话的主要原因是为了确保IKM的机密性,以防止在不可信网络上发生数据泄露,避免在Cloudflare-like事件(或任何中间人攻击)中暴露信息。加密会话使您在内存泄露再次发生时能够有信心地使用类似Cloudflare的服务,而不会暴露IKM和其他安全数据。
请参阅test/integration.rs
文件以获取请求和加密、解密响应的完整示例。
Rocket.rs体解析,和响应发出
此库提供针对Rocket.rs的特定实现来处理传入的加密(以及通过代理的纯文本)JSON请求。处理此请求的设置如下:
-
您的服务器必须提供Redis实例,并且它必须对Rocket可用。
-
为
databases
配置项添加一个rocket_Db_pools::Config
。
let config = rocket::Config::figment()
.merge(("databases.cache", rocket_db_pools::Config {
url: format!("redis://127.0.0.1:6379/"),
min_connections: None,
max_connections: 1024,
connect_timeout: 3,
idle_timeout: None,
}))
- 现在,您可以通过添加一个body接受者来解析和接受ncryptf:🚀:Json的application/json和application/vnd.ncryptf+json,您的请求现在将能够以这种方式解析和接受请求和响应。
#[post("/echo", data="<data>")]
fn echo(data: ncryptf::rocket::Json<TestStruct>) -> ncryptf::rocket::Json<TestStruct> {
return ncryptf::rocket::Json(data.0);
}
如果需要,也提供了
JsonResponse<T>
来返回带有状态码的Ncryptf或纯文本JSON响应。
- 为了引导,库提供生成引导密钥的便利端点。
/// Define an actual RedisDb instance
#[derive(Database)]
#[database("cache")]
pub struct RedisDb(deadpool_redis::Pool);
/// Use the provided macro to generate the route.
ek_route!(RedisDb);
/// Attach the dynamic macro route to your request.
let rocket = rocket::custom(config)
.attach(RedisDb::init())
.mount("/ncryptf", routes![ncryptf_ek_route]);
身份验证和请求验证
Ncryptf还提供了验证请求的功能。虽然tests/rocketts
文件夹包含许多针对Rocket的特定示例,但该方法可以用于任何实现。Ncryptf的请求授权类似于AWS Signature V2身份验证,因为它
- 为验证服务器端以确认请求未被篡改而签署未加密的请求体。
- 防止重放攻击。
- 将请求时间限制在签署请求的日期和时间。
客户端应实施以下内容以进行授权请求。
- 从IKM端点提供的数据生成令牌。
let token = ncryptf::Token::from(
"x2gMeJ5Np0CcKpZav+i9iiXeQBtaYMQ/yeEtcOgY3J".to_string(),
"LRSEe5zHb1aq20Hr9te2sQF8sLReSkO8bS1eD/9LDM8".to_string(),
base64::decode("f2mTaH9vkZZQyF7SxVeXDlOSDbVwjUzhdXv2T/YYO8k=").unwrap().to_vec(),
base64::decode("7v/CdiGoEI7bcj7R2EyDPH5nrCd2+7rHYNACB+Kf2FMx405und2KenGjNpCBPv0jOiptfHJHiY3lldAQTGCdqw==").unwrap().to_vec(),
now + 14400
).unwrap();
- 为您的请求创建一个授权对象。
let auth = match ncryptf::Authorization::from(
"POST".to_string(), /// this must be uppercase
"/auth_echo".to_string(),
token,
Utc::now(),
json.clone().to_string(),
None,
Some(2)
) {
Ok(auth) => auth,
Err(_) => {
assert!(false);
panic!("unable to generate auth header")
}
};
- 生成头并添加到请求中。
let client = reqwest::Client::new();
let res = client
.post("https://www.ncryptf.com/example")
.header("Authorization:", auth.get_header())
.send()
.await?;
如果您已启用client
功能,您还可以更简单地执行请求。有关更多详细信息和方法示例,请参阅cargo文档。
Rocket请求保护器
本库额外提供了处理认证请求的功能,包括解析和与Rocket.rs的验证。以下是实现方式。
- 让您的用户实体实现
ncryptf::rocket::AuthorizationTrait
异步特质。 - 在您的用户实体实现结束时,运行以下宏来绑定FromRequest特质。
ncryptf::auth!(User);
- 您的请求现在可以作为一个Rocket请求保护的一部分检索用户实体。
#[get("/")]
fn auth_echo( _user: User){
dbg!(_user);
}
- 对于带有主体的请求,您可以使用数据保护提取身份和请求数据。
#[post("/", data = "<data>")]
fn auth_echo(data = ncryptf::rocket::RequestData<User>){
let user: User = data.get_identity();
let s: ncryptf::rocket::Json::<T> = data.get_data();
}
您可以将此与请求和响应的格式化和解析结合使用。
重要注意事项
该库为了适当读取和解析请求头和主体,对Rocket的几个实现进行了一些奇怪的操作。因此,只有当请求的Content-Type设置为以下任意一种时,授权头才会被解析和处理:application/json
或application/vnd.ncryptf+json
。通过Accept头处理响应,对于上述两种内容类型,您的Rocket路由必须返回一个ncryptf::rocket::Json<T>
,它可以适当处理这两种内容类型。
此外,ncryptf:🚀:Fairing消耗DataStream,直到您的默认JSON限制。如果您的请求开始超过8M的限制,您必须扩展您的限制以捕获整个流,否则所有请求将返回401或403。
由于缺少通用的缓存实现(如PSR-6),该库强制使用Redis。因此,您必须提供一个可用的Redis实例。
V2加密有效载荷
版本2与版本1的有效载荷工作方式相同,区别在于,所有用于解密消息的组件都打包在有效载荷本身中,而不是拆分为单独的头。这减轻了开发者管理多个头的担忧。
版本2的有效载荷描述如下。每个组件都连接在一起。
段 | 长度 |
---|---|
4字节头DE259002 ,二进制格式 |
4字节 |
nonce | 24字节 |
与私钥关联的公钥 | 32字节 |
加密主体 | X字节 |
签名公钥 | 32字节 |
签名或原始请求主体 | 64字节 |
前述元素的校验和 | 64字节 |
依赖项
~9–45MB
~760K SLoC