PowerShell Credentials and SecureStrings, Part III

In my first blog post on using secure passwords in PowerShell scripts, I explained how the .NET Framework uses strings and SecureString objects.

SecureString objects help protect against attacks that try to read sensitive values from memory. The data is encrypted while stored in memory, making it more secure than plain text strings.

I also introduced the Get PSCredential cmdlet, which prompts for a username and password and stores the password in a secure string property named Password.

An alternative, when only a secure string is required, is the Read Host command with the As SecureString option.

These cmdlets, Get PSCredential and Read Host, work well when scripts are run interactively because they prompt the user to enter required values. However, they are not suitable when running scripts as scheduled tasks, where user input is not possible.

In scheduled scenarios, the password must be stored securely. The ConvertFrom SecureString command is used to convert a secure string into an encrypted format that can be saved to a file using Set Content.

The ConvertTo SecureString command can then be used to read the encrypted value from the file and convert it back into a secure string. This allows it to be used with credential objects or other commands that require secure input.

ConvertFrom SecureString offers three ways to convert a secure string into an encrypted string that can be stored in a file. The default behavior uses the Windows data protection API to encrypt the value.

This method is very secure, but it only works for the same user account on the same computer where the encryption was created.

In this post, we will explore alternative ways to securely store passwords in scripts and files that can be used in automated scheduled tasks. These methods remove the limitation of being tied to a single user or machine.

We will also discuss the other two encryption options available in ConvertFrom SecureString.

–Key and –SecureKey Parameters

ConvertFrom SecureString and ConvertTo SecureString have two parameters that can change their default behavior. These parameters are SecureKey and Key. The SecureKey parameter accepts a secure string value, while the Key parameter accepts a byte array.

You use –SecureKey with a SecureString memory object that encrypt and decrypt the other SecureString.  This does not really help us in our goal of storing secure passwords and accessing them through automation.  You would need a SecureString object built, either by unencrypting another string using anotheroption, or by having someone type the SecureString interactively.   The first does not solve the problem of it being secured, the second does not solve the automation problem.

The Key parameter allows you to use a 128-bit, 192-bit, or 256-bit key and uses the Advanced Encryption Standard AES, also known as the Rijndael cipher, to encrypt and decrypt a secure string. It is a symmetric encryption method, which means the same key is required for both encryption and decryption.

One possible approach is to store the key inside the script file. However, this is not recommended because it offers little security compared to storing a password in plain text. It also makes it difficult to update the key or password regularly.

A better approach is to store the key in a separate file instead of keeping it within the script along with the encrypted password.

Use NTFS permissions to secure the file with the key so that only the users you want to use the key and access it.  Even better would be to use Encrypting File System to encrypt the key file and share to only the user accounts that should be able to access it.  You can then create a new file with a new key whenever you like and use the key to re-encrypt the password.  Of course, re-encrypt the password to a new password whenever the password changes.  To increase the security (a little, as it’s a “security by obscurity” trick), store the password file and key file in separate locations.  Here is what that codemylook like (notice at the end we get a SecureString back):

PowerShell Capture password as Secure String & Encrypt

You should always get a SecureString back, but if the wrong key was used, then the password will be wrong and authentication in your scripts will not work.  This is exactly what you want.

Other Options to Protect Passwords

Of course, this is less secure than still other solutions.   As mentioned in the 2nd blog post on this subject, 3rd party solutions can often be easier and more secure to implement.  Another option is to use Public Key Infrastructure PKI to encrypt the key file.  This method uses Public Keys and certificates to encrypt the key file.  You would encrypt a new copy of the key file for each user that would need to access the key to decrypt the password.  To use thismethodyou would use objects inthe .NET Framework and trusted certificates.  This is a more complicated solution requiring a built out PKI infrastructure.  I may present that method in another blog post.

Additional Considerations

I would encourage you to use the AllSigned PowerShell script execution policy and digitally sign all your scripts.  While this requires additional configuration and obtaining a Class 3 Microsoft Authenticode Code Signing certificate, it can add an important additional security mechanism.  Your password security does not matter much if someone can just alter your scripts that are configured to decrypt the password and run.  They could put in whatever code they wanted to do what they wanted and when your script executes as a job that you have alreadyschedule, then they have accomplished what they want.  If you sign your scripts, PowerShell validates the signature.  Validating digital signatures verifies that the file has not changed or was not signed by a trusted publisher.  If the file has been changed and not resigned then PowerShell will find the script invalid and will not run it.  Denial-of-service attack?  Sure, but it is a lot better than running whatever code the attacker wants.

I hope you have found this series of blog posts useful and interesting.