0

A while ago I wanted to deploy a service using a OCI (docker/podman) container, and I noticed to me, what seemed like a possibly distributing trend. In the build file for a lot of the containers, the password is put there in plain text in docker-compose files during the build process and stored in environment variables for the duration of the containers life.

Part of why this was disturbing too me, a while ago I presumably wanted to do something that would require a password. Not being an expert I looked for a library to handle the password part.

I came across a Rust library (it might have been this one) I recalled a note, something about storing clear text passwords in memory for a very short while, and storing salted + hashed passwords on disk only. This library claims to put passwords in encrypted memory at runtime.

I didn't like that the password was ever in plain text, but that is kind of necessary. Other than that, this seemed all good too me.

Part of the reason why, is my understanding was that passwords were to be used as cryptographic keys to decrypt encrypted information. They were only salted/hashed so they could be stored.

Back to my story about containers, not only were clear text passwords not hashed they were in clear text for a very long time for something that was going to be exposed to the internet. No problem I though, I found a way to, for the postgresql database have the password be ephemeral (except for what postgresql itself may do, and I think it hashes it). I had sort of hoped something like this would be stored in encrypted memory (wrapped in another layer of encryption). Because now, the salted/hashed password just seems like another password. Ignoring it, I went on to the next service (a well known git server), which seemed to not only require its own password but the postgresql password! And it wants to store it in plain text (though it seems to store user passwords more securley)!

After looking at the source code, I determened it would likely require modifications to the server itself to change this (and here I thought I was doing things the easy way by using a prebuilt/now modified set of containers), unless I could sort of "spoof" things on the postgresql end.

I looked into the postgresql source code, and found that the password does not seem to decrypt anything at runtime before sending a response to a request, it just

  • Checks if the password is hashed, if not it salts it with a received salt and hashes it
  • Once the password has been hashed or if the password is hashed compares it too the hashed result, if it matches it send the appropriate response to the query

This does not seem to give the sort of "mathematical" guarantee I would expect from encryption, to preserve the mathematical gaurntees I would expect something like any of the following

  • "Hey give me a password, and I will try to decrypt this, if it fails [invalid response, gibberish, etc] you don't have access"
  • "Let me compare your salt to this salt, if it matches use the password/hashed (but perhaps not salted, or differently salted) to decrypt the data
  • Or even "you make a request, I pass you encrypted data, if you have the password you can decrypt it, maybe I check against salted password first before handing it too you, ultimately a password must be entered by the client or someone with a password for different bits of info so the password wont be stored too long or this is all done in encrypted memory"

Thankfully you seem to be able to store the hashed/salted password on the git server side of things, but that leaves me thinking:

Hashed/salted passwords, used in this way just seem like another password, and if that's the case, should it not also be considered bad to store a salted password on disk as it is to store a plain text password on disk? I am not an expert but this does not seem like the level of safety or care displayed in some of the libraries I mentioned earlier, Im not sure I understand why?

An alternative might be to use a secret manager, but I have a suspicion a password will be stored there too.

I can think of complex schemes that might mitigate these things, but I kindof would expect them to be the case. Am I missing something here? why does everything store plain text or hashed+salted passwords server-side when there seems to be no mathematical guarantee of security? The security seems to be better about transporting the passwords and user passwords, but the root passwords for the applications themselves are as described.

Is it just my model? I generally assume technological measures to protect data can be overcome with enough effort, a motivated attacker can probably find some way into a server if they want. Isent the point of encryption that: even if someone gets their hands on your data the y cant read it without the key (but you sort of store it on the server?)

25
  • 2
    It is hard to understand your question. For instance, it is not clear, if the service you describe uses passwords to access other services, or is it a password that other services need to provide to access this service. Then you are writing "cryptographic keys to decrypt encrypted information". Again, it is not clear: Are you talking about authentication or about encryption? I'd suggest you to reduce the question as much as possible. If you have actually more than one question, then split it into several posts, a separate post for each question. Otherwise the question can be closed.
    – mentallurg
    Commented Feb 7 at 1:02
  • 1
    "The git server requires a password to access the postgresql database." - Then you need to provide password. It is a bad idea to put password to the image. One of better approaches is to provide password via an external source, as a so called "secret". See details in the Docker documentation.
    – mentallurg
    Commented Feb 7 at 1:23
  • 1
    I could ask "why isn't everything encrypted" - Again, this is a separate question.
    – mentallurg
    Commented Feb 7 at 1:28
  • 1
    "find their way onto the git server" - If the attacker gets access to your git server, then it depends if their can use the same account as your git server. If not, then your secrets file is safe. If the attacker can use the same account as git server, then of course the attacker will have the same access to the database as your git server, and there is no way to prevent the access.
    – mentallurg
    Commented Feb 7 at 1:44
  • 3
    @TheFloatingBrain If it's encrypted and can't be read then it's useless - and you can remove it. The problem is fundamentally that you need your app to have access to the secret. There's no way to have your cake and eat it too.
    – vidarlo
    Commented Feb 7 at 5:56

1 Answer 1

3

That is a whole lot of question+comments, so forgive me if this answer isn't quite complete...

Generally, when a password is stored in a config file or similar, it's a credential that needs to be input to something, rather than that needs to verify an input credential. Systems that verify credentials (be they passwords, API keys, whatever) should store the credentials in hashed form - the exact details differ but at a minimum they shouldn't be in plain text - because the verifier doesn't need to know the original password, just an algorithm by which it can be verified (they will see the original password when it's entered, unless there is also client-side hashing which there usually isn't, but they don't have to and should not store the actual password anywhere). However, systems that send credentials obviously need to know the credential to send; if you pre-hash it, then the hash itself de facto becomes the password and it doesn't matter what the original is (this is one reason why client-side hashing is rarely used).

Obviously, if you're distributing software that comes with a pre-installed password, you do need some way to distribute the password to the users. The usual approach for such cases is that the pre-installed password is public and you're required to change it at setup or first usage after setup, in which case it doesn't really matter if the initial/default password is stored in plain text or not, but in practice it should still be stored hashed just so there's no code path that uses unhashed credentials. Obviously it'll be documented (in plain text) somewhere, though.


There are others cases where passwords are used, other than identification. For example, they can be used to derive cryptographic keys (though it's incorrect to say they are used as keys). However, unless the password gets combined with some secret information as part of the derivation process, there's no reason (other than convenience for a human typing them out) to store them in plain text anywhere at all; it would make more sense to store the keys directly (and indeed to not use password-derived keys at all, as they are less secure than truly random keys). You say

Part of the reason why, is my understanding was that passwords were to be used as cryptographic keys to decrypt encrypted information. They were only salted/hashed so they could be stored.

but this doesn't really make sense. If the passwords are being transmitted to another system, they might need to stored in plain locally (since otherwise they can't be transmitted in the form the other party expects), but if this system is receiving passwords from elsewhere then it shouldn't store them in plain for any reason, and for purely local use you'd just want to derive keys directly instead, or else treat the user as "another system" from which they're transmitted.

To a first approximation, there's no "all of this is done in encrypted memory" option, not without dedicated security hardware. You can do the actual cryptography in security hardware, or pre-encrypt inputs using ephemeral keys, or so on, but the inputs are usually still in memory in plain text somewhere. The client would have to encrypt before sending the data (this is sometimes done, e.g. credit card numbers are sometimes transmitted this way) and then the encrypted data (password, CC#, etc.) goes into a hardware security module for decryption rather than being decrypted in system RAM. Besides, unless you're doing asymmetric encryption and the private key is only stored in the hardware security module (which is a common use of HSMs, to be sure), the decryption is stored at least for a time in plain text somewhere too.

The way to cut this confusion is to accept that, in most cases, it's not worth worrying about "what if an attacker was able read the system RAM at the exact moment that the password/decryption key is present in it?". It's not that this threat isn't worth considering, but that in most cases, it's worth accepting; the cost of avoiding it just isn't worth the marginal security gain. You're positing an attacker who generally already has access to basically everything they could want, and furthermore the attack scenario itself is unlikely (and you could more easily make security gains by making it less likely than by reducing the impact of an attacker getting to that state). Security is always a matter of tradeoffs; perfect security doesn't exist, and security measures have costs. For anything of less than literally infinite value (so, for everything), there is a finite limit to how much adding more security is worthwhile; eventually the marginal benefit is worth less than the marginal cost. In software, this tends to come pretty early; get the low-hanging security fruit out of the way and get the code into production!

3
  • thank you for your thoughtful answer! I thought the idea of the value of considering the attack being higher than actually worrying about it was interesting. One thing I wanted to add, "Part of the reason why, is my understanding was that passwords were to be used as cryptographic keys to decrypt encrypted information. They were only salted/hashed so they could be stored." What I mean by that: the password itself, yes, would be in plain text briefly (storage could be used for a sanity check before performing the work of decryption), (1/2) Commented Feb 11 at 3:08
  • but I was thinking the time period should be very short that they existed in plain text, and all computation with cleartext pw should try to be handled in volatile memory. Also I suppose the only befit I can think of to pre hashing is if you were using the same password to encrypt the database as do authentication (if the pw is hashed, cant decrypt the db, even if you defeat authentication), but this would not necessarily be the case. Thank you again for your insightful patient, and well thorough answer to my (long) question! Its appreciated (2/2) Commented Feb 11 at 3:12
  • 1
    Glad it helped! You're right about pre-hashing, incidentally; it's mostly used in zero-trust systems like online password managers, where there's only one master password (used both for authentication and for key derivation) but the password is hashed before sending it to the server so the server never sees any form of the password that is useful toward the key derivation (except by guess-and-check brute forcing). Almost nothing else uses pre-hashing; it doesn't add any useful security in most cases.
    – CBHacking
    Commented Feb 11 at 11:29

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .