10

I am learning the Pydantic module, trying to adopt its features/benefits via a toy FastAPI web backend as an example implementation.

I chose to use Pydantic's SecretStr to "hide" passwords. I know it is not really secure, and I am also using passlib for proper password encryption in DB storage (and using HTTPS for security in transit).

But this got me thinking: if there is no real security to SecretStr, what is its purpose?

I don't mean for this to sound inflammatory; Pydantic does not claim that the Secret Types are secure. The only claim they provide is this:

You can use the SecretStr and the SecretBytes data types for storing sensitive information that you do not want to be visible in logging or tracebacks.

But I do not understand this: how does SecretStr help in hiding logging or tracebacks? Can't I just make sure not to log the password at all?


Can someone provide an explanation + example to help me better understand when and how it can be helpful? I am struggling to find its real purpose... and if there is no benefit, then it is better to just use an str for the model/schema instead of SecretStr.

Mike Williamson
  • 4,915
  • 14
  • 67
  • 104
  • You can *try* to make sure not to log the password, but what if it gets passed around somewhere in a list or dictionary and logged as part of some other process? As it says, it's to prevent showing the value in logging or tracebacks by replacing the value with asterisks: https://github.com/samuelcolvin/pydantic/blob/e985857e5a9ede8d346b010a5a039aa84a089826/pydantic/types.py#L617-L618 – jonrsharpe Jul 29 '20 at 20:09
  • Yeah, @jonrsharpe, I get how it works (but I do appreciate the GitHub link). I just do not understand how this is helpful... if I have the wherewithal to make sure to use `SecretStr`, then I have the wherewithal to create unit tests that ensure the password is never being passed in any logs. What am I missing here? – Mike Williamson Jul 29 '20 at 20:29
  • 3
    That you might not want to write a whole bunch of (probably highly coupled) unit tests that none of your code or any library code that you rely on ever logs that value; making sure that if they do it's not a problem is *much* more straightforward. – jonrsharpe Jul 29 '20 at 20:34
  • Good point, fair enough. I think when I first stumbled upon `SecretStr` I was presuming it was far more powerful/cryptographically useful. When I found out it wasn't, I was unable to "think outside the box" and figure out what its real purpose was. – Mike Williamson Jul 29 '20 at 20:45

1 Answers1

19

You already answered a big part of the question yourself.

You can use the SecretStr and the SecretBytes data types for storing sensitive information that you do not want to be visible in logging or tracebacks.

I would like to add another benefit.

Developers are constantly reminded that they are working with secrets because they need to invoke .get_secret_value() to read the real value.

We might consider this as syntactic salt (analog to syntactic sugar which makes things easier). Syntactic salt makes things harder to mess up. If you would try to send a SecretStr in a response model in e.g. FastAPI, you'd need to proactively enable that functionality.

From the docs:

class SimpleModelDumpable(BaseModel):
    password: SecretStr

    class Config:
        json_encoders = {
            SecretStr: lambda v: v.get_secret_value() if v else None
         }
ctholho
  • 801
  • 11
  • 18