15个版本 (7个破坏性更新)
0.8.0 | 2019年1月18日 |
---|---|
0.6.0 | 2018年12月22日 |
0.5.2 | 2018年11月21日 |
0.1.3 | 2018年1月15日 |
0.1.2 | 2017年12月24日 |
#1936 in 密码学
每月80次下载
88KB
1.5K SLoC
HTTP签名
此crate用于创建和验证HTTP签名,定义如下:此处。它支持Actix Web、Hyper、Rocket和Reqwest类型。未来,我也可能支持Iron中间件进行验证。
运行示例
每个示例都位于其自己的crate中,在示例文件夹中
Hyper示例默认配置为相互通信。服务器运行在端口3000上,客户端在端口3000上POST。它们还使用Signature
头进行请求的签名和验证。
actix-web服务器和客户端示例监听并POST到端口5000,可以相互测试。它们使用Signature
头进行请求的签名和验证。
rocket 4服务器监听在端口8000上,reqwest客户端可以与之交互。这些示例使用Authorization
头进行请求的签名和验证。
用法
使用Actix Web
将其添加到您的Cargo.toml
[dependencies.http-signatures]
version = "0.7"
features = ["use_actix_web"]
服务器使用
像这样在您的应用程序中使用它。
const PHRASE: &str = "Hewwo, Mr. Obama???";
#[derive(Debug, Fail)]
#[fail(display = "Error verifying signature, {}", _0)]
pub struct Error(#[cause] http_signatures::Error);
impl ResponseError for Error {}
#[derive(Clone)]
pub struct MyState {
arc: Arc<Vec<u8>>,
}
fn index((req, state): (HttpRequest<MyState>, State<MyState>)) -> impl Responder {
let verified = req.verify_signature_header(VerifyKey::unchecked_from_slice(&state.arc));
verified.map_err(|e| Error(e.into())).map(|_| {
HttpResponse::Ok()
.content_length(PHRASE.len() as u64)
.content_type("text/plain")
.force_close()
.body(format!("{}", PHRASE))
})
}
fn main() -> Result<(), Box<dyn Fail> {
let mut key_file = File::open("../../tests/assets/public.der")?;
let mut key_file_vec = Vec::new();
key_file.read_to_end(&mut key_file_vec)?;
let key_arc = Arc::new(key_file_vec);
let state = MyState { arc: key_arc };
server::new(move || App::with_state(state.clone()).resource("/", |r| r.with(index)))
.bind("127.0.0.1:5000")
.expect("Can not bind to port 5000")
.run();
Ok(())
}
客户端使用
let key_id = "some-username-or-something";
let json = r#"{"library":"actix-web"}"#;
let mut req = post("https://127.0.0.1:5000")
.content_length(json.len() as u64)
.content_type("application/json")
.body(json)?;
req.with_signature_header(
key_id.to_owned(),
CreateKey::rsa(private_key, ShaSize::SHA256),
)?;
actix_web::actix::run(move || {
req.send().map_err(|_| ()).map(|res| {
println!("POST: {}", res.status());
actix_web::actix::System::current().stop();
})
});
使用Hyper
将其添加到您的Cargo.toml
[dependencies.http-signatures]
version = "0.7"
features = ["use_hyper"]
客户端
按照以下方式构建请求时使用它。
let client = Client::new();
let json = r#"{"library":"hyper"}"#;
let mut req = Request::post("https://127.0.0.1:3000")
.body(Body::from(json))?;
req.headers_mut().insert(
CONTENT_TYPE,
HeaderValue::from_str("application/json")?,
);
req.headers_mut().insert(
CONTENT_LENGTH,
HeaderValue::from_str(&format!("{}", json.len()))?,
);
let key_id = "some-username-or-something";
// Add the HTTP Signature
req.with_signature_header(
key_id.into(),
CreateKey::rsa(private_key, ShaSize::SHA256),
)?;
let post = client.request(req).and_then(|res| {
println!("POST: {}", res.status());
res.into_body().concat2()
});
tokio::run(post.map(|_| ()).map_err(|_| ()));
服务器
这是一个非常基础的示例服务器轮廓,应该能给您一个如何设置验证HTTP签名的Hyper服务器的总体概念。这不是实际可运行的代码。
const PHRASE: &str = "Hewwo, Mr. Obama???";
fn main() -> Result<(), Box<dyn Error> {
let mut key_file = File::open("../../tests/assets/public.der")?;
let mut key_file_vec = Vec::new();
key_file.read_to_end(&mut key_file_vec)?;
let key_arc = Arc::new(key_file_vec);
let service = move || {
let key = Arc::clone(&key_arc);
service_fn(move |req: Request<Body>| {
let verified = req.verify_signature_header(VerifyKey::unchecked_from_slice(&key));
verified
.into_future()
.map_err(|e| format!("{:?}", e))
.and_then(|_| {
println!("Succesfully verified request!");
Response::builder()
.header(CONTENT_LENGTH, PHRASE.len() as u64)
.body(Body::from(PHRASE))
.map_err(|e| format!("{:?}", e))
})
})
};
let addr = "127.0.0.1:3000".parse()?;
let server = Server::bind(&addr)
.serve(service)
.map_err(|e| eprintln!("server error: {}", e));
rt::run(server);
Ok(())
}
使用Reqwest
将其添加到您的Cargo.toml
[dependencies.http-signatures]
version = "0.7"
default-features = false
features = ["use_reqwest"]
在您的代码中,按照以下方式构建请求时使用它。
let key_id = "some-username-or-something".into();
let client = Client::new();
let mut req = client.get("https://127.0.0.1:8000").build()?;
req.with_authorization_header(key_id, CreateKey::rsa(private_key, ShaSize::SHA512))?;
let res = client.execute(req)?;
使用Rocket
将其添加到您的Cargo.toml
[dependencies.http-signatures]
version = "0.7"
default-features = false
features = ["use_rocket"]
在您的代码中,像这样在路由中使用它
struct Verified;
impl<'a, 'r> FromRequest<'a, 'r> for Verified {
type Error = ();
fn from_request(request: &'a Request<'r>) -> Outcome<Verified, ()> {
let res = request
.guard::<State<Vec<u8>>>()
.succeeded()
.ok_or(())
.and_then(|key| {
request
.verify_authorization_header(VerifyKey::unchecked_from_slice(&key))
.map_err(|e| println!("Error: {:?}", e))?;
Ok(Verified)
});
match res {
Ok(verified) => Success(verified),
Err(fail) => Failure((Status::Forbidden, fail)),
}
}
}
#[get("/")]
fn index(_verified: Verified) -> &'static str {
"Successfully verified request"
}
fn main() -> Result<(), Box<dyn Error> {
let mut key_file = File::open("../../tests/assets/public.der")?;
let mut key_vec = Vec::new();
key_file.read_to_end(&mut key_vec)?;
rocket::ignite()
.mount("/", routes![index])
.manage(key_vec)
.launch();
Ok(())
}
贡献
请注意,所有贡献给此项目的代码都将根据GPL版本3进行许可。
许可证
HTTP Signatures是自由软件:您可以在自由软件基金会发布的GNU通用公共许可证的条款下重新分发和/或修改它,许可证版本为3,或(根据您的选择)许可证的任何较新版本。
HTTP Signatures是根据GNU通用公共许可证分发的,希望它将是有用的,但没有任何保证;甚至没有关于适销性或适用于特定目的的暗示保证。有关详细信息,请参阅GNU通用公共许可证。此文件是HTTP Signatures的一部分
您应该已随HTTP Signatures一起收到GNU通用公共许可证的副本。如果没有,请参阅https://gnu.ac.cn/licenses/。
依赖项
~6–12MB
~322K SLoC