SecureStrings in PowerShell

Thu, Jun 1, 2006 2-minute read

When you use any string in the CLR, it retains that string so that it can efficiently reuse it later.  Unlike most .Net data, unused strings persist even through garbage collection cycles.  While this data is in memory, there is always the chance that it could get captured in a crash dump, or swapped to disk in a paging operation. Because some data (such as passwords, and other confidential information) may be sensitive, the .Net framework includes the SecureString class – a container for text data that the CLR stores in memory in an encrypted form.  Code that needs to interact with the plain text data inside of a SecureString does so as securely as possible.

When a cmdlet author asks you for sensitive data (i.e.: a password,) the best practice is to designate that password parameter as a SecureString in order to help keep your password confidential.   You can supply the parameter with a SecureString variable as input, or the host prompts you for the SecureString if you do not provide one.  We also have two cmdlets (ConvertTo-SecureString and ConvertFrom-SecureString) that allow you to round-trip this data to disk in a secure fashion.

By default, the SecureString cmlets use Windows’ Data Protection API when they convert your SecureString to and from a plain text representation.  The encryption key is based on your Windows logon credentials, so only you can decrypt the data that you’ve encrypted.  If you want the exported data to work on another system or separate user account, you can use the parameter sets that let you provide an explicit key.  PowerShell treats the data as an opaque blob – and so should you.

However, there are many instances when you may want to automatically provide the SecureString input to a cmdlet, rather than have the host prompt you for it.  In these situations, the ideal solution is to import a previously exported SecureString from disk (using ConvertTo-SecureString.)  This retains the confidentiality of your data, and still allows you to automate the input. 

If the data is highly dynamic (ie: coming from a CSV,) then the best approach is

$secureString = ConvertTo-SecureString "Kinda Secret" -AsPlainText –Force

The Cmdlet requires the Force parameter to ensure you acknowledge the fact that PowerShell cannot protect plain text data – even after you’ve put it in a SecureString.

The new –AsPlainText parameter set doesn’t exist in RC1, so the equivalent function is:

function New-SecureString([string] $plainText)
{
   $secureString = new-object System.Security.SecureString

   foreach($char in $plainText.ToCharArray())
   {
      $secureString.AppendChar($char)
   }

   $secureString
}

[Edit: Fixed typo]