6 min read
Kodierung vs. Verschlüsselung: Was schützt wirklich?
Was ist der Unterschied zwischen Kodierung und Verschlüsselung? Dieser Artikel erklärt, welchen Zweck sie erfüllen und...
PowerShell-Erfolgsrezepte – die Profi-Tipps für effektives Scripting
Wie gewährleistet Windows die Sicherheit von SecureString? Tauche mit uns im zweiten Artikel noch tiefer in die Verschlüsselungsmethoden ein – wir decken plattformübergreifende Sicherheitslücken auf.
Im ersten Teil dieser Miniserie (Sicherheitsrisiken bei cross-platform Encryption mit .NET SecureString) haben wir uns mit SecureStrings beschäftigt, wie sie unter Windows automatisch verschlüsselt werden, jedoch unter Linux und macOS (ggf. unbemerkt!) unverschlüsselt bleiben.
Heute werden wir die zugrundeliegende Verschlüsselungs-API untersuchen, um zu verstehen, wie sich die Windows-Plattform von anderen unterscheidet und warum SecureStrings unter Windows sicher AES-verschlüsselt sind, während sie unter Linux und macOS jedoch nur codiert sind.
Im ersten Artikel haben wir uns verschiedene Code-Beispiele angesehen, unter anderem dieses:
$path = "$env:userprofile\mypasswords.xml"
@{
Server1 = Get-Credential -Message 'Enter password for Server 1' -UserName $env:USERNAME
Server2 = Get-Credential -Message 'Enter password for Server 2' -UserName $env:USERNAME
Server3 = Get-Credential -Message 'Enter password for Server 3' -UserName $env:USERNAME
} | Export-Clixml -Path $path
Es werden drei Anmeldeinformationen abgefragt und in einer XML-Datei gespeichert. In dieser Datei werden alle SecureStrings automatisch verschlüsselt:
<ToString>System.Management.Automation.PSCredential</ToString>
<Props>
<S N="UserName">tobia</S>
<SS N="Password">01000000d08c9ddf0115d1118c7a00c04fc297eb01000000fca013869c24324fa191f7d1f5e8d46a00000000020000000000106600000001000020000000de26f1058a814b27a481821459eea01f8ad340a87512a6be0c21f871b46e8ee6000000000e8000000002000020000000cc97abd02f4f296d16338711331f1e9893e36da5ba397a3286891b06d329ff6710000000c7f9f9af2a5d3e7b980cab7acc7b22ee400000006dfc7c22382502e9ec47eb0ea28f990807dc336f1d673a06754c9de5a794b077633217176cfa027ee180073bb42965128442c917f40a25d7150d5536e325f82f</SS>
</Props>
Du (und nur du – und nur auf dem Gerät, auf dem du die Secrets verschlüsselt hast) kannst die Secrets ganz einfach entschlüsseln. Somit sind du und dein Rechner die transparenten Secrets, die zum Schutz der sensiblen Informationen verwendet werden:
$path = "$env:userprofile\mypasswords.xml"
$mySecrets = Import-Clixml -Path $path
# Abrufen der gespeicherten Anmeldedaten
$mySecrets.Server1
# Ich bin der Besitzer, also kann ich auch immer den Klartext sehen
$mySecrets.Server1.GetNetworkCredential().Password
$mySecrets.Server2
$mySecrets.Server2.GetNetworkCredential().Passwort
$mySecrets.Server3
$mySecrets.Server3.GetNetworkCredential().Password
Alle anderen, die die XML-Datei in die Hände bekommen, haben keinen Zugriff auf die Secrets.
Hinter den Kulissen verwendet .NET nur unter Windows eine API-Schnittstelle zur Durchführung von Ver- und Entschlüsselungsoperationen, auf die auch direkt zugegriffen werden kann. Wir bilden direkt nach, was in den obigen Beispielen passiert.
Dieses Skript fordert zur Eingabe eines Secrets im Klartext auf und verschlüsselt es sicher auf der Festplatte. Es verwendet die Protect()-Methode und den CurrentUser-Datenschutzbereich: Der AES-Schlüssel wird automatisch generiert, basierend auf deiner Identität und deinem PC.
$path = "$env:temp\secret1.txt"
$secretMessage = Read-Host -Prompt 'Enter a plain text secret'
Add-Type -AssemblyName System.Security
# Text in Bytes in UTF8-Kodierung konvertieren
$bytes = [System.Text.Encoding]::UTF8.GetBytes($secretMessage)
# Bytes mit dem eingebauten Secret verschlüsseln
$bytesEncrypted = [System.Security.Cryptography.ProtectedData]::Protect($bytes, $null, [System.Security.Cryptography.DataProtectionScope]::CurrentUser)
# Bytes in Base64-Kodierung umwandeln
$string = [Convert]::ToBase64String($bytesEncrypted)
# Inhalt in Datei schreiben
Set-Content -Path $path -Value $string -Encoding UTF8
# Inhalt der Datei anzeigen
notepad $path
Das verschlüsselte Geheimnis wird im Base64-Format gespeichert und sieht ungefähr so aus:
AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAA/KAThpwkMk+hkffR9ejUagAAAAACAAAAAAAQZgAAAAEAACAAAACP381DtngZmmO7VaQSkRvSjBzQVXOxeGHYj01yQsuuxQAAAAAOgAAAAAIAACAAAADqEoinaw5VNx1F9AMdJCI67N+SbgzdrR+iK9LBgMqXXhAAAABMtA1+Stck7j4XmrgYMGpLQAAAAGsK+mzvebNhNrRWtnO/ijhmyYffw7byoGI/0pFSn45+BC7oz05XJa853Kw8PRsVouGb+umlbGVjH/6kXD0GKFA=
Verwende Folgendes, um das Secret zu entschlüsseln, ohne ein solches angeben zu müssen:
$path = "$env:temp\secret1.txt"
Add-Type -AssemblyName System.Security
# Base64 kodierten Text lesen
$base64 = Get-Content -Path $path -Encoding UTF8
# in verschlüsselte Bytes umwandeln
$bytesEncrypted = [Convert]::FromBase64String($base64)
# entschlüsseln mit eingebautem Geheimnis
$bytes = [System.Security.Cryptography.ProtectedData]::UnProtect($bytesEncrypted, $null, [System.Security.Cryptography.DataProtectionScope]::CurrentUser)
# Bytes in String umwandeln
$plaintext = [System.Text.Encoding]::UTF8.GetString($bytes)
$plaintext
Wie bei der SecureString-Serialisierung kann nur die Person, die das Geheimnis verschlüsselt hat, es entschlüsseln (auf dem PC, auf dem es verschlüsselt wurde). Jeder andere, der Zugriff auf die Datei erhält, kann sie nicht entschlüsseln.
Die direkte Verwendung von Protect() und Unprotect() bietet zusätzliche Optionen, die bei der standardmäßigen SecureString-Verschlüsselung nicht zur Verfügung stehen. Zum Beispiel kann DataProtectionScope von CurrentUser auf LocalMachine geändert werden. Das bedeutet, dass nur der PC als Secret verwendet wird, so dass alle Benutzer auf dem Rechner es entschlüsseln können, wodurch jedoch die Sicherheit gelockert wird.
In ähnlicher Weise kann die Sicherheit auch erhöht werden. Die Methoden Protect() und Unprotect() erlauben ein zusätzliches "Salt" (ein drittes Geheimnis):
Das "Salt" ist der Parameter optionalEntropy, der ein Byte-Array ist. Wenn ein Geheimnis mit optionaler Entropie geschützt wird, muss dieses "Salt" (Byte-Array oder zusätzliches Passwort) angegeben werden, um das Geheimnis zu entschlüsseln.
Wir wollen beweisen, dass die transparente SecureString-Verschlüsselung auf der zugrundeliegenden Protect()/Unprotect()-API basiert (unter Windows, aber nicht unter Linux oder anderen Plattformen):
# transparente SecureString-Verschlüsselung verwenden
$path = Join-Path -Path $env:temp -ChildPath testsecret.xml
Read-Host -Prompt 'Enter password' -AsSecureString | Export-Clixml $path
# XML-Datei öffnen
$xmlFile = [xml]::new()
$xmlFile.Load($path)
# verschlüsselten SecureString aus der Datei ausgeben
$xmlFile.objs.SS
Das Ergebnis sieht in etwa so aus:
01000000d08c9ddf0115d1118c7a00c04fc297eb01000000fca013869c24324fa191f7d1f5e8d46a00000000020000000000106600000001000020000000b49c91059f0c802dee4055cbbed6901038bf3c5436e94cce9385e7f643f86467000000000e800000000200002000000090a8c203312e7dd2b8c7273b267d27ba50ca8e1216e2b1c236037a2ba004978e1000000060298f08ff28e517b415dc35485a9faf400000005c64a32f404da2ff23b19c5771edd0dd38f95fbe2200c5e254d8c4c31fb166f1151f852f1018b2174760988fde826de6787425e82f01415ed5011cb2f5a08b47
Versuchen wir, die verschlüsselte Hex-Zeichenfolge zu entschlüsseln, die durch die automatische SecureString-Konvertierung erzeugt wurde, indem wir die API-Funktion Unprotect() direkt verwenden:
# unsere geheimen Informationen
$secureString = Read-Host -Prompt 'Enter password' -AsSecureString
# text -> Encryption (using Export-CliXml)
$path = Join-Path -Path $env:temp -ChildPath testsecret.xml
$secureString| Export-Clixml $path
# verschlüsselten Text aus der Datei abrufen
$xmlFile = [xml]::new()
$xmlFile.Load($path)
$stringFromSecureString = $xmlFile.objs.SS
# Verschlüsselung -> Text (mittels DPAPI/Unprotect())
# Hex-String in Byte-Array umwandeln
$bytesFromSecureString = for ($i = 0; $i -lt $stringFromSecureString.Length; $i += 2) {
[Convert]::ToByte($stringFromSecureString.Substring($i, 2), 16)
}
# ungeschützte (entschlüsselte) Informationen
$bytesPlain = [System.Security.Cryptography.ProtectedData]::UnProtect($bytesFromSecureString, $null, [System.Security.Cryptography.DataProtectionScope]::CurrentUser)
# Bytes in String umwandeln (Unicode-Encoding!)
$plaintext = [System.Text.Encoding]::Unicode.GetString($bytesPlain)
$plaintext
Der Test ist erfolgreich: Du gibst Klartext ein, dieser wird automatisch verschlüsselt und in XML geschrieben, und die Unprotect()-Methode der API kann den verschlüsselte Hex-String wieder in Klartext umwandeln. Beachte dabei, dass die automatische SecureString-Verschlüsselung Unicode als Textkodierung verwendet, während in den ersten Beispielen UTF8 verwendet wurde.
Kurz gesagt, du verstehst jetzt, wie SecureStrings unter Windows sicher gespeichert werden. So kannst du transparente SecureString-Verschlüsselung mit direkten Aufrufen von DPAPI-Methoden kombinieren und verwenden.
Wenn du den ersten tiefen Deep Dive in SecureString in .NET verpasst hast, der die Frage beantwortet, wie sicher deine sensiblen Daten plattformübergreifend sind, hier der Artikel zu den Risiken plattformübergreifender Verschlüsselung mit SecureString von .NET
Entfessele das volle Potenzial von PowerShell mit unserem praktischen Poster. Egal, ob frischer Einsteiger oder erfahrener Profi, dieser Spickzettel ist so konzipiert, dass du schnell die wichtigsten und am häufigsten verwendeten Cmdlets findest.
Das Poster ist zum Download und in Papierform erhältlich.
Nov 26, 2024 by Aleksandar Nikolić und Dr. Tobias Weltner
Was ist der Unterschied zwischen Kodierung und Verschlüsselung? Dieser Artikel erklärt, welchen Zweck sie erfüllen und...
Nov 26, 2024 by Aleksandar Nikolić und Dr. Tobias Weltner
Wie gewährleistet Windows die Sicherheit von SecureString? Tauche mit uns im zweiten Artikel noch tiefer in die...
Nov 18, 2024 by Aleksandar Nikolić und Dr. Tobias Weltner
Denkst du, dass dein SecureString sicher ist? Nicht auf allen Plattformen! Entdecke die Risiken der...
Tobias Weltner und Aleksandar Nikolić haben gemeinsam die Blogpost-Reihe „Tobias&Aleksandars PowerShell-Tipps“ verfasst. Deshalb möchten wir euch beide hier vorstellen:
----------------------------
Aleksandar Nikolić ist ein Microsoft Azure MVP und Mitbegründer von PowerShellMagazine.com, der ultimativen Online-Ressource für PowerShell-Enthusiasten. Mit über 18 Jahren Erfahrung in der Systemadministration ist er ein angesehener Trainer und Redner, der rund um den Globus reist, um sein Wissen und seine Fähigkeiten über Azure, Entra und PowerShell weiterzugeben. Er hat auf IT-Veranstaltungen wie Microsoft Ignite, ESPC, NIC, CloudBrew, NTK und der PowerShell Conference Europe gesprochen.
----------------------------
Tobias ist ein langjähriger Microsoft MVP und war von Anfang an an der Entwicklung von PowerShell beteiligt. Er hat die PowerShell IDE „ISESteroids“ erfunden, zahlreiche Bücher über PowerShell für Microsoft Press und O'Reilly geschrieben, die PowerShell Conference EU (psconf.eu) gegründet und trägt derzeit als Mitglied der „Microsoft Cmdlet Working Group“ zur Weiterentwicklung der PowerShell bei. Tobias gibt sein Wissen als Berater in Projekten und als Trainer in Inhouse-Schulungen für zahlreiche Unternehmen und Agenturen in ganz Europa weiter.