Inhaltsverzeichnis
Wohin nur mit den Passwörtern in Windows und Linux Skripten? - Passwörter in Skripten verschlüsselt hinterlegen.
Veröffentlicht im Red Stack Magazin der DOAG, September 2018
Sourcecode Beispiele
Beispiele im Detail auf https://github.com/gpipperr/RedStack_Magazin_2018_encrypt_password
Das Problem:
In vielen Skripten rund um die tägliche Wartung unserer Systemumgebungen müssen Passwörter hinterlegt werden. Und nicht immer kann mit der Oracle Wallet oder SSL Zertifikaten bzw. Betriebssystem Rechten ganz auf Passwörter verzichtet werden.
Wie aber diese Passwörter so schützen, dass nicht jeder sofort die Passwörter auslesen und verwenden kann?
Wie die Skripte in einer Sourcecode Verwaltung so hinterlegen, dass dort sicher keine Passwörter mehr vorkommen? Wie Passwörter auf gehosteten Server Umgebungen hinterlegen und den Sicherheits-Regularien meines Unternehmens genügen?
Gerade in Umgebungen, die in die Jahre gekommen sind, wimmelt es nur so von Passwörtern. Jede Änderung bedingt meist umfangreiche Anpassungen an vielen Stellen. Werden Skripte kopiert und weitergegeben, besteht immer die Gefahr, dass ein Passwort in die falschen Hände gerät. Besonders in gehosteten Umgebungen, auf denen das Betriebssystem vom einen Hoster mit Root Rechten verwaltet wird, sollte sich der Kunde der Gefahr mit den offenen Passwörtern in Skripten sehr bewusst sein.
Diese Passwörter stellen trotz aller Bemühung auch heute noch eines der höchsten Sicherheitsrisiken für die meisten Systeme dar.
Um dieses Risiko zu bekämpfen, sollten die folgenden Vorgaben für alle Umgebungen gültig sein:
- Kein Passwort kommt im Skript vor, nur eine Variable wird verwendet, die mit dem Passwort gefüllt wird.
- Bei einer Passwort-Änderung muss das Skript nicht angepasst werden.
- Die Passwörter sind auf dem System verschlüsselt hinterlegt.
- Die verschlüsselten Passwörter können nur auf der Zielmaschine entschlüsselt gelesen werden.
- Alles was für die Umsetzung des Konzepts benötigt wird, muss auch in veralteten, bzw. gehosteten Umgebungen ohne besondere Systemrechte möglich sein.
Und nebenbei werden so ohne großen Aufwand meist schon die wichtigsten Sicherheits-Regeln eingehalten, ohne den Betrieb mit zu hohen Aufwänden zu belasten.
Vor welchen Szenarien schützt uns die Umsetzung des Konzepts?
- Skripte können nun problemlos per Mail / Git oder Web verteilt werden, keine Passwörter gehen aus Versehen verloren.
- Die verschlüsselten Passwörter sind keinem von Nutzen, der keinen Zugriff auf dem Zielserver hat.
- Unangenehme Gespräche mit dem Security Officer in der Kantine beim Mittagessen.
Vor welchen Szenarien schützt uns das NICHT?
- Vor den neugierigen Blicken der Kollegen mit Root Zugriff auf das System! Während das Skript läuft, ist im Speicher oder der /proc Umgebung das Passwort meist mit etwas Geschick auffindbar.
- Das Passwort lässt sich auf der Maschine per Skript auslesen, der Schlüssel für das Passwort lässt sich dort aber nie so verstecken, dass keiner den Schlüssel findet, das Skript benötigt diesen ja auch.
Denn wie bei jeder Verschlüsselung ist es eigentlich egal wie komplex oder sicher der Algorithmus ist, meist kann durch ein wenig Nachdenken und Ausprobieren der Schlüssel im System selber gefunden werden.
Den Schlüssel zu verstecken gelingt den wenigsten wirklich, denken wir nur an unsere Eltern, da liegt der Schlüssel auch immer hinten am Gartenzaun unter dem Blumentopf.
Werden diese einfachen Vorgaben konsequent umgesetzt, bedeutet dies für das Unternehmen meist schon eine dramatische Verbesserung der Sicherheitslage ohne großen Aufwand und viele Schwierigkeiten im Betrieb
Wie lässt sich das ganze nun aber unter Windows und Linux so bequem wie möglich umsetzen?
Unser Werkzeugkasten:
- Das Microsoft Credential Objects in der Windows PowerShell
- Verschlüsseltes Hinterlegen von Passwörtern auf Linux Systemen mit openssl
- Oracle Features wie der Oracle Wallet
Die ideale Lösung - Keine Passwörter verwenden .-)
Und nun zuerst die ideale Lösung für das Problem, wir verwenden gar keine Passwörter mehr.
D.h. in der Regel delegieren wir diese Aufgabe einfach an das Betriebssystem der Datenbank und überlassen diesem, bzw. dem Systemadministrator der Umgebung, die ganze Verantwortung, dass alles sicher betrieben wird.
Nachteil: Wer sich am System anmelden kann kommt nun ganz ohne Passwort aus.
Sehr einfach
Sehr einfach lässt sich das Umsetzen, wenn der OS User in der DBA Gruppe ist und alle Aufgaben mit dem SYS User durchgeführt werden können.
Geht aber nur, wenn der OS User in der DBA Gruppe ist und alles mit SYS auch durchgeführt werden kann/darf/will.
Etwas besser
Etwas sicherer ist es, „External authentification“ für die Datenbankzugänge einzusetzen.
Das heißt aber das auch etwas Technik dahinter funktionieren muss, oft schwer umzusetzen in gehostenen Umgebungen in denen jeder ja froh ist das es überhaupt noch irgendwie läuft.
Siehe ⇒ https://oracle-base.com/articles/misc/os-authentication
Oracle Wallet- Secure External Passwort Store
Sehr komfortabel ist die Oracle Wallet als Secure External Passwort Store Lösung, mehr dazu unter
⇒ Secure External Passwort Store
Passwörter unter Windows schützen
Unter Windows ist das verschlüsselte Hinterlegen der Passwörter so trivial, dass jeder der es nicht nützt, sich eigentlich fast grob fahrlässig verhält.
Das Erstellen eines Passwort-Containers inkl. des Aufrufes der Pflegeoberfläche sind im Prinzip nur 2 Zeilen Code.
# PWD $db_user = "system" $oracle_credential = "$scriptpath\ORACLE_CREDENTIAL.xml" # # To store the password we use the PSCredential object # if the serialized object of the password not exists # prompt the user to enter the password # if (!(test-path -path $oracle_credential)) { $user_credential=GET-CREDENTIAL -credential "$db_user" export-clixml -InputObject $user_credential -Path $oracle_credential } else { $user_credential=Import-Clixml -Path $oracle_credential } #get the clear type password $db_password=$user_credential.GetNetworkCredential().Password
Source Code ⇒ https://github.com/gpipperr/RedStack_Magazin_2018_encrypt_password/blob/master/ms_powershell/simpleExample.ps1
Ein praktisches Beispiel siehe hier ⇒ Oracle Apex Source Code automatisch exportieren und einchecken mit Git unter Windows mit der PowerShell
Passwort über GET-CREDENTIAL eingeben
GET-CREDENTIAL -credential "oralce"
Mit
$user_credential=GET-CREDENTIAL -credential "$db_user"
erzeugen wir uns in der Variablen user_credential ein Credential Object mit unsern Password. Der Schlüssel das ganzen ist die eindeutige ID des OS.
Serialisern des Objektes mit export-clixml
Um nun unseren Passwort Store auf der Platte abzulegen (wir wollen ja nicht bei jedem Skript Aufruf das Passwort neu eingeben), serialisieren wir das Objekt mit „export-clixml -InputObject $user_credential -Path $oracle_credential”. Es entsteht eine XML Datei mit dem Objekt in einer Art BASE64 Codierung.
export-clixml -InputObject $user_credential -Path $oracle_credential
Es entsteht eine XML Datei mit den Objekt in einer Art BASE64 Codierung.
Einlesen des Passworts aus dem Store
Beim nächsten Lauf ist das Passwort bereits hinterlegt, und das Objekt wird wieder in den Speicher geladen mit „$user_credential=Import-Clixml -Path $oracle_credential„”.
$user_credential=Import-Clixml -Path $oracle_credential" geladen.
Nun kann das Passwort im Script in Klarschrift ausgelesen werden über „$db_password=$user_credential.GetNetworkCredential().Password“.
$db_password=$user_credential.GetNetworkCredential().Password
Password Dialog in der Konsole starten
Wer lieber das Password über die Console setzt, kann mit dem Registry Eintrag (HKLM:\SOFTWARE\Microsoft\PowerShell\1\ShellIds\ConsolePrompting) =$True den graphischen Dialog vermeiden.
Key setzen:
$key = “HKLM:\SOFTWARE\Microsoft\PowerShell\1\ShellIds” Set-ItemProperty $key ConsolePrompting True
Password in der Console hinterlegen:
Get-Credential cmdlet Get-Credential at command pipeline position 1 Supply values for the following parameters: Credential User: oracle Password for user oracle: ****** UserName Password -------- -------- oracle System.Security.SecureString
siehe auch:
Passwörter unter Linux sicher verwahren
Unter Linux wird das ganze etwas schwieriger. Gerade in gehosteten Umgebungen muss der Kunde mit dem Vorlieb nehmen, was der Dienstleister unter Sicherheit versteht. Das heißt meistens rein kosten optimiert zu arbeiten und wenig flexibel auf besondere Softwarewünsche wie ein aktuelles Java oder einen gcc einzugehen.
SSH und damit „openssl“ steht hier aber überwiegend zur Verfügung, bzw. es spricht sehr wenig dagegen das kostenfrei installieren zu lassen.
Damit haben wir mit „openssl“ auf Linux ein Werkzeug zur Verfügung das die kompliziertesten Verschlüsselungs-Verfahren sehr sicher beherrscht.
Jetzt müssen wir nur noch einen Schlüssel finden, der möglichst länger ist als das Passwort, um das Entschlüsseln für den Angreifer spannender zu gestalten.
Der Schlüssel muss erfüllen:
- Muss auf jeden Server dieser Welt eindeutig sein.
- Länger als das Passwort sein.
- Sollte sich nicht auf den ersten Blick erkennen lassen.
- Einfaches erzeugen/auslesen unter Linux.
Solche Schlüssel können sein:
- WWN oder UUID einer Devices, dass sich nicht so schnell ändert
- Hardware ID wie die MAC Adresse oder die Prozessor ID.
- Eine eigene Routine in c die eine eindeutige ID erzeugt.
Meist verwende ich einfach die UUID von /dev/sda1 als Schlüssel oder die Seriennummer des OS unter HP UX.
Hier ist es der Phantasie des Entwicklers überlassen durch Obfuscation das Ganze noch etwas intransparenter zu gestalten. Die Kollegen vom Support aus fernen Ländern sollten das am Ende aber noch bedienen und warten können.
Wie funktioniert das Ganze im Detail?
Das Passwort wird zu Beginn in einer Datei in Klarschrift hinterlegt und dann verschlüsselt. Das kann im Skript gleich beim nächsten Aufruf oder mit einem kleinen Hilfsskript vorab erfolgen.
„openssl“ dient im folgenden dazu die Konfigurationsdatei mit dem Passwort Store zu verschlüsseln und stellt den kompliziertesten Teil des Ganzen dar. Über folgenden Aufruf „openssl des3 -salt -in ${PWDFILE} -out ${PWDFILE}.des3 -pass pass:„${SYSTEMIDENTIFIER}„“ wird die Passwort Datei dabei verschlüsselt.
openssl des3 -salt -in ${PWDFILE} -out ${PWDFILE}.des3 -pass pass:"${SYSTEMIDENTIFIER}"
Auch hier lässt sich dann mit ein paar Zeilen Code ein Ergebnis erzielen
# password.conf.des3 PWDFILE=.password.conf export PWDFILE # etwas Eindeutiges aus der Umgebung der Maschine auslesen # Linux SYSTEMIDENTIFIER=`ls -l /dev/disk/by-uuid/ | awk '{ print $9 }' | tail -1` export SYSTEMIDENTIFIER # # Password verschlüsseln encryptPWDFile () { /usr/bin/openssl des3 -pbkdf2 -salt -in ${PWDFILE} -out ${PWDFILE}.des3 -pass pass:"${SYSTEMIDENTIFIER}" > /dev/null # Remove orignal file rm ${PWDFILE} } # Password wieder auslesen dencryptPWDFile() { /usr/bin/openssl des3 -pbkdf2 -d -salt -in ${PWDFILE}.des3 -out ${PWDFILE} -pass pass:"${SYSTEMIDENTIFIER}" > /dev/null } # Password in den Speicher laden # Falls verschlüsselte Datei vorliegt if [ -f "${PWDFILE}.des3" ]; then dencryptPWDFile # in die Umgebung einlesen . ${PWDFILE} # Klarschrift Datei wieder entfernen rm ${PWDFILE} else # Falls unverschlüsselt vorliegt, Datei verschlüsslen if [ -f "${PWDFILE}" ]; then . ${PWDFILE} encryptPWDFile else echo "no preconfiguration file =>password.conf<= found" echo "export DB_PWD=" > ${PWDFILE} echo "no preconfiguration password.conf found - edit the file =>password.conf<= and set password and start again" exit 1 fi fi # Password auf eine interne Variable kopieren und überschreiben # siehe Kasten zu den environ Problem INTERNAL_PWD=${DB_PWD} export DB_PWD=“DU_SOLLST_DAS_NICHT_LESEN“ echo "Info -- read encrypted password =>> ${INTERNAL_PWD} <<=="
Um die Sicherheit noch weiter zu erhöhen und um Spuren in der Umgebung so weit wie möglich zu verschleiern, kann das Passwort in der Datei beim Verschlüsseln zuvor noch mit einem symmetrischen Algorithmus so verschlüsselt werden, dass erst zur Laufzeit im Skript an den jeweiligen Stellen das echte Passwort daraus extrahiert daraus wird. Diese sollte dann ohne Umwege in das aufzurufende Programm hinein „gepiped“ werden. Dies ist zwar nicht deutlich sicherer, dient aber dazu auf den ersten Blick den Angreifer etwas mehr zu verwirren.
Sourcecode Beispiele
Beispiele im Detail auf https://github.com/gpipperr/RedStack_Magazin_2018_encrypt_password
Härten
Ist das nicht genug kann die Zielumgebung über Techniken wie einen Logon Trigger natürlich zusätzlich gehärtet werden.
Fazit
Auch mit diesem Konzept lässt sich in unserer Welt keine endgültige Sicherheit herstellen. Es ist aber ein wichtiger Schritt sensitiver und vor allem proaktiv mit dem Passwortproblem umzugehen.
Und das Ganze ohne besonderem Aufwand für den Betrieb mit dem Vorteil die Passwortänderungen zu zentralisieren.
Den vollständigen Source Code finden Sie auf Github unter https://github.com/gpipperr/RedStack_Magazin_2018_encrypt_password
Besonders möchte ich mich bei Martina Pippèrr und Sebastian Geddes bedanken, die geduldig geholfen haben diesen Text zu überabeiteten.
Über das Auslesen von Umgebung-Variablen in Linux
Über /proc die Laufzeit Umgebung eines Linux Prozesses auslesen
Mit entsprechenden Rechten (denken sie dabei an ihren Kollegen oder Ihren Dienstleister) kann über das /proc Dateisystem und die „environ“ Datei die gesetzte Umgebung eines Scripts ausgelesen werden. D.h. sensitive Daten wie Passwörter sollten nur so kurz wie möglich in diesem Bereich sichtbar sein!
Über diesen Weg lässt sich auch sehr einfach überprüfen, welche Umgebungs-Variablen ein Prozess (wie zum Beispiel ein Oracle Hintergrund Prozess) wirklich sieht und verwendet.
Anwendungsbeispiel:
- Prozess ID ermitteln mit „ps uafx | grep sqlplus”
- In das Proc File System wechseln „cd /proc/<processid>/“
- Über die Datei „environ“ kann nun die Umgebung des Prozesses ausgelesen werden „strings environ | grep NLS_LANG“
Quellen
MS Windows Powershell:
Linux Openssl:
Siehe zum Thema bei mir auf der Seite: