Skip to content

Commit

Permalink
feat: use secstr to secure the secret in memory
Browse files Browse the repository at this point in the history
  • Loading branch information
its-danny committed Aug 19, 2024
1 parent 55bfda7 commit bd33ffd
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 8 deletions.
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ futures-util = "0.3.30"
hmac = "0.12.1"
http = "1.1.0"
rand = "0.8.5"
secstr = "0.5.1"
sha2 = "0.10.8"
thiserror = "1.0.63"
tower-cookies = "0.10.0"
Expand Down
5 changes: 3 additions & 2 deletions src/surf.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use futures_util::future::BoxFuture;
use http::{Request, Response};
use secstr::SecStr;
use std::{
sync::Arc,
task::{Context, Poll},
Expand All @@ -15,7 +16,7 @@ use crate::{guard::GuardService, Error, Token};

#[derive(Clone)]
pub(crate) struct Config {
pub(crate) secret: String,
pub(crate) secret: SecStr,
pub(crate) cookie_name: String,
pub(crate) expires: Expiration,
pub(crate) header_name: String,
Expand Down Expand Up @@ -50,7 +51,7 @@ impl Surf {
pub fn new(secret: impl Into<String>) -> Self {
Self {
config: Config {
secret: secret.into(),
secret: SecStr::from(secret.into()),
cookie_name: "csrf_token".into(),
expires: Expiration::Session,
header_name: "X-CSRF-Token".into(),
Expand Down
17 changes: 11 additions & 6 deletions src/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::sync::Arc;
use base64::prelude::*;
use hmac::{Hmac, Mac};
use rand::prelude::*;
use secstr::SecStr;
use sha2::Sha256;
use tower_cookies::{Cookie, Cookies};

Expand Down Expand Up @@ -80,7 +81,10 @@ impl Token {

type HmacSha256 = Hmac<Sha256>;

pub(crate) fn create_token(secret: &str, identifier: impl Into<String>) -> Result<String, Error> {
pub(crate) fn create_token(
secret: &SecStr,
identifier: impl Into<String>,
) -> Result<String, Error> {
let random = BASE64_STANDARD.encode(get_random_value());
let message = format!("{}!{}", identifier.into(), random);
let result = sign_and_encode(secret, &message)?;
Expand All @@ -89,7 +93,7 @@ pub(crate) fn create_token(secret: &str, identifier: impl Into<String>) -> Resul
Ok(token)
}

pub(crate) fn validate_token(secret: &str, cookie: &str, token: &str) -> Result<bool, Error> {
pub(crate) fn validate_token(secret: &SecStr, cookie: &str, token: &str) -> Result<bool, Error> {
let mut parts = token.splitn(2, '.');
let received_hmac = parts.next().unwrap_or("");

Expand All @@ -112,8 +116,8 @@ fn get_random_value() -> [u8; 64] {
[42u8; 64]
}

fn sign_and_encode(secret: &str, message: &str) -> Result<String, Error> {
let mut mac = HmacSha256::new_from_slice(secret.as_bytes())?;
fn sign_and_encode(secret: &SecStr, message: &str) -> Result<String, Error> {
let mut mac = HmacSha256::new_from_slice(secret.unsecure())?;
mac.update(message.as_bytes());
let result = BASE64_STANDARD.encode(mac.finalize().into_bytes());

Expand All @@ -128,15 +132,16 @@ mod tests {

#[test]
fn create_token() -> Result<()> {
let token = super::create_token("super-secret", "identifier")?;
let secret = SecStr::from("super-secret");
let token = super::create_token(&secret, "identifier")?;

let parts = token.splitn(2, '.').collect::<Vec<&str>>();
assert_eq!(parts.len(), 2);

let message = format!("{}!{}", "identifier", BASE64_STANDARD.encode([42u8; 64]));
assert_eq!(parts[1], message);

let signature = sign_and_encode("super-secret", &message)?;
let signature = sign_and_encode(&secret, &message)?;
assert_eq!(parts[0], signature);

Ok(())
Expand Down

0 comments on commit bd33ffd

Please sign in to comment.