Crate for handling secrets/sensitive data?

Is there any popular crate for marking types as sensitive (e.g. to prevent accidentally printing the in your logs)?

You might be interested in https://github.com/rust-lang/rfcs/pull/2859

1 Like

Thanks. It seems focus on cryptographic data etc. while I was mostly thinking about avoiding accidentally logging stuff, like an authorization token in a http request or something. These two are somewhat connected, but I'm not sure if that rfc is trying to address that case.

As long as you key types don't implement Debug and Display (and don't have other functions that serialize the key material) it should be pretty difficult to accidentally log them.

3 Likes

But what if they're ... strings. :smiley: . It's a common occurrence in other programming langues to spot in the logs lines containing something like POST request to http://username:supersecretpassword/some.api.some.service/dosomething failed: connection timeout. I haven't tried, but I wonder if anything like could happen with popular libraries like hyper.

Would be great if Rust had some widely-adopted mechanism to prevent simple human-mistakes like this. We prevent things like naive float comparisons, why wouldn't we take care of a big-impact higher-level issue like this. :slight_smile:

Some wrappers over types, that would made them print [REDACTED] or something, until .get_sensitive is used, or something like that.

struct SafeString(String);

impl SafeString {
    fn get_sensitive(&self) -> &str {
        &self.0
    }
}

...and you can do whatever you want in Display/Debug implementations, or omit them at all.

That helps in case-by-case basis, but it's not great for interoperability. And from what I can tell, issues like this usually happen on the edge of layers (like http client library + bussiness code).

I thought about it, and struct SafeString(String); is also not great for usability.

Ideally we would have one well-recognized library, or eventually even stdlib types, that everybody use. This way we could even get a lot of convenience methods for conversions and stuff.

That's why I'm looking for existing solutions to see what's out there, before I venture on exploring something on my own.

Disclaimer: I have no idea how hyper (or any other web framework or other crates) handles key material.

In any case you will have to hope that your chosen crate doesn't log the key material, but as you said the problem for you is more the boundary between the crate and your code.
In this case I can think of 3 options:

  1. Keep the code surface with the crate as minimal as possible, possibly by creating an intermediate crate exposing the interface as you want it (with some kind of SafeStruct).
  2. Ask the crate author to change their interface and outsource the types containing keys and convince other crates of using the same types.
  3. some kind of static data flow analysis.

I would probably try to contact the crate author of one of the bigger crates that cover your use case and try to see if they already have something along these types (they contain sensitive data so I better hope they treat it as such).

Side note:
In case of 1) (which is clearly not optimal) you could even make the function that returns the wrapped key unsafe. Not because it might cause UB of any form, but just as an additional precaution it isn't called accidentally.

Please don't give this bad advice. unsafe has a very specific meaning in Rust – a warning of potential UB – which this use case does not meet. The topic of annotating security-sensitive material has been much discussed in the rust-secure-code WG.

2 Likes

I scrolled through projects in the link you provided, but from the brief descriptions I couldn't find anything that seemed to provide annotations for sensitive data.

To be honest, given the sensitivity of the data, I personally wouldn't mind using unsafe blocks to ensure that function isn't called without second thought. Is this optimal? Obviously not! But just dismissing it because it isn't optimal isn't gonna cut it if there isn't a better way to do it.

Perhaps others can recall the details. @burdges @bascule

Check out secrecy:

https://docs.rs/secrecy

Among other things, it provides a SecretString type.

2 Likes

Regarding the get_sensitive suggestion, secrecy has an ExposeSecret trait with an expose_secret method.

1 Like

Woah what?

The whole idea of wrapping security sensitive code in "unsafe" is jarring my mind.

That is certainly not what "unsafe" is for. It disables safety interlocks, exactly in the place you want safely interlocks in this case.

If you really have secret/sensitive data then put it in a container that it cannot escape from. A container where everything is under your control and will be verified to the max. Rust provides the means to create such a container with it's regular safe code. Whilst at the same time providing, automatically, a lot of the guarantees you need for that verification.

"unsafe" is what one uses to blow holes in such containers.

Back in the day when I did some work for a certain British four letter agency that had the notion of "red" and "black" data. You can imagine what that meant. The red data was handled by red code and subject to maximum scrutiny, especially that it cannot escape to the black area. Of course we had to design our hardware to physically separate red and black memory and code areas. There was no MMU on those systems back in the day and who would trust a C style compiled language to keep things in the right place in the face of programmer error.

2 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.