I have a program which allows another authorized user (with a password) to access someone else's computer without them having to be there. However, I don't know how to safely store the password without requesting the user reenter the password every time they launch the program. I have a few ideas, such as hashing the password and storing it to a file, but this could get cracked by a hash cracking program such as hashcat. I have read Safe ways to store passwords without hashing them and have thought about the CryptProtectData API. Would it protect the passwords from another application which is potentially malicious? Or is it on a per application basis?
-
You can make it safer, but never really safe. Your app has to read it, so someone can find those methods if they know what they're doing. You can make it a little safer by using the user machine's serial number as the key (or part of the key). (Windows provides a method that is partially based on this... the idea is to read a unique id from the hardware.) This is only safer in the case where someone gets the stored data but isn't able to execute code to read your serial number. (or peek at your memory...)– browsermatorCommented May 21, 2021 at 18:02
2 Answers
Would it protect the passwords from another application which is potentially malicious?
No
DPAPI (of which CryptProtectData
is a part) cannot protect against a malicious application running under the same user. This is because any application running under the same user can request decryption of a DPAPI encrypted blob. It is possible to give DPAPI some additional entropy while requesting encryption, and then only an application that knows the additional entropy will be able to decrypt the blob, but you run into the original issue again. Where do you store the additional entropy, such that a malicious application cannot access it?
The only situation in which DPAPI offers any real security is if you're device gets stolen (or confiscated by some authorities) and you don't have FDE. In this case, provided that your Windows password is strong enough to resist bruteforce, the stored DPAPI encrypted data cannot be read.
In the end, it's just as @Polynomial says in the linked answer:
Any procedure you choose to obfuscate passwords is an exercise in futility against any half-determined attacker, so at most you're creating an illusion of security.
I have a few ideas, such as hashing the password and storing it to a file
The main problem here isn't that the hash can be cracked, it is that cryptographic hashes are irreversible. So when you need to log in, you won't be able to recover the password from the hash. If you design the application to send the hash instead of the password, the hash effectively becomes the password, and you're back to storing it as plaintext.
Edit: As clarified by OP in comments, the application in question is the server, not the client. For a server, there is absolutely no reason you should store the password in a reversible format. Hash it with a strong password hash like bcrypt or Argon2id and store the hash only. (Warning: Do not try to implement the hash functions yourself. Use a well-known and tested implementation.)
-
Thanks for the insight. Wouldn't a user logging in and the app hashes it be a safe solution? My application doesn't store any data and changing the password would just be a matter of changing the hash on the file or deleting it. Commented May 21, 2021 at 17:30
-
@TheUltimateGuide If I understand correctly, your application allows a user to access another computer remotely if they have the password. If you hash the password, how are you going to send the password to the remote computer for authentication?– nobodyCommented May 21, 2021 at 17:34
-
The app has a client and a server. The server gets a password which it hashes and saves to a file. The client sends a header with a password and the server hashes it and compares the two hashes. Commented May 21, 2021 at 17:51
-
@TheUltimateGuide OK, so you are talking about the server application. I had assumed you were trying to store the password client side (the question you linked to is about a client). For a server, there is absolutely no reason you should store the password in a reversible format. Hash it with a strong password hash like bcrypt or Argon2id and store the hash only.– nobodyCommented May 21, 2021 at 17:58
The easiest solution is to use PowerShell
cmdlet Export-Clixml
.
<snippet>
Example 3: Encrypt an exported credential object on Windows
In this example, given a credential that you've stored in the $Credential
variable by running the Get-Credential
cmdlet, you can run the Export-Clixml
cmdlet to save the credential to disk.
Important
Export-Clixml
only exports encrypted credentials on Windows. On non-Windows operating systems such as macOS and Linux, credentials are exported as a plain text stored as a Unicode character array. This provides some obfuscation but does not provide encryption. PowerShell
$Credxmlpath = Join-Path (Split-Path $Profile) TestScript.ps1.credential
$Credential | Export-Clixml $Credxmlpath
$Credxmlpath = Join-Path (Split-Path $Profile) TestScript.ps1.credential
$Credential = Import-Clixml $Credxmlpath
The Export-Clixml
cmdlet encrypts credential objects by using the Windows Data Protection API. The encryption ensures that only your user account on only that computer can decrypt the contents of the credential object. The exported CLIXML
file can't be used on a different computer or by a different user.
In the example, the file in which the credential is stored is represented by TestScript.ps1.credential
. Replace TestScript with the name of the script with which you're loading the credential.
You send the credential object down the pipeline to Export-Clixml
, and save it to the path, $Credxmlpath
, that you specified in the first command.
To import the credential automatically into your script, run the final two commands. Run Import-Clixml
to import the secured credential object into your script. This import eliminates the risk of exposing plain-text passwords in your script.
</snippet>
Would it protect the passwords from another application which is potentially malicious?
Depends on the permissions granted to the potentially malicious application. If it has Administrator level permissions then no. If the malicious application can impersonate your account, or whatever credentials run this job, then it should be evident that you must address that issue first.
Or is it on a per application basis?
As the referenced page states, the file is restricted to the user and computer where the file is created. Applications on Windows systems must run in a user context and thus the importance of using the Principle of Least Privilege. If you have a potentially malicious application that can abuse user segregation, don't run it on the same system. Separate these two tasks to different systems as this will minimize risk.