PowerShell und die secure Strings
2024-02-18Wie können wir mit sicheren Secure Strings arbeiten und ist es möglich, Secure Strings zu vergleichen oder wieder lesbar zu machen?
Aus diesem Grund habe ich diesen Artikel geschrieben und hoffe, einige Fragen zu Secure Strings beantworten zu können.
Sind secure strings sicher?
Die Antwort darauf hängt von der Sichtweise ab.
Die Hauptsache bei einem Secure String ist, dass er nach seiner Erstellung standardmäßig nicht für andere Benutzer nutzbar ist, was das Arbeiten mit Secure Strings relativ sicher macht.
Es gibt jedoch Methoden, um den Secure String in einen normalen String zrückzuwandeln. Das ist nicht so schlimm, wie es klingt.
Vergleichen von Secure Strings
Wenn wir ein Passwort zweimal eingeben, um sicherzustellen, dass es keine Tippfehler enthält, müssen wir die Passwörter vergleichen. Wenn wir versuchen, die beiden Secure Strings direkt zu vergleichen, funktioniert dies nicht richtig:
$sec1 = Read-Host -AsSecureString -Prompt "Enter new password"
$sec2 = Read-Host -AsSecureString -Prompt "Re-Enter new password"
$sec1 -eq $sec2
False
und das wird deutlich, wenn wir das CmdLet ConvertFrom-SecureString
verwenden:
Beide Variablen enthalten Secure String für "Test1", aber wenn wir das CmdLet ConvertFrom-SecureString
verwenden, sehen wir, dass wir zwei völlig unterschiedliche Zeichenfolgen zurückbekommen.
ConvertFrom-SecureString $sec2
01000000d08c9ddf0115d1118c7a00c04fc297eb0100000027154735e0b6d4458f51d5b42e5dc05700000000020000000000106600000001000020000000536db4dd82716b3a2e20bf608be08bcb90cbfb0be813eb0cdc167e7a15e32593000000000e800000000200002000000032cba0cc1a075c3761da819c89354c6bdcacc4476c927b27bceb87aee8000d73100000009b4b013c9e09c9379b92f134602bc32540000000d98b339cf214f40b2efcaebff2f9ccb9c339c49cba2f321238b48a4a81f930493ba39563712a14911a786f49e360c1e250426ad3efd1bdfc8a30b63edd3c010d
ConvertFrom-SecureString $sec1
01000000d08c9ddf0115d1118c7a00c04fc297eb0100000027154735e0b6d4458f51d5b42e5dc05700000000020000000000106600000001000020000000d34b04ac1456b2f4a71ab380c150fa6262e7f9dbe89c49477984af1724b489e9000000000e8000000002000020000000a10b035236fc20dca29710909ef79c27b558be621c83ead2ef30d88b469ad21910000000d56dbd8e982a83eaf98f1c83d89dd0f4400000007821a7c7178a20819da44706e2d65a9e4982b96a5b7e89111f003618116d756acf8d34234d4da88a1d24e4f0ad929d0e40b90877b5ed71aa28aef8e54efd7249
Wie wir sehen, müssen wir eine andere Methode finden, um die Secure Strings zu vergleichen.
Secure Strings zurück in Klartext konvertieren
Um die beiden Secure Strings zu vergleichen, müssen wir sie wieder in Klartext umwandeln.
Das ist viel einfacher, als du denkst.
Es gibt dafür zwei Methoden. Die erste verwendet die Methode GetNetworkCredential()
der Klasse System.Management.Automation.PSCredential
.
Die GetNetworkCredential()
Methode
$PlainPassword="TestPwd"
# Converting plain text password to a secure string
$SecurePassword = ConvertTo-SecureString $PlainPassword -AsPlainText -Force
<#
Create a pscredential object and calling method GetNetworkCredential().
Then use the Password property of the System.Net.NetworkCredential object
#>
$UnsecurePassword = (New-Object pscredential 0,$SecurePassword).GetNetworkCredential().Password
#Output the plain text password
$UnsecurePassword
oder
$PlainPassword="TestPwd"
# Converting plain text password to a secure string
$SecurePassword = ConvertTo-SecureString $PlainPassword -AsPlainText -Force
#Create a pscredential object
$credential=New-Object pscredential 0,$SecurePassword
#calling method GetNetworkCredential().Then use the Password property of the System.Net.NetworkCredential object
$UnsecurePassword = $credential.GetNetworkCredential().Password
#Output the plain text password
$UnsecurePassword
Die "universelle" Methode
$PlainPassword="TestPwd"
# Converting plain text password to a secure string
$SecurePassword = ConvertTo-SecureString $PlainPassword -AsPlainText -Force
# Copies the content of secure string into an unmanaged binary string and returns an integer pointer (System.IntPtr)
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecurePassword)
#Create a managed string and copy the binary string from unmanaged memory into it
$UnsecurePassword = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($BSTR)
# overwrite the allocated unmanaged memory with zeros then free the memory of the binary string
[Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR)
#Output the plain text password
$UnsecurePassword
Ich persönlich bevorzuge diesen Weg, da ich mit ZeroFreeBSTR
das erste kritische Objekt explizit zerstöre.
Nachdem du mit dem Klartext-Passwort gemacht hast, was du wolltest, solltest du die Variable sofort mit Remove-Variable
entfernen.
Example
function Convert-SecureStringToPlainText{
param(
[Parameter(Mandatory=$true)]
[securestring]$SecureString
)
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecureString)
# Create a managed string and copy the binary string from unmanaged memory into it
$PlainTextString = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($BSTR)
# overwrite the allocated unmanaged memory with zeros then free the memory of the binary string
[Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR)
#Output the plain text password
return $PlainTextString
}
$PasswordsEqual=$false
do {
$NewPwd=Read-Host -AsSecureString -Prompt "Enter new password"
$ReEnteredNewPwd=Read-Host -AsSecureString -Prompt "Re-Enter new password"
if((Convert-SecureStringToPlainText -SecureString $NewPwd) -eq (Convert-SecureStringToPlainText -SecureString $ReEnteredNewPwd)) {
$PasswordsEqual=$true
Remove-Variable -Name ReEnteredNewPwd -Force -Confirm:$false
} else {
Write-Host "Your passwords are not equal. Please try again" -ForegroundColor Yellow
}
} until ($PasswordsEqual)
Write-Host "Your new password has been set" -ForegroundColor Yellow