Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/eopb/redact

A simple library for keeping secrets out of logs
https://github.com/eopb/redact

Last synced: 3 months ago
JSON representation

A simple library for keeping secrets out of logs

Awesome Lists containing this project

README

        

# Redact

[![License](https://img.shields.io/crates/l/redact.svg)](https://crates.io/crates/redact)
[![Latest version](https://img.shields.io/crates/v/redact.svg)](https://crates.io/crates/redact)
[![Latest Docs](https://docs.rs/redact/badge.svg)](https://docs.rs/redact/)
[![downloads-badge](https://img.shields.io/crates/d/redact.svg)](https://crates.io/crates/redact)

[API docs](https://docs.rs/redact/)

A simple library for keeping secrets out of logs.

Redact provides a wrapper that prevents secrets from appearing in logs.

```rust
use redact::Secret;

let encryption_key = Secret::new("hello world");
assert_eq!("[REDACTED &str]", format!("{encryption_key:?}"))
```

The underlying secret contained within the wrapper can only be accessed using the [expose_secret][Secret::expose_secret] method or [expose_secret] function[^1].

```rust
use redact::Secret;

let encryption_key = Secret::new("hello world");
assert_eq!("hello world", *encryption_key.expose_secret())
```

The `Secret` type doubles as a useful documentation tool.
Documenting values maintainers should be careful with.

```rust
use redact::Secret;

#[derive(Debug)] // Safe since Debug is not able to "see" our `Secret`s
struct Payment {
// The recipient is PII so we don't want it to appear in logs
recipient: Secret,
// It's okay for the amount to appear in logs so we don't mark it with `Secret`
amount: u64,
}
```

## Serde support

For serde support ensure the serde feature is enabled in your `Cargo.toml`.

```toml
redact = { version = "0.1", features = ["serde"] }
```

`Deserialize` works as expected, transparently deserializing the enclosed secret.

Since serialization can expose the enclosed secret it is only possible to implement `Serialize` "with" [expose_secret].

```rust
use redact::{Secret, expose_secret};
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize)]
struct Payment {
#[serde(serialize_with = "expose_secret")]
recipient: Secret,
amount: u64,
}
```

If you would like to implement `Serialize` without exposing the `Secret` see [serde::redact_secret].

## Zeroizing `Secret`s

`redact` does not require `Secret`s to be [`Zeroize`][::zeroize::Zeroize]able but does allow `Secret`s to be `Zeroize`d when the contained secret is `Zeroize`able.
To be able to `Zeroize` `Secret`s, enable `zeroize` in your `Cargo.toml`.

```toml
redact = { version = "0.1", features = ["zeroize"] }
zeroize = "1"
```

Once enabled, it is possible zeroize secrets.

```rust
# use redact::Secret;
use zeroize::Zeroize;

fn main() {
let mut secret = Secret::new("hunter2".to_owned());

// [ ... ] use secret here

// Now that we're done using the secret, zero it out.
secret.zeroize();
# assert_ne!(*secret.expose_secret(), "hunter2")
}
```

If you would like your `Secret` to be automatically `Zeroize`d when it is no longer being used,
consider wrapping your `Secret` in [`Zeroizing`][::zeroize::Zeroizing] which will `Zeroize` your secret when it is [`Drop`]ed

```rust
# use redact::Secret;
use zeroize::Zeroizing;

fn main() {
let mut secret = Zeroizing::new(Secret::new("hunter2".to_owned()));

// [ ... ] use secret here

// The secret is automatically zeroed out at the end of the scope when it is dropped
}
```

## Comparison with alternatives

### [secrecy](https://docs.rs/secrecy/latest/secrecy/)

[Secrecy](https://crates.io/crates/secrecy) was the original inspiration for this crate and it has a similar API.

One significant difference is that secrecy requires that all secrets implement [`Zeroize`](https://docs.rs/secrecy/latest/secrecy/trait.Zeroize.html) so that it can cleanly wipe secrets from memory after they are dropped.
This unfortunately limits the types of values that secrecy can wrap in a `Secret` since every type has to be aware of `Zeroize`.

Redact relaxes this requirement, allowing all types to be `Secret`s.
When zeroizing is required, consider the techniques [above](#zeroizing-secrets).

### [secrets](https://docs.rs/secrets/latest/secrets/)

[Secrets](https://crates.io/crates/secrets) provides even stronger memory protection than [secrecy](#secrecy) using [`mlock(2)`]/[`mprotect(2)`] among other things.
If you need strong memory protection before and after a `Secret` is dropped consider [secrets](https://crates.io/crates/secrets).

[`mlock(2)`]: https://man7.org/linux/man-pages/man2/mlock.2.html
[`mprotect(2)`]: https://man7.org/linux/man-pages/man2/mprotect.2.html

[^1]: [Secret] will assume that it is safe to expose its secret to its contained types implemenations of
[Default],
[Hash],
[Copy],
[Clone],
[Ord],
[PartialOrd],
[Eq],
[PartialEq],
[std::ops::Add],
[std::ops::AddAssign],
[std::ops::BitAnd],
[std::ops::BitAndAssign],
[std::ops::BitOr],
[std::ops::BitOrAssign],
[std::ops::BitXor],
[std::ops::BitXorAssign],
[std::ops::Div],
[std::ops::DivAssign],
[std::ops::Mul],
[std::ops::MulAssign],
[std::ops::Rem],
[std::ops::RemAssign],
[std::ops::Shl],
[std::ops::ShlAssign],
[std::ops::Shr],
[std::ops::ShrAssign],
[std::ops::Sub],
[std::ops::SubAssign],
[std::ops::Neg] and
[std::ops::Not]