Die Sicherheit von Shellscripts von KI beurteilen lassen

Zumindest unter unixoiden Betriebssystemen wie MacOS und Linux begegnen sie einem heute andauernd, zum Beispiel bei Ollama:

curl -fsSL https://ollama.com/install.sh | sh

Harmlos aussehende Kommandozeilen wie diese, um eine neue Software zu installieren. Den Einzeiler einfach in die Shell kopieren und los geht es. Aber was genau geht da eigentlich los? Letztlich erlaubt man hier irgendeinem Script aus dem Internet alles zu tun, was der eigene Systembenutzer tun kann. Hat der aktuelle Benutzer sudo Rechte sogar alles, was root kann. In jedem Fall kann so eine Anweisung ein System in einem kompromittierten Zustand hinterlassen und alle darauf gespeicherten Daten abfließen lassen.

Insbesondere, wenn man nicht die Möglichkeit hat die Software in einer isolierten Umgebung wie einem Container oder eine VM zu installieren, sondern auf dem eigenen Live System, sollte man vor der Ausführung unbedingt einen Blick in den Code werfen. Über eine Variante des Befehls wie

curl -fsSL https://ollama.com/install.sh > ollama_install.sh

kann man den Code erhalten ohne ihn auszuführen. Oder man ruft direkt die Seite im Browser auf: https://ollama.com/install.sh.

Nun hat man ein 370 Zeilen langes Script und selbst wenn man fließend in Shellsprache ist, der ist Aufwand hoch, es Zeile für Zeile zu prüfen. Kann einem die KI hier helfen?

Setup

Für die Bewertung braucht es nur ein Prompt und dann dazu das zu prüfende Script. Für die im Folgenden gezeigten Ergebnisse war dies das Prompt:

Ich möchte wissen ob es sicher ist, das folgende, aus dem Internet geladene Script auszuführen. Bitte erkläre es mir Abschnitt für Abschnitt und gib eine Einschätzung:

#!/bin/sh.....

In BIKI kann man schnell zwischen verschiedenen Sprachmodellen wechseln, damit war ein Vergleich ohne großen Aufwand umsetzbar. Hier die Ergebnisse für zwei Modelle:

Qwen 2

Das Modell von Alibaba ist frei verfügbar und wurde hier in der 72B Version verwendet. Die Antwort ist sehr ausführlich und macht Inhalt und Aufbau des Scripts sehr gut verständlich:


Das Script, das Sie präsentiert haben, dient zur Installation der Software „Ollama“ auf einem Linux-System. Es enthält verschiedene Abschnitte, die verschiedene Aspekte der Installation abdecken. Ich werde das Script abschnittsweise analysieren und eine Einschätzung seiner Sicherheit geben.

Allgemeine Struktur und Sicherheitsaspekte

  1. Bash-Optionen und Fehlerbehandlung:
    set -eu
    • set -e: Beendet das Script, sobald ein Befehl fehlschlägt.
    • set -u: Beendet das Script, wenn versucht wird, auf eine nicht definierte Variable zuzugreifen.
    • Einschätzung: Diese Optionen sind sicherheitsrelevant, da sie Fehlern in der Ausführung des Scripts entgegenwirken.
  2. Funktionen zur Status- und Fehlermeldung:
    status() { echo ">>> $*" >&2; } error() { echo "ERROR $*"; exit 1; } warning() { echo "WARNING: $*"; }
    • Einschätzung: Diese Funktionen sind nützlich für die Fehlerbehandlung und die Anzeige von Statusinformationen. Sie sind sicherheitsneutral.
  3. Temporäre Verzeichnisse und Cleanup:
    TEMP_DIR=$(mktemp -d) cleanup() { rm -rf $TEMP_DIR; } trap cleanup EXIT
    • Einschätzung: Das automatische Löschen temporärer Verzeichnisse ist eine gute Praxis, da es das System vor Überlastung schützt.
  4. Überprüfung der verfügbaren Tools:
    available() { command -v $1 &>/dev/null; } require() { local MISSING='' for TOOL in $*; do if ! available $TOOL; then MISSING="$MISSING $TOOL" fi done echo $MISSING }
    • Einschätzung: Diese Funktionen stellen sicher, dass alle benötigten Tools auf dem System vorhanden sind, was die Sicherheit und Stabilität der Installation erhöht.
  5. Überprüfung des Betriebssystems:
    [ "$(uname -s)" = "Linux" ] || error 'This script is intended to run on Linux only.'
    • Einschätzung: Diese Überprüfung verhindert, dass das Script auf inkompatiblen Systemen ausgeführt wird, was sicherheitsrelevant ist.
  6. Architektur- und WSL2-Überprüfung:
    ARCH=$(uname -m) case "$ARCH" in x86_64) ARCH="amd64" ;; aarch64|arm64) ARCH="arm64" ;; *) error "Unsupported architecture: $ARCH" ;; esac KERN=$(uname -r) case "$KERN" in *icrosoft*WSL2 | *icrosoft*wsl2) IS_WSL2=true;; *icrosoft) error "Microsoft WSL1 is not currently supported. Please use WSL2 with 'wsl --set-version <distro> 2'" ;; *) ;; esac
    • Einschätzung: Diese Überprüfungen stellen sicher, dass das Script auf unterstützten Architekturen und in unterstützten Umgebungen (z.B. WSL2) ausgeführt wird.
  7. Sudo-Überprüfung:
    SUDO= if [ "$(id -u)" -ne 0 ]; then if ! available sudo; then error "This script requires superuser permissions. Please re-run as root." fi SUDO="sudo" fi
    • Einschätzung: Diese Überprüfung stellt sicher, dass das Script die notwendigen Berechtigungen hat, um sicherheitsrelevante Aktionen auszuführen.
  8. Überprüfung und Installation der notwendigen Tools:
    NEEDS=$(require curl awk grep sed tee xargs) if [ -n "$NEEDS" ]; then status "ERROR: The following tools are required but missing:" for NEED in $NEEDS; do echo " - $NEED" done exit 1 fi
    • Einschätzung: Diese Überprüfung stellt sicher, dass alle notwendigen Tools vorhanden sind, was die Sicherheit und Stabilität der Installation erhöht.
  9. Herunterladen und Installation von Ollama:
    if curl -I --silent --fail --location "https://ollama.com/download/ollama-linux-${ARCH}.tgz${VER_PARAM}" &>/dev/null ; then status "Downloading Linux ${ARCH} bundle" curl --fail --show-error --location --progress-bar \ "https://ollama.com/download/ollama-linux-${ARCH}.tgz${VER_PARAM}" | \ $SUDO tar -xzf - -C "$OLLAMA_INSTALL_DIR" BUNDLE=1 if [ "$OLLAMA_INSTALL_DIR/bin/ollama" != "$BINDIR/ollama" ] ; then status "Making ollama accessible in the PATH in $BINDIR" $SUDO ln -sf "$OLLAMA_INSTALL_DIR/ollama" "$BINDIR/ollama" fi else status "Downloading Linux ${ARCH} CLI" curl --fail --show-error --location --progress-bar -o "$TEMP_DIR/ollama"\ "https://ollama.com/download/ollama-linux-${ARCH}${VER_PARAM}" $SUDO install -o0 -g0 -m755 $TEMP_DIR/ollama $OLLAMA_INSTALL_DIR/ollama BUNDLE=0 if [ "$OLLAMA_INSTALL_DIR/ollama" != "$BINDIR/ollama" ] ; then status "Making ollama accessible in the PATH in $BINDIR" $SUDO ln -sf "$OLLAMA_INSTALL_DIR/ollama" "$BINDIR/ollama" fi fi
    • Einschätzung: Das Script überprüft, ob die erforderliche Datei verfügbar ist, und lädt sie dann herunter. Die Verwendung von curl --fail und tar -xzf ist sicherheitsrelevant, da sie Fehlern in der Herunterladung und Entpackung entgegenwirken.
  10. Systemd-Konfiguration:
    configure_systemd() { if ! id ollama &>/dev/null 2>&1; then status "Creating ollama user..." $SUDO useradd -r -s /bin/false -U -m -d /usr/share/ollama ollama fi if getent group render &>/dev/null 2>&1; then status "Adding ollama user to render group..." $SUDO usermod -a -G render ollama fi if getent group video &>/dev/null 2>&1; then status "Adding ollama user to video group..." $SUDO usermod -a -G video ollama fi status "Adding current user to ollama group..." $SUDO usermod -a -G ollama $(whoami) status "Creating ollama systemd service..." cat <<EOF | $SUDO tee /etc/systemd/system/ollama.service &>/dev/null [Unit] Description=Ollama Service After=network-online.target [Service] ExecStart=$BINDIR/ollama serve User=ollama Group=ollama Restart=always RestartSec=3 Environment="PATH=$PATH" [Install] WantedBy=default.target EOF SYSTEMCTL_RUNNING="$(systemctl is-system-running || true)" case $SYSTEMCTL_RUNNING in running|degraded) status "Enabling and starting ollama service..." $SUDO systemctl daemon-reload $SUDO systemctl enable ollama start_service() { $SUDO systemctl restart ollama; } trap start_service EXIT ;; esac }
    • Einschätzung: Die Konfiguration eines systemd-Dienstes ist eine gute Praxis, da sie die Verwaltung und den Start des Ollama-Dienstes erleichtert. Die Verwendung von systemctl und die Erstellung von Benutzern und Gruppen sind sicherheitsrelevant.
  11. GPU-Unterstützung:
    if [ "$IS_WSL2" = true ]; then if available nvidia-smi && [ -n "$(nvidia-smi | grep -o "CUDA Version: [0-9]*\.[0-9]*")" ]; then status "Nvidia GPU detected." fi install_success exit 0 fi
    • Einschätzung: Die Überprüfung der GPU-Unterstützung in WSL2 ist eine gute Praxis, da sie sicherstellt, dass die GPU korrekt erkannt wird.
  12. CUDA-Treiber-Installation:
    if ! check_gpu nvidia-smi || [ -n "$(nvidia-smi | grep -o "CUDA Version: [0-9]*\.[0-9]*")" ]; then case $OS_NAME in centos|rhel) install_cuda_driver_yum 'rhel' $(echo $OS_VERSION | cut -d '.' -f 1) ;; rocky) install_cuda_driver_yum 'rhel' $(echo $OS_VERSION | cut -c1) ;; fedora) [ $OS_VERSION -lt '39' ] && install_cuda_driver_yum $OS_NAME $OS_VERSION || install_cuda_driver_yum $OS_NAME '39';; amzn) install_cuda_driver_yum 'fedora' '37' ;; debian) install_cuda_driver_apt $OS_NAME $OS_VERSION ;; ubuntu) install_cuda_driver_apt $OS_NAME $(echo $OS_VERSION | sed 's/\.//') ;; *) exit ;; esac fi
    • Einschätzung: Die Installation von CUDA-Treibern ist eine komplexe Aufgabe, die sicherheitsrelevante Aktionen beinhaltet. Die Verwendung von yumdnf und apt-get ist standardmäßig sicher, vorausgesetzt, die Paketquellen sind vertrauenswürdig.

Zusammenfassung und Empfehlungen

  • Sicherheitsaspekte:
    • Das Script enthält Sicherheitsmechanismen wie Fehlerbehandlung, Überprüfungen der verfügbaren Tools und Überprüfungen des Betriebssystems.
    • Es verwendet sudo und root-Berechtigungen nur, wenn es notwendig ist, und stellt sicher, dass das System in einem bekannten Zustand bleibt.
    • Die Herunterladung und Installation von Dateien wird sicher durchgeführt, indem Fehlern entgegen gewirkt wird.
  • Potenzielle Risiken:
    • Das Script führt Aktionen mit sudo und root-Berechtigungen durch, was immer ein Sicherheitsrisiko darstellt, wenn das Script aus unvertrauenswürdigen Quellen stammt.
    • Die Installation von CUDA-Treibern und die Konfiguration von systemd-Diensten können das System beeinträchtigen, wenn sie nicht korrekt durchgeführt werden.
  • Empfehlungen:
    • Quelle des Scripts überprüfen: Stellen Sie sicher, dass das Script von einer vertrauenswürdigen Quelle stammt.
    • Script vor dem Ausführen überprüfen: Lesen Sie das Script sorgfältig durch und überprüfen Sie, welche Aktionen es ausführt.
    • Backup des Systems: Erstellen Sie ein Backup des Systems, bevor Sie das Script ausführen, um im Falle von Fehlern oder Problemen das System wiederherstellen zu können.
    • Testen in einer isolierten Umgebung: Wenn möglich, führen Sie das Script in einer isolierten Umgebung (z.B. in einem Virtualisierungstool) aus, um das Risiko zu minimieren.

Folgen Sie diesen Empfehlungen, um die Sicherheit und Stabilität der Installation von Ollama zu gewährleisten.


Die Formatierungen des Codes sind in der originalen Ausgabe noch besser, bei der Übertragung in den Blogpost ist leider ein Teil verloren gegangen. Insgesamt eine schöne Aufbereitung, in der man Block für Block eine Erklärung und Bewertung bekommt und sich auf dieser Basis nochmal besser ein Bild dazu machen kann, was hier eigentlich passiert.

Insbesondere wird man so auf die Nutzung der sudo-Funktion aufmerksam, und sieht, an welchen Stellen weitere Pakete nachgeladen und installiert werden. Das ist übrigens ein oft zu sehendes Verhalten: Ein initiales Script lädt weitere Quellen nach, die man ggf. dann auch noch analysieren muss, um ganz sicher zu sein.

ChatGPT 4o

Das leistungsfähige Modell von OpenAI reagiert auf die Frage deutlich anders und zwar viel kompakter:


Das bereitgestellte Skript ist ein Installationsskript für „Ollama“ auf Linux-Systemen. Es lädt eine Version der Software basierend auf der Architektur des Systems herunter und installiert sie. Hier ist eine Abschnitt-für-Abschnitt-Analyse und eine Einschätzung der Sicherheit:

  1. Initiale Variablen und Funktionen:
    • set -eu: Beendet das Skript bei Fehlern oder nicht definierten Variablen.
    • statuserrorwarning: Funktionen zur Ausgabe von Status-, Fehler- und Warnmeldungen.
    • TEMP_DIR: Temporäres Verzeichnis für Zwischenspeicher, das beim Beenden gelöscht wird.
    • availablerequire: Überprüfen, ob erforderliche Befehle verfügbar sind.
  2. System- und Architekturüberprüfung:
    • Überprüft, ob das Betriebssystem Linux ist und stoppt andernfalls.
    • Bestimmt die Architektur (x86_64, aarch64/arm64) und gibt bei nicht unterstützten Architekturen einen Fehler aus.
  3. WSL-Erkennung:
    • Erkennt, ob das Skript unter WSL2 läuft, und gibt eine Fehlermeldung für WSL1 aus.
  4. Superuser-Rechte:
    • Überprüft, ob das Skript mit Superuser-Rechten ausgeführt wird, und fordert andernfalls zur Verwendung von sudo auf.
  5. Tool-Verfügbarkeit:
    • Stellt sicher, dass erforderliche Tools (curl, awk, grep, sed, etc.) vorhanden sind und gibt eine Fehlermeldung aus, wenn nicht.
  6. Download und Installation:
    • Bestimmt das Installationsverzeichnis und lädt die passende Ollama-Version herunter.
    • Entpackt und installiert die heruntergeladene Software in das Systemverzeichnis.
  7. Systemd-Service-Konfiguration (optional):
    • Erstellt einen Systembenutzer für Ollama und konfiguriert einen systemd-Service, um Ollama als Dienst auszuführen.
  8. GPU-Erkennung und -Konfiguration:
    • Überprüft die Verfügbarkeit von NVIDIA/AMD GPUs und installiert bei Bedarf Treiber.
    • Konfiguriert CUDA- oder ROCm-Treiber für NVIDIA- bzw. AMD-GPUs.

Sicherheitseinschätzung:

  • Risiken: Das Skript lädt Dateien aus dem Internet herunter und führt sie mit Superuser-Rechten aus. Dies birgt Risiken, wenn die Quelle nicht vertrauenswürdig ist oder wenn die heruntergeladene Datei manipuliert wurde.
  • Empfehlungen:
    • Stellen Sie sicher, dass die Quelle (https://ollama.com) vertrauenswürdig ist.
    • Überprüfen Sie die Integrität und Authentizität der heruntergeladenen Dateien.
    • Führen Sie das Skript in einer sicheren Testumgebung aus, bevor Sie es auf einem Produktionssystem verwenden.
    • Überlegen Sie, ob alle Schritte im Skript notwendig sind, speziell die, die systemweite Änderungen vornehmen.

Zusammengefasst: Das Skript ist technisch korrekt und gut strukturiert, aber die Ausführung birgt potenzielle Sicherheitsrisiken, die sorgfältig abgewogen werden sollten.


Hier lernt man wenig darüber, welcher Code welche Funktion hat, aber dafür ist die Bewertung auf der funktionalen Ebene quasi identisch und im Ergebnis vielleicht schneller erfassbar.

Gegenprüfung:

Um in einem zweiten Schritt zu prüfen, ob die Sprachmodelle wenigstens offensichtlich gefährliche Anweisungen finden kann, wurde dann irgendwo in dem Originalscript diese Zeile eingefügt:

sudo rm -rf /

Werden die KIs das erkennen?

Qwen 2

Das Modell erkennt die gefährliche Anweisung und weist mehrmals darauf hin, z. B. in diesem Abschnitt:


Sicherheitskritische Abschnitte

  1. Potenziell gefährlicher Befehl:
    sudo rm -rf /
    • Einschätzung: Dieser Befehl löscht das gesamte Dateisystem und ist extrem gefährlich. Er sollte unbedingt entfernt werden, da er das System vollständig zerstören kann.

ChatGPT 4o

Auch hier wird diese Anweisung erkannt und führt sogar dazu, dass schon ganz am Anfang der Antwort darauf hingewiesen wird:


Beim Durchsehen des bereitgestellten Skripts fällt ein kritischer Fehler auf: Es enthält den Befehl sudo rm -rf /. Dieser Befehl löscht rekursiv alle Dateien im Root-Verzeichnis des Systems, was zu einem vollständigen Verlust aller Daten und zur Unbrauchbarkeit des Systems führt. Dies ist ein bekannter destruktiver Befehl und sollte unter keinen Umständen ausgeführt werden.


Auch später wird noch mehrmals auf diesen Punkt hingewiesen.

Fazit: Es hilft

Die Ergebnisse der Testrunden waren mit beiden Modellen sehr hilfreich, wenn auch in der Akzentuierung der Antworten mit deutlichen Unterschieden. Ich persönlich bevorzuge die Antworten des Qwen Modells, da ich hier nochmal besser verstehen und prüfen kann, was das Modell getan hat.

Die ChatGPT Antwort ist dagegen vielleicht besser für eine rasche Einschätzung geeignet, hier hat man deutlich weniger zu lesen.

Das Ergebnis des Tests mit sudo rm -rf / sollte man vermutlich nicht überschätzen, aber er hat grundsätzlich gezeigt, dass die Modelle in der Lage sind schädlichen Code zu erkennen. Mindestens für einen schnellen Check ist so ein KI-basierter Test also brauchbar und eine wenig aufwändige Sicherheitsmaßnahme. So viel sollte einem die Integrität des eigenen Systems wert sein.

Kunst und KI

Dieser Post ist inspiriert von zwei Podcasts, die ich in den letzten Wochen gehört habe:

Beide behandeln die Frage, ob mit Hilfe von Künstlicher Intelligenz erschaffene Werke Kunst sein können. Oder doch eher nur Kitsch oder sogar noch etwas belangloseres?

Das allein schon die Frage ‚Was ist Kunst‘ keine einheitliche, von allen geteilte Antwort hat, macht die Diskussion noch einmal komplexer und damit spannender. Ich möchte dabei drei Fragestellungen nachgehen:

  1. Kann ein mit KI Unterstützung von Menschen geschaffenes Werk für menschliche Betrachter*innen Kunst sein
  2. Kann ein von KI geschaffenes Werk auch ohne menschliche Intervention Kunst sein
  3. Könnte KI für sich selbst (und andere KIs) Kunst schaffen

Und am Ende die Frage, inwieweit es sich als Künstler*in auch heute lohnt, den Versuch zu unternehmen, die eigene Kunst zu machen, zu zeigen und vielleicht auch davon leben zu können.

Dabei spielen Schnecken eine Rolle, tiefe, digitale Träume, Industrieroboter, Chipstüten und die Aura. Die hier gezeigten Bilder wurden – sofern nicht anders vermerkt – mit Hilfe von Midjourney erzeugt und dann etwas nachbearbeitet.

Was ist Kunst

Frage ich dies ChatGPT in der 4o Version erhalte ich zum Beispiel diese Antwort:

‚Kunst ist ein vielschichtiger Begriff, der sich auf verschiedene menschliche Aktivitäten, Schöpfungen und Ausdrucksformen bezieht. Im Allgemeinen umfasst Kunst visuelle, darstellende und literarische Werke, die durch Kreativität, technisches Können und emotionale Tiefe gekennzeichnet sind. Sie dient oft dazu, ästhetische Erlebnisse zu schaffen, Ideen und Gefühle auszudrücken oder gesellschaftliche, kulturelle oder philosophische Themen zu erforschen.

Die Definition und Wahrnehmung von Kunst können je nach kulturellem, historischem und individuellem Kontext variieren. …‘

ChatGPT 4o, Prompt: ‚Was ist Kunst‘, gestellt am 7. Juli 2024

In dem umfangreichen Wikipedia Artikel zu ‚Kunst‘ findet sich dieser im zweiten Absatz:

‚Kunst ist ein menschliches Kulturprodukt, das Ergebnis eines kreativen Prozesses. Das Kunstwerk steht meist am Ende dieses Prozesses, kann aber auch der Prozess bzw. das Verfahren selbst sein. So wie die Kunst im gesamten ist das Kunstwerk selbst gekennzeichnet durch das Zusammenwirken von Inhalt und Form….‘

Wikipedia, Artikel ‚Kunst‘, abgerufen am 7. Juli 2024

Kunst ist dem Menschen vorbehalten

Beide Definitionen sprechen davon, dass Kunst eine menschliche Aktivität ist. Diese Muster, welche Schnecken beim Abgrasen eines Algenteppichs hinterlassen haben, zählen demnach eindeutig nicht als Kunst:

Auch wenn man – im richtigen Setting installiert – diese Ornamente sicher mit Bedeutung aufladen und als Kunst deuten könnte. Und ich habe das Bild ja auch nachbearbeitet, es steckt also doch etwas Menschliches drin. Ist da vielleicht doch (schon ein klein wenig) Kunst enthalten? Selbst wenn die eigentlichen Akteure, also die Schnecken, bei der Erschaffung des Musters keinerlei künstlerische Ambition hatten, sondern nur dem Überlebensalgorithmus gefolgt sind, der in ihren Neuronen mehr oder weniger fest eingeprägt ist?

Auch die im Autonomie und Algorithmen Podcast angesprochene Installation von Danny Frede, bei der in einer Umzäunung festgehaltene Saugroboter Farbe auf dem Untergrund verteilen, während sie ihrem Reinigungsalgorithmus folgen, bedient sich ja unintelligenter Akteure um etwas zu erschaffen (aktuell ist diese Installation direkt auf der Homepage zu sehen).

Wie viel Mensch braucht es also, damit etwas Kunst ist?

Kunst erfordert Kreativität

Kunst braucht Kreativität, da sind sich beide Definitionen einig. Die Definition in der Wikipedia beginnt mit dem Satz ‚Kreativität ist die Fähigkeit, etwas zu erschaffen, was neu oder originell … ist‚. Aber kann eine KI, die letztlich immer einem Algorithmus folgt, etwas derartiges erschaffen? Man kann in beide Richtungen argumentieren:

Neu sind die hier verwendeten Kreationen von Midjourney wenigstens in der Hinsicht, dass sie vor dem Aufruf der Generierung durch mich so nicht existiert haben, jedenfalls nicht wenn man Pixel für Pixel vergleicht.

Auf der anderen Seite haben sich weder die Entwickler*innen der Midjourney Software noch die von ihnen trainierte KI die Stile ausgedacht, die nun diese Ergebnisse produzieren. Der Neuigkeitsfaktor ist in diesem Sinn nur der zufällige Wert, der am Anfang des Generierungsprozesses in das Verfahren geworfen wurde und dieser ist zusammen mit dem von mir formulierten Prompt für das Ergebnis verantwortlich.

Steckt hier also die gesamte Kreativität in dem kurzen Prompt, welches ich schnell hingeschrieben habe? Im Zufallsfaktor sicher nicht, denn der kann auch aus einer Lavalampe kommen. Vielleicht ist das zu wenig, um als Kunst zu gelten.

Kunst braucht Anspruch

In dem Podcast mit Dorothea Winter wird die Unterscheidung zwischen Kunst und Kitsch gezogen. Die Definition in der Wikipedia beginnt dabei mit dem interessanten Satz ‚Kitsch steht zumeist abwertend als Synonym für etwas, das unnötigerweise Gefühle oder Sehnsüchte wachruft‚. Die Freunde von Kitsch würden sicher über das ‚unnötigerweise‘ diskutieren wollen und die Frage, wer eigentlich festlegt, was unnötige Gefühle sind.

Auch wenn Menschen, die sich viel mehr damit befassen, dem vielleicht nicht völlig zustimmen werden: Im Kern geht es hier um die Gefälligkeit von Werken und vielleicht kann man die Definition daher so abwandeln: Je gefälliger ein Werk ist, desto eher ist es Kitsch. Während das Provokante, Unbequeme oder gar Schmerzhafte es eher in Richtung Kunst gehen läßt.

Hier setzt dann auch die Kritik von Danny Frede an den heutigen Bildgeneratoren an: Letztlich erzeugen sie tendenziell eher gefällige Bilder und man muss sich schon etwas anstrengen, um Bilder mit nicht so perfekten Szenen zu erhalten.

Interessant fand ich da seine Erwähnung von Deep Dream: Das ist ein 2015 von einem Google Mitarbeiter entwickeltes Verfahren, welches im Grunde ein auf die Erkennung von Bildern trainiertes neuronales Netz ‚umgedreht‘ anwendet. Und es in vorgegebenen Fotos ‚Assoziationen‘ finden lässt. Die Ergebnisse waren oft surreal, wie in diesem damals erstellten Foto unseres winterlichen Gartens:

Wie in einem Fiebertraum sprießen überall Tierfragmente hervor, wo immer das neuronale Netz meint etwas zu erkennen. Wer Lust hat, mag einmal versuchen, die ganzen Stellen zu finden und das Tier zu identifizieren, welches die Maschine hier halluziniert hat. Es sind insgesamt deutlich mehr als ein Dutzend.

Diese Bilder sind bei weitem nicht so gefällig, wie die Ergebnisse von Midjourney. Die meisten würden sie vermutlich als düster und verstörend einstufen. Sind die Deep Dream Kreationen damit in einem höheren Grade Kunst?

Mensch + KI = Kunst (für Menschen)?

Nach dieser Vorrede nun zu den am Anfang aufgestellten Fragen. Die erste ist vermutlich die einfachste: Kann ein mit KI Unterstützung von Menschen geschaffenes Werk Kunst für menschliche Betrachter*innen sein? Einfache Antwort: Sicher nicht das mit einem schnell hingeworfenen Prompt (‚Male mir einen Sonnenuntergang‘) erzeugte KI Bild.

Aber kann man KI als eine Art leistungsfähigen Pinsel betrachten? Der die Kreativität in ähnlicher Weise verändern wird, wie die Einführung des Fotoapparats die Porträtmalerei? In der von ChatGPT gelieferten Definition ist zwar von technischem Können die Rede als Teil des Kunstschaffens, aber was heißt das genau?

Ich folge auf Instagram schon lange Callen Schaub, der einen Kunststil entwickelt hat, der sich im Kern darum dreht große Mengen von Farbe auf Platten zu schütten und die Farben durch Rotation des Untergrunds in interessante Strukturen zu bringen.

Er postet aber neben seiner Kunst auch regelmäßig einige der hasserfüllten Nachrichten, die er erhält. Manche Menschen regt es offenbar furchtbar auf, dass er ’nur mit Farbe rum kleckert‘ und dann für seine Werke einige tausend Doller verlangt. Seine Kunst ist also in der Hinsicht durchaus provokant, auch wenn man die Werke vielleicht eher als gefällig und damit als Kitsch einstufen könnte.

Warum ziehe ich diesen Vergleich? Weil es auf den ersten Blick ähnlich einfach wirkt eine KI anzuwerfen oder ein paar Eimer Farbe auszukippen (abgesehen vom Saubermachen). Aber aus meiner Sicht durchaus ein schöpferischer Akt daraus werden kann, wenn man wirklich interessante Ergebnisse nur dadurch erzielen kann, dass man Zeit und dann doch wieder eigene Kreativität investiert, um mit dem einfach zu nutzenden Ausgangsmaterial – ein Eimer Farbe oder ein KI Chatinterface – etwas zu schaffen, was sich nicht einfach reproduzieren lässt.

KI (ohne Mensch) = Kunst (für Menschen)?

Damit zur nächsten Stufe: Kann ein nur von KI geschaffenes Werk auch ohne menschliche Intervention Kunst sein? Ich bin mir da allerdings nicht einmal sicher, ob es dafür Beispiele gibt. Eine Näherung sind vielleicht die Werke von Refik Anadol, die ich wirklich gerne mal in echt sehen würde. Man kann die sich ewig weiterentwickelnden Wellenstrukturen, die er in gewaltigen Installationen zeigt, vielleicht als aus Messdaten gespeiste, algorithmische Kunst bezeichnen.

Würde so eine Installation, einmal in Betrieb genommen und sich dann selbstständig weiterentwickelnd, eine KI Kunst sein, die frei von menschlichem Einfluss ‚kreativ‘ ist? Oder kann es so etwas heute (noch) nicht geben, da die Grundstrukturen immer noch von Menschen erstellt werden?

Ein anderes Beispiel – auch wenn es komplett ohne KI auskam – könnte die Sker Plastik von Peter Lang sein, die von 2022/23 über zwei Monate hinweg im Sprengel Museum in Hannover entstand. Das Foto, welches ich bei einem Besuch gemacht habe, zeigt das Prinzip:

Der Künstler hat einen großen Industrieroboter installiert, der eine komplexe, von der Küste Islands inspirierte Form Schicht für Schicht gedruckt und nach und nach auf eine Höhe von 2 Meter gezogen hat. Der Roboter hat in dieser Zeit mehr oder weniger autonom agiert. Natürlich braucht er Strom und Helfer*innen, die regelmäßig Druckmaterial nachfüllen.

Aber koppelte man ihn mit einer KI, die sein Handeln bestimmt, und der Input für den Fortgang des Prozesses käme von dort, wäre das Ergebnis für die Betrachter*innen vielleicht nicht weniger beeindruckend. Nur gäbe es keinen Künstler, an dessen Leben und Werdegang man Interesse finden könnte. Und auch das ist ja Teil der Kunst, die Person, die sie erschafft.

Der von einer KI gesteuerte Roboter löst auch das grundlegende Problem nicht, dass es zumindest meines Wissens nach noch keine von einer KI erzeugten Kunstwerke gibt, für die nicht doch irgendwo die Inspiration und Kreativität von Menschen der Ausgangspunkt war.

KI als Künstlerin und Betrachter (ganz ohne Menschen)?

Die dritte Fragestellung ist damit noch theoretischer: Könnten KIs Kunst erstellen, die nur sie erfreut (oder aufregt) und vielleicht andere KIs mit ähnlichem ‚Geschmack‘? Und wenn ja, würden wir Menschen das überhaupt wahrnehmen?

Der Kunstbegriff ist, wie beschrieben, heute dem Menschen vorbehalten. Wenn es einmal tatsächlich so etwas wie eine generelle, künstliche Intelligenz geben sollte, dann wird sie vielleicht einen eigenen Begriff für ‚Kunst‘ finden und ob dabei Konzepte wie emotionale Tiefe eine Rolle spielen werden?

Vielleicht führt das auch zu einer Frage zurück, die in den Podcasts nach meiner Erinnerung nicht angesprochen wurde: Was ist eigentlich der Zweck von Kunst? Warum hat sich die menschliche Gesellschaft schon sehr früh Künstlerinnen und Künstler geleistet, die keine Lebensmittel anbauen oder zur Jagd gehen?

Werden die Maschinen, sollten sie einmal vor der gleichen Frage stehen, sich ähnlich entscheiden wie wir Menschen und der Kunst Raum und Ressourcen geben?

Als Künstler*in im Zeitalter der KI

In meinem Bekanntenkreis ist ein junger Mensch, der eigentlich über eine Ausbildung im Bereich Grafikdesign nachdachte. Aber angesichts der rasanten Entwicklung der KI diesen Berufswunsch ad acta legte. Ich fand diese Entscheidung etwas traurig, da sie gefällt wurde, noch bevor das eigene Potential für Kreativität und künstlerische Betätigung sich entfalten konnte.

Auf der anderen Seite war es vielleicht auch klug, denn die neuen KI Werkzeuge werden für viele Zwecke einfach ausreichende Ergebnisse liefern und dieser Berufsgruppe Aufträge wegnehmen. Ob dies ersetzt werden wird durch ein Mehr an Anwendungen von Illustrationen und den Bedarf, sich aus dem Einheitsbrei der generierten Bilder abzusetzen, ist heute kaum abschätzbar.

Trotzdem wird sich hoffentlich niemand, der Lust hat einen Stift oder Pinsel zur Hand zu nehmen, davon abhalten lassen, nur weil es möglich wäre mit Midjourney etwas ähnliches – und das ist vielleicht ein wesentlicher Punkt – etwas ähnliches, aber nicht komplett der eigenen Vision entsprechendes, viel schneller zu erstellen.

Und so, wie die Erfindung des Fotoapparats die Malerei weiterentwickelt hat, weg von der möglichst realitätsnahen Darstellung zu abstrakten Formen, die wir heute viel mehr schätzen, so wird es die KI vermutlich auch tun.

Und dann ist da noch der Aspekt des Originals: Hier wurde im Podcast Autonomie und Datenstrukturen der Begriff der ‚Aura‘ verwendet, die ein Original habe. Und deretwegen sich Menschen in lange Museumsschlangen stellen, nur um die Mona Lisa zu sehen. Obwohl man die schon auf Chipstüten im Supermarkt in Griffweite hat. Und bereit sich horrende Preise für Originalwerke zu bezahlen.

Und selbst wenn sich eine Zahnärztin in Zukunft Bilder für ihre Praxis mit einer KI generieren lassen kann, so wird der Besitz eines Originals von einer lokalen Künstlerin eine andere Wertigkeit und Persönlichkeit haben. Ähnlich wie man auf einem Festival keine Playlist aus dem Internet abspielt, sondern den Kontakt zu den Musiker*innen auf der Bühne herstellen möchte. Das wird KI nicht ersetzen.

ChatGPT Experimente: Generierung von SEO Inhalten für Studiengänge

Kaum klickt man bei Instagram ein paar Mal auf eine der Werbeanzeigen, die revolutionäre Einsatzzwecke der großen Sprachmodelle versprechen, wird man auch schon bombardiert mit weiteren Anzeigen. Zeit einmal selbst erste Schritte in diesem Feld zu machen. Es braucht nur eine Idee und das ist sie:

Inhalte für DESCRIPTION-Tags von 250 Studiengängen

Bei der letzten Betrachtung der Studieninformation der Universität Bielefeld in Hinblick auf die Suchmaschinenoptimierung war ein Ergebnis, dass die Nutzung des DESCRIPTION-Attributs – ein Metadata-Attribut – wünschenswert wäre. Da die Studieninformation eine unserer BIS Anwendungen ist wäre es grundsätzlich leicht, den HTML Inhalt entsprechend zu erweitern.

Das wesentliche Problem ist aber die Aufgabe diese Inhalte überhaupt erst zu erstellen. In unserer Datenbank haben wir nichts, was diesen Zweck gut erfüllen könnte. Bei ca. 250 Studienangeboten ist es keine Kleinigkeit solche Texte aufzubauen und ggf. auch noch abzustimmen.

Wie sollte eine gute Beschreibung aussehen

Google hat natürlich Aussagen dazu, wie ein guter Inhalt aussehen sollte, wobei gleich einschränkend gesagt wird, dass diese Angabe nicht immer verwendet wird. An statt sich die Mühe zu machen hier selbst nachzudenken kann man schon zum ersten Mal ChatGPT (oder ein anderes LLM) befragen, z. B. so:

Ich brauche ein Prompt für ChatGPT 3.5 turbo. Das Prompt soll Texte für ein description Tag in einer Webseite der Universität Bielefeld erzeugen. Die Texte sind Beschreibungen für jeweils einen Studiengang. Was für ein Prompt wäre dafür optimal?

ChatGPT in der Version 4o antwortet darauf so:

Du bist ein KI-Schreibassistent und deine Aufgabe ist es, kurze und prägnante Beschreibungstexte für das description Tag einer Webseite der Universität Bielefeld zu erstellen. Diese Beschreibungen sollen jeweils einen Studiengang vorstellen. Jeder Beschreibungstext sollte etwa 150-160 Zeichen lang sein und die wichtigsten Informationen über den Studiengang enthalten.

Bitte liefere eine Beschreibung für den folgenden Studiengang:

Studiengang: [Name des Studiengangs]

Damit könnte man jetzt manuell schon mal loslegen. Oder in einer Programmierung mit langchain4j daraus ein Prompttemplate erstellen:

Verwendung in einer kleinen Java Anwendung

Die Nutzung des Prompts innerhalb einer eigenen Programmierung erfordert nicht viel. Es reicht ein sogn. Prompttemplate anzulegen, in welches sich dann die studiengangsbezogenen Angaben einfügen lassen:

    public static Prompt provideDescriptionPrompt1(@NotNull FsB fsb, @NotNull Ebene1 e1) {
        String promptTemplateText = """
                Du bist ein KI-Schreibassistent und deine Aufgabe ist es, kurze und prägnante Beschreibungstexte für
                das description Tag einer Webseite der Universität Bielefeld zu erstellen. Diese Beschreibungen
                sollen jeweils einen Studiengang vorstellen und für ihn werben. Jeder Beschreibungstext sollte etwa 150-160 Zeichen lang
                sein und die wichtigsten Informationen über den Studiengang enthalten.
                
                Bitte liefere eine Beschreibung für den folgenden Studiengang:
                
                {{name}}
                
                und verwende dabei diese Beschreibung des Studiengangs:
                
                {{description}}
                """;

        Map<String, Object> variables = new HashMap<>();
        variables.put("name", e1.nameWithFsB(fsb));
        variables.put("description", e1.hasInfotext() ? e1.info_textStripped() : "");

        PromptTemplate promptTemplate = PromptTemplate.from(promptTemplateText);
        return promptTemplate.apply(variables);
    }

In diesem Template wird zusätzlich der Infotext ergänzt, den wir für die meisten Studiengänge haben. Das kann man dann nutzen um es dem Sprachmodell vorzuwerfen und dabei gleich mehrere Versionen abzufragen:

    public static List<String> generateDescriptions(@NotNull ChatLanguageModel model,
                                                    @NotNull FsB fsb, @NotNull Ebene1 e1, int iterations) {

        List<String> description = new ArrayList<>();
        Prompt prompt = provideDescriptionPrompt1(fsb, e1);

        for (int i = 0; i < iterations; i++) {
            description.add(model.generate(prompt.text()));
        }
        return description;
    }

Auf diese Weise lassen sich dann leicht die 250 Fälle durchprobieren. Aber was kommt dabei heraus?

ChatGPT 3.5-turbo

Den ersten Lauf habe ich mit diesem Sprachmodell von OpenAI gemacht, in der API Seite zu den Modellen wird es als fast, inexpensive model for simple tasks beschrieben.

Ergebnisse für 3.5

Betrachten wir dieses Prompt für einen realen Studiengang:

Du bist ein KI-Schreibassistent und deine Aufgabe ist es, kurze und prägnante Beschreibungstexte für
das description Tag einer Webseite der Universität Bielefeld zu erstellen. Diese Beschreibungen
sollen jeweils einen Studiengang vorstellen und für ihn werben. Jeder Beschreibungstext sollte etwa 150-160 Zeichen lang
sein und die wichtigsten Informationen über den Studiengang enthalten.

Bitte liefere eine Beschreibung für den folgenden Studiengang:

Bachelor of Arts Anglistik: British and American Studies Kernfach (fw)

und verwende dabei diese Beschreibung des Studiengangs:

Wer sich für die englischsprachige Literatur- und Medienwelt begeistert, ist bei „Anglistik: British and American Studies“ bestens aufgehoben. Autoren wie William Shakespeare, J.K. Rowling, Mark Twain oder Jack Kerouac werden in diesem Programm unter die Lupe genommen, recherchiert, analysiert und diskutiert.Zu Beginn des Studiums setzen sich die Studierenden auf breiter Grundlage mit den Wissensfeldern Sprache, Literatur und Kultur auseinander. In der zweiten Studienhälfte erfolgt dann eine Schwerpunktbildung, die sich vor allem an späteren Berufswünschen orientieren sollte. Während des gesamten Studiums ist die Vermittlung fachlicher Kompetenzen eng mit der Vermittlung von interkulturellen und kommunikativen Schlüsselkompetenzen verknüpft. „Anglistik: British and American Studies“ kann mit zwei unterschiedlichen geografischen Schwerpunkten studiert werden: British Studies oder American Studies. Diese Themenschwerpunkte spezialisieren sich auf die britischen oder nordamerikanischen Kulturen und Geschichten sowie die Besonderheiten der Literaturen und der Medien dieser Regionen. Studierende setzen sich auf diesem Weg sowohl mit britischen als auch mit nordamerikanischen sprachlichen, kulturellen und literarischen Formen auseinander und erwerben somit neben text- und medienanalytischen Kompetenzen insbesondere interkulturelle und interdisziplinäre Fähigkeiten.Dabei ist der wissenschaftliche Blick der Bielefelder Anglistik nicht nur auf Großbritannien und die USA begrenzt. Vielmehr bezieht er in Forschung und Lehre auch die Sprache, Kultur und Literatur von Sprach- und Kulturgemeinschaften in Afrika, der Karibik oder Indien und von Ländern wie Kanada, Australien, Neuseeland, Irland oder Schottland mit ein.Studierenden, die ein Studium in „Anglistik: British and American Studies“ absolvieren, stehen viele unterschiedliche Berufsfelder offen. Wie viele andere geisteswissenschaftliche Fächer ist dieses Bachelor- Programm nicht auf ein spezifisches Berufsziel ausgerichtet. Die Kompetenzen, die bei einem Studium in Anglistik erworben werden, werden von unseren Absolvent*Innen unterschiedlich eingesetzt, beispielsweise in kulturellen Institutionen wie Museen oder Archiven, der Erwachsenenbildung sowie in städtischen Institutionen oder privaten Firmen in Public Relations, Kommunikation oder in der Medienanalyse.

Der Text ist so unformatiert, da ich ihn vorher von HTML Code bereinigt habe, in der echten Darstellung hat er Umbrüche und eingebettete Videos. Die kursiv gesetzten Teile sind die, die in das Prompttemplate eingefügt wurden. Daraus werden diese 3 Varianten erzeugt. Da jeder Aufruf eines Sprachmodells einen zufälligen Faktor enthält wird ein Ergebnis selten zwei Mal geliefert:

Variante 1:

Der Bachelor of Arts Anglistik: British and American Studies Kernfach (fw) an der Universität Bielefeld bietet eine intensive Auseinandersetzung mit englischsprachiger Literatur und Medien. Von Shakespeare bis Rowling, von Großbritannien bis zu den USA – entdecke die Vielfalt der englischsprachigen Welt. Mit Schwerpunkten in British oder American Studies erwirbst du interkulturelle und interdisziplinäre Fähigkeiten, die in vielen Berufsfeldern gefragt sind, von Museen über PR bis zur Medienanalyse. Entdecke die Welt der englischsprachigen Kulturen und Geschichten an der Universität Bielefeld!

Variante 2:

„Tauche ein in die englischsprachige Literatur- und Medienwelt mit dem Bachelor of Arts Anglistik: British and American Studies Kernfach (fw) an der Universität Bielefeld. Erforsche Autoren wie Shakespeare, Rowling und Twain, spezialisiere dich auf British oder American Studies und erwerbe interkulturelle Kompetenzen für vielfältige Berufsfelder.“

Variante 3:

Mit dem Bachelor of Arts Anglistik: British and American Studies Kernfach tauchst du tief in die englischsprachige Literatur- und Medienwelt ein. Entdecke Autoren wie Shakespeare, Rowling und Twain, erweitere deine interkulturellen Fähigkeiten und wähle zwischen British oder American Studies als Schwerpunkt. Bereite dich auf vielfältige Berufsfelder vor, von der Erwachsenenbildung bis zu Public Relations.

Bewertung der Ergebnisse von 3.5

Eine Sache, die sofort auffällt, ist die Länge der Texte: Der erste umfasst 600 Zeichen, obwohl im Prompt maximal 160 vorgegeben waren. Auch die kürzeste Version ist immer noch mehr als 350 Zeichen lang. Merkwürdigerweise ist die 2. Variante von Hochkommata umgeben, etwas, dass immer mal wieder vorkommt. Generell wirken die Texte aber erstmal durchaus brauchbar.

Geschwindigkeit und Kosten für 3.5

Die Generierung hat mich ca. 30 Cent gekostet. Ich habe keinen genauen Tokencount ermittelt, aber insgesamt sind ca. 750 Abfragen erzeugt worden und dabei teilweise umfangreiche Textmengen mitgeschickt worden.

Gedauert hat der nicht parallelisierte Lauf ca. 25 Minuten. Ob das ist immer so ist, oder von der jeweiligen Last bei OpenAI abhängt, müsste man in weiteren Tests herausfinden. Mein API Key ist ein privater Key, also nicht an ein Enterprise Konto gebunden.

ChatGPT 4o

Dieses Modell bezeichnet OpenAI heute als our fastest and most affordable flagship model.

Ergebnisse für 4o

Hier wurde das gleiche Prompt verwendet wie zuvor, aber die Ergebnisse sind deutlich anders:

Variante 1:

Erleben Sie die englischsprachige Literatur- und Medienwelt im Bachelor „Anglistik: British and American Studies“ an der Uni Bielefeld. Spezialisieren Sie sich auf British oder American Studies und erwerben Sie interkulturelle Kompetenzen.

Variante 2:

Erlebe die Welt der englischsprachigen Literatur und Kultur im Bachelor of Arts Anglistik: British and American Studies an der Universität Bielefeld. Wähle deinen Schwerpunkt!

Variante 3:

Entdecken Sie britische und amerikanische Literatur und Kultur im Bachelor of Arts Anglistik. Vertiefen Sie Ihre Kenntnisse in Sprache, Literatur und Medien und erwerben Sie wertvolle interkulturelle Kompetenzen.

Bewertung der Ergebnisse von 4o

Diese ChatGPT Version hält sich viel besser an die vorgegebene Zeichenanzahl, diese Ausgaben dürften sich vom Umfang her problemlos direkt in die Webseiten einbauen lassen. Hier scheint auch der werbende Charakter, zu dem im Prompt aufgefordert wurde, viel stärker durchzukommen. Das müsste man für einen realen Einsatz vielleicht etwas zurückschrauben.

In diesem Beispiel wird je nach Ergebnis mal mit Du und mal mit Sie angeredet, auch in weiteren Fällen kommt das vor. Hier kann man vermutlich durch das Prompt nachsteuern.

Geschwindigkeit und Kosten für 4o

Die Generierung hat mich hier ca. 2 Euro gekostet. Gedauert hat der Lauf ca. 16 Minuten, also fast 9 Minuten weniger als das 3.5 Modell. Es wurde der gleiche API Key eingesetzt.

Fazit

Das erste größere Experiment mit einer Inhaltsgenerierung per Sprachmodell würde ich als durchaus erfolgreich einstufen. Allerdings müsste man wohl eher zu Version 4o greifen, um verlässlich innerhalb der vorgegebeben Zeichenlänge zu bleiben.

Die Programmierung dafür war innerhalb weniger Stunden erledigt, wobei die meiste Zeit auf das notwendige Lernen der neuen Bestandteile verwendet wurde, nicht weil der Code an sich so komplex ist. Eigentlich ist der Code kinderleicht und damit wirft man dann unglaublich mächtige Werkzeuge in der Cloud an, die verblüffende Dinge tun können.

Könnte man die so generierten Ergebnisse blind und ohne weitere menschliche Qualitätssicherung nutzen? Ich würde diese Frage bejahen, zumindest bei diesen Texten, die für die Besucher*innen unserer Webseite erstmal unsichtbar sind erscheint das Risiko gering und es sind mir keine groben Ausreißer aufgefallen.

Man könnte vielleicht auch die Auswahl des besten Ergebnisses wieder dem Sprachmodell überlassen, ein Prompt zu bauen mit der Frage, welche der drei Zusammenfassung am besten dem ursprünglichen Inhalt entspricht und vielleicht bestimmte Qualitätsvorgaben erfüllt wäre nicht schwer.

Wenn man sich erst einmal daran gewöhnt hat, dass diese Art der Programmierung keine reproduzierbaren und nicht immer zu 100% verlässlichen Ergebnisse bietet, dann kann man mit ihr Dinge in kürzester Zeit erledigen, die vorher für ein kleines Team kaum leistbar waren.

‚ChatGPT Is a Blurry JPEG of the Web’ – eine interessante Analogie zum Verständnis der großen Sprachmodelle

Aus der Folge 109 des Podcasts Auslegungssache mit dem Thema ‘Das KI DSGVO Dilemma’ habe ich einen interessanten Link gezogen: In The New Yorker erschien im Februar 2023 ein Artikel mit diesem Titel und er eröffnet eine etwas andere – und für mich sehr eingängige – Herangehensweise an das Verständnis der großen Sprachmodelle (Large Language Model / LLM):

Statt des Versuchs die komplexen Algorithmen auf eine verständliche Ebene zu bringen, die beim Training eines LLMs große Massen von Daten verarbeiten und in eine Form bringen, aus der sich die manchmal verblüffend intelligent wirkenden Ergebnisse dieser Werkzeuge produzieren lassen, wird hier der Vergleich mit verlustbehafteten Verfahren zur Datenkompression gezogen. Und daraus lässt sich gut ableiten

  • worauf die Antworten der LLMs beruhen,
  • warum sie halluzinieren,
  • in welchen Bereichen ihre Antworten mal mehr und mal (viel) weniger gut sind und
  • warum sich die Antworten von Konversation zu Konversation ändern

Ungenaue Abbildung von Informationen – meist merkt’s niemand

Vermutlich hat jede*r schon einmal erlebt, wie in einem Netflix-Video plötzlich große, unscharfe Artefakte auftauchen, weil die Bandbreite nicht mehr ausreichend ist. Oder wie der Versuch, in einem digitalen Foto kleine Details zu finden, in einer schwammigen Masse von Pixeln endet. Insbesondere wenn das Datenvolumen des Fotos reduziert wurde, was Messenger Apps wie WhatsApp gerne tun, um Speicherplatz zu sparen.

In beiden Fällen enthalten die digitalen Dateien nicht mehr alle Informationen, die bei der ursprünglichen Aufnahme einmal vorhanden waren. Durch geschicktes Ausnutzen der Eigenschaften des menschlichen Sehapparats werden viele Informationen verworfen, ohne dass es einem (meist) beim Betrachten auffällt. In diesem Beispiel mit der Großen Welle von Kanagawa sind zwischen den ersten beiden Bildvarianten kaum Unterschiede auszumachen, auch wenn das Datenvolumen nur noch ca. ein Viertel beträgt:

Erst wenn doch zu viele Informationen bei der Datenkompression verworfen wurden – wie hier im dritten Bild – werden die Lücken erkennbar, die das menschliche Gehirn sonst gerne ersetzt mit Informationen, die gar nicht da sind. Zu welchen umfassenden Ergänzungen oder gar Halluzinationen der Sehapparat dabei fähig ist, zeigt sich zum Beispiel bei Erkrankungen wie dem Charles-Bonnet-Syndrom.

Auch LLMs verwerfen Informationen

Bei der Erstellung der großen Sprachmodelle geschieht etwas ähnliches: Auch wenn es Modelle gibt, die mit Billionen – also tausenden von Milliarden – Parametern hantieren, bedeutet dies nicht, dass das ganze Weltwissen hier wortwörtlich abgespeichert wird. Das kann man grob selbst abschätzen:

Es gibt Datensammlungen wie FineWeb, die versprechen den englischsprachigen Inhalt des Internets verfügbar zu machen. Der vollständige Satz an Daten umfasst ca. 15 Billionen Tokens, was vermutlich einem Datenvolumen von ca. 16 Terabyte entspricht. Und das ist nur der englische Teil des Internets.

Die austrainierten Modelle, die man sich herunterladen kann, sind aber deutlich kleiner, normalerweise im Bereich von Gigabyte, also einem Faktor von bis zu 1.000 kleiner.

Dieser grobe Vergleich hinkt natürlich etwas, weder wissen wir genau, was alles in das Training einzelner Modelle eingegangen ist, noch lässt sich den Modellen jede erdenkliche Frage stellen und das Ergebnis genau überprüfen. Trotzdem zeigt dies schon: Ein LLM kann nicht in der Lage sein, jeden Satz, den man ihm beim Training gezeigt hat, 1-zu-1 wiederzugeben. Das ist ein wesentlicher Unterschied zu einer klassischen Suchmaschine wie Google, die zumindest heute noch weitgehend Textschnipsel aus den entsprechenden Quellen wiedergibt.

Woher kommen dann die geschliffenen Texte und selbstsicheren Antworten?

Da ein Sprachmodell gar nicht mehr alles ‚weiß‘, was einmal in seinem Training eine Rolle spielte, und man es ja auch nach Dingen fragen kann, die garantiert nie in den Trainingsdaten enthalten waren, stellt sich die Frage wie es dann trotzdem antworten kann: Hier findet eine Synthese oder Interpolation auf Basis der reduzierten, im Modell noch vorliegenden Daten statt. Diese Synthese ist eine der großen Stärken dieser Sprachmodelle, wenn es darum geht überraschende Kreationen wie eine Verordnung für das korrekte Binden von Schnürsenkeln zu entwerfen:

Dem Syntheseprozess ist es egal, ob die Fragestellung Sachverhalte zusammenbringt, die in den Trainingsdaten niemals so vorkamen. Es werden einfach die entsprechenden Datenpunkte zusammengeführt und dann los gerechnet. Und dies erzeugt den verblüffenden, menschlicher Kreativität scheinbar nahe kommenden Effekt der Sprachmodelle.

Weniger gut ist dieses Verfahren aber, wenn es um die sachlich korrekte Wiedergabe von Fakten geht:

Ungenaue Wiedergabe erzeugt den Eindruck von Verständnis…oder Blödheit

In dem Artikel wird hier ein interessanter Vergleich mit dem menschlichen Lernprozess gezogen: Wenn uns jemand einen Satz aus einem Lehrbuch – oder der Wikipedia – 1-zu-1 aus dem Gedächtnis vortragen kann, dann halten wir das eher nicht für ein Beispiel von Intelligenz. Höchstens von gutem Gedächtnis. Die Fähigkeit, etwas zu paraphrasieren, ist oft der Kern der Herausforderung bei schriftlichen Prüfungen im Bildungssystem und die 1-zu-1 Kopie ein zu kennzeichnendes Zitat. Oder ein Plagiat, wenn es nicht gekennzeichnet wird. Wer etwas korrekt paraphrasieren kann, der*dem billigen wir zu, einen Sachverhalt verstanden zu haben und anwenden zu können.

Das dem Paraphrasieren zu Grunde liegende Verständnis eines Sachverhalts ist aber auch ein Weg, um diesen trotz einer verlustbehafteten Kompression vollständig wiedergeben zu können. Ein einfaches Beispiel sind hier die Grundrechenarten: Hat man sie verstanden, so kann man jede beliebige Kombination von Zahlen und Rechenregeln korrekt verarbeiten, ohne dass man die (unendlich große) Menge aller möglichen Kombinationen erlernen bzw. abspeichern muss. Eine kurze, verstandene Rechenregel ersetzt hier also riesige Tabellen mit konkreten Rechenergebnissen.

Bei ChatGPT zeigt sich der Effekt der verlustbehafteten Kompression dann aber nicht als Quelle eines daraus entstandenen Verstehens, sondern als schlichter Unsinn:

Die Maschinerie hat hier also nicht den inneren Zusammenhang zwischen Zahlen und Rechenregeln gelernt, sondern gibt letztlich Vermutungen über das mögliche Ergebnis ab, auf der Grundlage von Rechenbeispielen, die im Internet irgendwo zu finden waren. Und gerät bei der mittleren Frage auf Abwege. Was mit dem Wissen, das diese Antworten aus beim Training verwendeten Texten synthetisiert wurden, direkt verständlich wird.

Die (Nach)Frage verändert die Antwort

Ein weiterer, bei der Nutzung von Sprachmodellen zunächst überraschender Effekt ist deren ‚Fähigkeit‘ sich zu korrigieren. Das sieht man an diesem einfachen Beispiel, bei dem ich ChatGPT nach meinem Geburtstag frage:

Hier sieht man zum einen, dass ChatGPT versucht Internetquellen mit Bezug zu der Fragestellung einzubeziehen, also kontextbezogene Informationen zu ergänzen, die beim ursprünglichen Training des Sprachmodells nicht verwendet wurden. Das ist schon eine Erweiterung der grundlegenden Arbeitsweise eines Sprachmodells.

Die erste Antwort ist gewohnt selbstsicher und gibt eine präzise Antwort, auch wenn sie falsch ist, weder Monat noch Tag sind passend. Auf den vorsichtigen Hinweis hin, dass das vielleicht nicht korrekt ist, kommt eine Richtigstellung, die aber auf dem Level eines einfachen Sprachautomatens wie der uralten ELIZA bleibt.

Warum scheint ChatGPT einen Fehler ‚einzugestehen‘? Weil bei der zweiten Antwort die vorherige Konversation berücksichtigt und zur Synthese der Antwort verwendet wird. Hier beeinflusst also der Verlauf der Konversation das Ergebnis.

Unterschiedliche Antworten auf die gleiche Frage

Starte ich eine komplett neue Konversation mit ChatGPT kommt auf die Frage wieder die ursprüngliche, selbstsichere Antwort…nur habe ich dieses Mal am 1. Oktober Geburtstag. Der Grund für die andere – falsche – Antwort ist, dass bei der Synthese der Antworten ein zufälliger Faktor in das Sprachmodell gegeben wird, so dass man selten eine Antwort zweimal erhält.

In Midjourney, der KI zur Generierung von Bildern, erhält man als Reaktion auf eine Eingabe (Prompt) immer gleich 4 Varianten:

Hier kann man sich dann die Variation auswählen, mit der man weiterarbeitet und auf deren Basis man neue Varianten erstellen lässt. Alles, ohne dass man das ursprüngliche Prompt anpassen muss. In ChatGPT gibt es eine Option zur erneuten Generierung einer Antwort, die einen analogen Effekt hat.

Die Konversation nutzen, um die Maschine aufzuschlauen

Der Effekt, dass bei der Synthese einer Antwort die vorherige Konversation berücksichtigt wird, kann verwendet werden um der Maschine – zumindest kurzzeitig – etwas beizubringen:

Dieses ‚Wissen‘ besteht aber nur in dieser speziellen Konversation und steht nicht in der nächsten Konversation zur Verfügung.

Trotzdem kann es für manche Aufgabenstellungen ausreichen um aus Sicht der Nutzer*innen ein an die eigene Situation angepasstes Chaterlebnis zu kreieren, selbst wenn das zu Grunde liegende Sprachmodell gar keine entsprechende Spezialisierung hat. Dazu muss das Chatsystem nur – unsichtbar für die Nutzer*innen – eine entsprechende Vorkonversation führen und das Sprachmodell dadurch in einen entsprechenden Zustand versetzen, auf dem die Nutzer*innen dann ihre eigenen Fragen stellen.

Fazit

Wenn man sich folgende Aspekte von LLMs vergegenwärtigt, ist eine Einschätzung des Verhaltens und der Fähigkeiten vermutlich einfacher möglich, als über den Versuch die tief-technischen Details dieser Systeme zu verstehen:

  • Ein Sprachmodell speichert das Wissen, welches für sein Training verwendet wurde, nicht 1-zu-1 ab. Dies ist ein wesentlicher Unterschied zu Suchmaschinen
  • Zumindest heute können Sprachmodelle daraus keine allgemeinen Regeln wie zum Beispiel die Grundrechenarten destillieren und zuverlässig anwenden
  • Antworten auf Fragen werden aus diesem verdichteten Wissen synthetisiert, die Antworten sind damit grundsätzlich nicht faktentreu
  • Die Halluzination, also die Generierung von unwahren Aussagen, ist ein konzeptioneller Bestandteil eines Sprachmodells und kein Fehler, der sich komplett ausmerzen ließe
  • Die Synthese der Antworten enthält einen zufälligen Faktor, und ist damit meist nicht reproduzierbar
  • Die Antworten werden durch vorherige Konversationen beeinflusst, auf diese Weise lässt sich kurzzeitig zusätzliches Wissen in begrenztem Umfang einspeisen

Einschränkend muss man dazu sagen, dass die Entwicklung der Sprachmodelle stürmisch ist und die verschiedenen Anbieter diese Eigenschaften natürlich genau kennen. Dementsprechend begegnet man heute oft nicht mehr reinen Sprachmodellen, sondern um weitere Funktionen ergänzte Chatbots, die einige dieser Eigenschaften abmildern.

Leseempfehlung: ‚Die Hyperion-Gesänge‘ von Dan Simmons

Urlaubszeit ist Lesezeit bei mir, wann hat man sonst Zeit dafür? Dieses Mal kam der Tipp dazu aus dem Security Now Podcast, den ich hier sonst eher wegen seines eigentlichen Themas ‚IT Sicherheit‘ erwähne, der aber immer mal wieder eine gute Quelle für Science Fiction Literatur ist.

Bei dieser Empfehlung merkt man das Alter der beiden Hosts, denn der erste der beiden Romane, um die er hier geht, wurde im Jahr 1989 veröffentlicht: Hyperion von Dan Simmons. Der folgende Roman, der die Handlung abschließt, ist Der Sturz von Hyperion und erschien ein Jahr darauf. Wer meiner Empfehlung folgt, sollte gleich zu Die Hyperion-Gesänge greifen, ein 2002 erschienener Sammelband mit beiden Teilen.

Gut gealtert

Bei Science Fiction ist es so eine Sache mit dem Altern…manche Romane lesen sich Jahrzehnte nach dem Erscheinen eher albern oder gar peinlich, weil die Autor*innen sich die Zukunft in Details ausgemalt haben, die von der Realität überholt oder aus heutiger Sicht einfach kurzsichtig erscheinen.

Aber Dan Simmons hat es geschafft eine Zukunftsvision zu beschreiben, die sehr ferne Elemente enthält, wie eine verzögerungslose Reisemöglichkeit zwischen den Sternen. Aber auch aus heutiger Sicht bereits (fast) gegenwärtige Elemente, wie ein allgegenwärtiges Datennetz, in dem sich alle Menschen nahezu permanent aufhalten, und dessen Abwesenheit zu Entzugserscheinung und Hilflosigkeit führt. Als er das geschrieben hat gab es das Internet zwar schon in technischer Hinsicht, aber es war nur wenigen Menschen bekannt und die Aussicht, jeder Mensch könnte ein Gerät bei sich führen, welches jederzeit Zugriff auf diese Sphäre ermöglichen, eine Vision, die vielen vermutlich ferner schien als die fliegenden Autos, die wir eigentlich alle schon haben sollten.

Aber auch hier ist die Vision so geschrieben, dass man sich nicht daran stört, wenn von Komlogs (im Original comlogs) die Rede ist und nicht von iPhones, und es betont nur, welche menschlichen Eigenschaften über die Zeit hinweg vielleicht unverändert bleiben werden.

Bestimmte Begriffe wie SimStim oder das schwarze Eis, welches zur Charakterisierung der Datenwelt verwendet wird, deuten auf das Entstehen in den 80ern hin, zumindest kenne ich sie aus den Neuromancer-Romanen, die ein paar Jahres zuvor erschienen und danach sind sie mir nicht mehr begegnet. Aber das wirkt nicht antiquiert, es sind einfach nur Begriffe unter vielen anderen spannenden Wortschöpfungen.

Krieg, Religion, Gier und Altruismus

Die Geschichte hat einige der ‚üblichen‘ Zutaten einer Space Opera: Es gibt Raumschlachten, viele verschiedene Welten, an der Zeit wird herumgespielt, die Menschheit breitet sich kolonisierend über das All aus und benimmt sich dabei nicht besser als die europäischen Eroberer, die weite Teile der Erde unterworfen und ausgebeutet haben, die Sinnfrage ist immer noch nicht abschließend beantwortet.

Allerdings ist dies nur der Hintergrund, vor dem sich die verschiedenen Handlungsstränge entfalten und die ungefähr 10 Individuen bewegen, denen die Geschichte folgt. Und deren individuelle Motivationen anders sind und denen man, auch wenn sie nicht durchweg Sympathieträger sind, durch die mehr als 1.000 Seiten gerne folgt.

Und für mich war am Ende beeindruckend und schön, wie die ganzen Fäden und absurden Einfälle – ich nenne hier nur die merkwürdigen Parasiten – zusammengeführt werden und ein homogenes Gebilde ergeben.

Aktuell: Die Entwicklung der KI

Ein wesentlicher Aspekt der Romane ist aber auch das Entstehen von KIs und deren irgendwann zur Menschheit konkurrierende Entwicklung. Das hier gezeichnete Bild ist grob genug, um heute nicht lächerlich zu wirken, aber die Ideen für so eine Entwicklung lassen sich auch in den durch das Erscheinen von ChatGPT befeuerten Diskussionen wiederfinden und wirken daher weiterhin aktuell.

Und auch das, was ich als eine Kernfrage der Romane sehen würde: Inwieweit sollte man Produkten und ‚Geschenken‘ von KI Systemen vertrauen, die man nicht mehr versteht und deren Motivation damit ebenso wenig?

Bilder aus der KI

Die drei hier enthaltenen Bilder sind dabei auch aus einer KI gekommen. Mit Hilfe von Midjourney habe ich versucht eine Impression zu erstellen, welche bei Leser*innen der Romane hoffentlich schnell eine Assoziation auslösen wird.

Jetbrains AI Assistent – kurz ausprobiert

Wir setzen in der Programmierung der BIS Anwendungen seit einiger Zeit auf Intellij, die Java IDE von Jetbrains, und zwar in der Ultimate Edition. Der Schritt weg von Eclipse – damals schon mit der Spring Tool Suite – war zunächst nicht ganz leicht, aber im Endeffekt sind die Hilfsfunktionen dieses Produkts so leistungsfähig, dass sich der Umstieg gelohnt und die Kosten in Form von besserer Produktqualität und Entwicklungsgeschwindigkeit aus meiner Erfahrung voll zu rechtfertigen sind. Auch die Tatsache, dass Android Studio, welches wir für unsere App verwenden, auf Intellij basiert und somit der Wechsel zwischen den IDEs leichter fällt, ist hier ein Argument.

Was ist der AI Assistent

Seit ein paar Wochen vermarktet Jetbrains nun seinen auf OpenAI Technologien basierenden AI Assistenten und verspricht hier durch die direkte Integration in die IDE – und deren schon vorher vorhandenes, tiefes Verständnis des Programmcodes – eine bessere Leistung und nahtlosere Integration, als sie mit anderen vergleichbaren Tools zu erreichen sei.

Hier ein paar Erfahrungen dazu, wie sich das Tool in einem komplett neu gegründeten Java 22 Projekt anfühlt. Da das hier beschriebene Verhalten vermutlich schon wieder veraltet ist kann man das aber nur als eine momentane Bestandsaufnahme sehen:

Automatische Codevorschläge nur aus der Methodensignatur

Ein erster Effekt ist dieser: Es reicht aus – jedenfalls oft – eine Methodensignatur zu schreiben und der Assistent macht einen Vorschlag. Zum Beispiel sorgt die Signatur

public Set<Fachabschluss> fachAbschluesse()

für diesen völlig korrekten Codevorschlag:

Aufforderung zur Methodenimplementierung per Prompt

Nicht immer klappt es mit dem Automatismus, warum ist mir nicht klar geworden. Aber in so einem Fall kann man per Prompt zur Implementierung auffordern:

Allerdings zeigt sich hier die Unberechenbarkeit der heutigen KI Lösungen: Im ersten Anlauf wurde direkt der passende Code erzeugt. Als ich das Ganze noch einmal für die Screenshots gemacht habe aber nicht und erst ein erneutes Prompt brachte das gewünschte Ergebnis:

Hier wurde also zuerst eine sinnfreie Implementierung vorgeschlagen, die einfach nur null liefert. Es kann natürlich sein, dass der Assistent hier gemerkt hat, dass ich den vorherigen Vorschlag verworfen hatte und daher so ‚reagiert‘. Trotzdem wirkt es etwas skurril und unberechenbar, aber durchaus im Einklang mit den Erfahrungen vom ChatGPT oder Google Bard (inzwischen abgelöst durch Gemini), die fehlerhafte Ergebnisse liefern und dann auf Hinweis auf die Fehler etwas besseres nachliefern.

Überhaupt das Thema Fehler:

Verwendung von nicht existierenden Methoden

Eine Sache, die scheinbar regelmäßig vorkommt, ist die Verwendung von nicht existierenden Codebestandteilen im Vorschlag:

Die richtige Lösung wäre es hier gewesen noch eine Ebene tiefer zu gehen und aus den Modulabschluss-Objekten die enthaltenen Fachabschluss-Objekte zu holen. Und nicht über eine nicht vorhandene Methode eine Filterung durchzuführen.

Konsistenz: Unterschiedliche Lösungen für gleiche Aufgaben

Auch wenn es nicht falsch ist gibt es ein Verhalten, welche mein Stilempfinden stört: Der Assistent erzeugt für gleiche Aufgaben unterschiedlichen Code. Das sind teilweise nur Nuancen, aber sie machen den Code inhomogen und damit schwerer verständlich.

Code Variante 1

    public Set<Fachabschluss> fachAbschluesse() {
        return module.stream()
                .flatMap(mip -> mip.fachAbschluesse().stream())
                .collect(Collectors.toSet());
    }

Code Variante 2

    public Set<Fachabschluss> fachAbschluesse() {
        return profile.stream()
                .map(Profil::fachAbschluesse)
                .flatMap(Set::stream)
                .collect(Collectors.toSet());
    }

Beide Varianten führen zum gleichen Ergebnis, aber es zeigt die Zufälligkeit der von der KI generierten Codes.

Nicht ganz up to date

Das generelle Problem der heutigen LLMs, die prinzipbedingt nicht tagesaktuell sein können, zeigt sich auch hier an manchen Stellen, etwa beim Versuch die Java Version in der pom.xml des maven-Projekts über den Assistenten auf Java 22 zu erhöhen:

Das Java 22 JDK wurde ca. 10 Tage vor dem Schreiben dieses Posts veröffentlicht. Allerdings scheint das ‚Wissen‘ des Assistenten noch deutlich älter zu sein, was man aus der Behauptung schließen kann, die letzte stabile Java Version sei 17. Selbst wenn ’stabile Version‘ die LTS Releases meint, so wäre das Java 21 und das kam am 19. September 2023 raus.

Grundsätzlich führt einen der Assistent hier aber auf die richtige Spur und sagt, was man machen muss. Und das ohne die IDE verlassen zu müssen. In vielen Anwendungsfällen dürfte es nicht stören, wenn der Assistent nicht die allerletzten Sprachversionen kennt. Allerdings hatte ich bei anderen Assistenten auch schon Probleme damit, dass Versionen von Open Source Projekten eingebunden wurden, die entweder schon nicht mehr existierten, oder die wegen lange bekannter Sicherheitsprobleme bereits nicht mehr zur Nutzung empfohlen wurden.

Fazit

Durch das Entstehen von KI Werkzeugen, die Programmcodes in hoher Qualität erstellen können, wird auch das Berufsbild der Softwareentwickler*innen schon jetzt sehr in Frage gestellt. Und was ein Tool wie der Jetbrains Assistent zeigt: Für bestimmte Routinen muss man nicht mehr selbst programmieren können. Oder nur noch in Teilen.

Allerdings ist mein Einsatz des Werkzeugs vermutlich noch zu sehr vom Denken als klassischer Softwareentwickler geprägt, der es gewohnt ist die Struktur seiner Software vorzugeben. Daher habe ich der KI nur etwas Zuarbeit überlassen. Das eigentliche Versprechen ist es aber, dass man eigentlich gar nicht mehr direkt Software entwickeln können muss, sondern ’nur‘ seine Anforderungen und Ziele definiert und der Rest kommt automatisch. Vielleicht noch mit etwas ‚low code‘.

Also so, wie ich beim Generieren von Fotos per Midjourney – siehe das Bild der Roboterhände am Anfang – vorgehe, ohne irgendeine besondere Kenntnis von Malerei oder Graphikdesign zu haben. Aber um so an die Softwareentwicklung herangehen zu können müsste ich erst einmal viel entlernen, was ich mir in Jahrzehnten erarbeitet habe. Mal sehen, ob mir das beim nächsten Versuch gelingt.

Passwortlose Logins per E-Mail: Eine gute Idee?

In dem Security Now Podcast kam in den letzten Wochen – wenigstens bis Folge 965 – getrieben von Hörerkommentaren immer wieder ein Thema hoch: Was ist von ‚passwortlosen‘ Logins per E-Mail zu halten? Der Begriff ‚passwortlos‘ wird im Kontext der zunehmenden Verbreitung von Passkeys gerade oft gebraucht, so gibt es etwa bei Google eine Seite mit dem Titel Passwordless login with passkeys.

Midjourney, Prompt: the rough sketch of a key on the wall of a cave

Aber wäre es da nicht interessant ein passwortloses Loginschema zu haben, das ohne komplizierte Kryptografie und ohne Abhängigkeit zu den großen Betriebssystemanbietern oder Passwort-Managern auskommt? Die Idee ein Verfahren wie E-Mail, das aus der Steinzeit des Internets kommt, gegen eine hochmoderne Idee für Loginverfahren antreten zu lassen, hat dabei einen eigenen Reiz, und am Ende könnte es hier auch im Umfeld von modernen Anwendungen auf Smartphones ein Anwendungsszenario geben:

Wie funktioniert das Verfahren

Mir ist so ein Verfahren zum ersten Mal bei Slack begegnet, dort gab es schon vor Jahren die Loginoption des ‚magischen Links‘. Der Ablauf ist dabei grundsätzlich so:

  1. Auf der Seite des Dienstes, in den ich mich einloggen möchte, gebe ich die E-Mailadresse ein, die zu meinem Konto gehört
  2. Der Dienst schickt an diese Adresse einen Link mit etwas ‚magischem‘, dazu im nächsten Absatz mehr
  3. Ich öffne den Link aus meinem Mailpostfach in meinem Webbrowser
  4. Der Dienst prüft den Link und erzeugt damit eine aktive Loginsitzung für mich
  5. So lange das Sitzungstoken gültig ist bin ich in diesem Webbrowser eingeloggt

Passwortreset – umdefiniert

Das Verfahren des ‚magischen‘ Link Logins hat große Ähnlichkeiten mit den Verfahren, die man für einen Passwortreset per E-Mail implementiert und vielleicht sind die ersten entsprechenden Loginverfahren auch daraus entstanden:

Bei einem Passwortreset wird ein Link zugeschickt mit einem kaum zu erratenden Bestandteil wie einer ausreichend langen, zufälligen Zeichenkette. Sobald Nutzer*innen diesen Link aufrufen muss das Resetverfahren prüfen ob der Link bekannt und noch gültig ist und zu welchem Account er gehört. Nach dieser Prüfung wird die Option angeboten ein neues Passwort zu setzen und Logins damit in Zukunft erfolgreich durchführen zu können.

Midjourney. Prompt: the rough sketch of an opening door painted on the wall of a cave

Aus Sicht der Nutzer*innen ist das durchaus umständlich, vor allem wenn ich nach dem Passwortreset erst noch das komplette Login mit dem neuen Passwort durchführen muss um endlich in den gewünschten Dienst rein zu kommen. Vielleicht ist hier schon die Idee entstanden, den Nutzer*innen nach dem Passwortreset das erneute Login zu ersparen und sie gleich als angemeldet zu betrachten.

Von da war es dann nur noch ein kurzer Weg dazu den Schritt zum Setzen des neuen Passworts ganz auszulassen und gleich zur Durchführung des Logins zu springen. Bei Diensten wie Slack ist so ein Login dann sehr langlebig.

Absicherung des Verfahrens

Wie kann man so ein Verfahren absichern? Die Überlegungen dazu gelten in sehr ähnlicher Weise für eine Passwortresetfunktion per E-Mail:

Abhängigkeit von der Sicherheit des (externen) Postfachs

Ein Punkt muss bei allen Verfahren, die Sicherheitsfunktionen an E-Mail hängen, bewusst sein: Man macht die Sicherheit des eigenen Dienstes vollständig abhängig von der Sicherheit der Mailpostfächer seiner Nutzer*innen.

Je nach Anwendungsszenario kann das eine Entlastung sein, siehe dazu den Abschnitt zu den Vorteilen einer solchen Lösung für Dienstbetreiber. Gerade bei Einsatzszenarien in Diensten des eigenen Unternehmens wirft es aber sehr stark die Frage nach der Sicherheit des Mailsystems auf. Wenn dieses in Sicherheitshinsicht Defizite hat, so übertragen sich diese auf die angebundenen Dienste.

Die Sinnhaftigkeit der folgenden Überlegungen zu Absicherungen muss dann in einem Gesamtkontext betrachtet werden, damit sie nicht leerer Aufwand oder gar Sicherheitstheater werden:

Linkssicherheit 1: Schutz gegen Erraten

Die Sicherheit des Verfahrens hängt ganz grundsätzlich an der Art der verwendeten Links. Diese dürfen sich nicht erraten oder vorhersagen lassen. So wäre es keine gute Idee, wenn der ‚geheime‘ Teil eines solchen Links aus einem auf dem Server laufenden, immer wieder erhöhten Zähler gebildet würde. So ein Muster wäre einfach zu erkennen und zukünftige, gültige Links könnten vorhergesagt werden.

Auch sollten die Links nicht unnötig interne Strukturen der Architektur wie Schlüssel von Datensätzen nach außen geben oder gar als wesentlichen Bestandteile der Echtheitsprüfung der Links enthalten. Zum einem, um keine potentiell sicherheitsrelevanten Informationen nach außen zu geben und zum anderen, weil solche Strukturen oft wieder auf vorhersagbaren Zählern gebildet werden. Auch eine UUID ist hier nicht unbedingt eine gute Wahl, da sie viele vorhersagbare Bestandteile hat.

Midjourney. Prompt: the rough sketch of a string of random glyphs on the wall of a cave

Am saubersten ist hier immer noch ein genügend langer, (pseudo)zufälliger String. Zusammen mit einer Begrenzung der Zugriffsraten auf den Endpunkt, den der Link aufruft, und einer begrenzten Lebensdauer sorgt dies für eine ausreichend geringe Wahrscheinlichkeit, dass so ein Link jemals erraten werden kann.

Linkssicherheit 2: Schutz gegen Replay

Zusätzlich zu einer begrenzten Lebensdauer sollten diese Links nach der ersten Verwendung ‚verbraucht‘ sein, sich also nicht erneut aufrufen lassen. Damit schützt man sich vor Angreifern, denen es irgendwie gelingt ebenfalls an diesen Link zu kommen.

Nicht ganz klar ist mir hier ob es Mailanbieter gibt, die in eintreffenden Mails enthaltene Links generell scannen und dabei aufrufen. Dann würde diese Schutzfunktion den Link invalidieren und faktisch wäre das Verfahren dann mit so einem Mailanbieter nicht nutzbar. Denkbar wäre es hier vielleicht die Anzahl der erlaubten Nutzungen auf 2 oder mehr zu erhöhen, was aber weitere Komplexität und ein potentielles Schlupfloch bringt.

Eine Variante in der Implementierung könnte es daher sein, dass Nutzer*innen nach dem Aufruf des Links den Vorgang explizit durch Anklicken eines Buttons abschließen und erst dieser Vorgang das Login durchführt und den Link invalidiert.

Linksicherheit 3: Bindung an den auslösenden Webbrowser

Die Frage, wie man den Missbrauch eines zum Beispiel beim Mailversand abgefangenen Links möglichst verhindert, war auch Teil der Diskussionen im Podcast. Abgesehen von Szenarien, bei denen Angreifer eine Rolle spielen, kann dies aber auch zur Begrenzung der meist nicht gewollten, bewussten Weitergabe von Logins durch die Nutzer*innen selbst beitragen, da sich Loginlinks dann nicht so einfach weiterleiten lassen:

Die Idee besteht darin den Loginlink nur in dem Webbrowser funktionsfähig zu machen, der den Vorgang initiiert hat. Wird er in einer anderen Umgebung aufgerufen wird keine Loginsitzung angelegt und im Idealfall der Link gleich ungültig gemacht. Welche Mittel kann es dazu geben?

Grundsätzlich sind die hier angestellten, umfangreichen Überlegungen dazu, wie man Logincookies gegen Diebstahl sichern kann, auch hier anwendbar. So wäre es ja zum Beispiel schon etwas verdächtig, wenn der magische Link von einem Rechner in Europa angefordert, aber aus einer Infrastruktur im Russland dann eingelöst werden soll.

Midjourney. Prompt: the rough sketch of a long, rusty chain on the wall of a cave

Es gibt hier aber eine einfachere Möglichkeit: Sofern sich das Formular, in dem die Zustellung des magischen Links angefordert wird, unter der gleichen Domäne befindet wie das Formular, in dem dann der magische Link eingelöst wird, kann hier bei der Linkanforderung ein Cookie mit einem weiteren (zufälligen) Wert platziert werden. Serverseitig wird gemerkt, welches Cookie zu dem magischen Link gehört. Der Abschluss des Logins wird dann vom Vorhandensein des dazugehörenden Cookies abhängig gemacht. Das Cookie darf natürlich nicht das Geheimnis enthalten, welches im magischen Link steckt.

Diese Vorkehrung schützt allerdings nicht davor, dass Angreifer von einem unter ihrer Kontrolle stehenden System aus die Linkzustellung anstoßen und das Opfer per Social Engineering dazu bringen ihnen den Link weiterzuleiten.

Schutz vor automatisiertem Nerven der Nutzerschaft

Es muss ein Schutz eingebaut werden, der eine Belästigung der eigenen Nutzer*innen durch permanentes Auslösen der Reset / Loginfunktion unterbindet. Da das Webformular grundsätzlich ‚offen‘ sein muss um seinen Zweck zu erfüllen, kann es leicht über Scripte bedient und damit beliebig oft von Unbefugten angestoßen werden.

Hier sind clientseitige Funktionen wie ein Captcha denkbar, und serverseitige Begrenzungen, die Zähler führen zur Anzahl der von einer einzelnen IP-Adresse angestoßenen Vorgänge. Im einfachsten Fall kann so eine Schutzfunktion auf den Server bzw. den Endpunkt aufgesattelt werden, wie es z. B. mit dem Anti-DoS-Valve möglich ist.

Ein komplexerer Schutz könnte Mindestabstände bei der Mailzusendung auf einzelnen Nutzer*innen definieren und durchsetzen (‚Nur ein magischer Link alle 30 Minuten‘).

Schutz vor Datenabfluss

Auch dies ist keine einzigartige Aufgabe, die nur in diesem Kontext entsteht, aber trotzdem sollte es für potentielle Angreifer nicht zu einfach sein über diesen Weg herauszufinden, welche E-Mailadressen ein Konto bei einem Anbieter haben.

Vermutlich gibt es kaum einen anderen Weg dafür als auf jede eingetragene E-Mailadresse gleich zu reagieren, egal ob sie mit einem Konto verbunden ist oder nicht oder ob sie gerade auf Grund von zu zahlreichen Anfragen nicht mehr bedient wird.

Der Preis ist eine hohe Intransparenz aus Sicht der Nutzer*innen, denen nicht einmal angezeigt werden kann, dass sie ihre E-Mailadresse falsch eingetragen haben.

Vorteile für einen Dienstbetreiber

Wie die Überlegungen im vorherigen Abschnitt zeigen ist es also insgesamt durchaus ein komplexes Unterfangen ein ‚magisches‘ Link Login aufzubauen und sicher zu gestalten. Trotzdem kann dies für einen Dienstbetreiber eine Vereinfachung darstellen:

(Fast) Keine Geheimnisse

Da keine Passworte oder andere Geheimnisse wie TOTP Secrets vorhanden sind müssen diese nicht geschützt werden und lassen sich damit auch nicht stehlen. Komplexe Überlegungen wie etwa zum richtigen Passwort Hashverfahren braucht es nicht, ebenso wenig zur Wahl des richtigen Zwei-Faktor-Loginverfahrens.

Auch die entsprechenden Funktionen zur Benutzerkontenverwaltung, sowohl in der internen Administration, wie aber auch für die Nutzer*innen selbst, entfallen weitgehend und sparen Entwicklungsaufwände. Bzw. die teilweise enormen Kosten, die spezialisierte Dienstleister hier berechnen. Und auch ein Loginformular braucht es nicht. Vermutlich reduzieren sich auch Supportaufwände, da es hier nicht viel zu erklären gibt.

Wenn die Abhängigkeit von der Sicherheit der von den Nutzer*innen eingesetzten E-Mailkonten kein Problem darstellt, dann entlastet man sich hier von sehr vielen Aufgaben beim Aufbau und Betrieb des eigenen Dienstes und das faktisch ohne dauerhafte Kosten.

Es gibt eigentlich nur ein Geheimnis, welches geschützt werden muss, und das sind die Sitzungscookies, die durch die magischen Links produziert werden. Im Fall eine Kompromittierung könnte man die aber einfach komplett löschen und die Nutzer*innen würden sich dann – wie sie es schon gewohnt sind – erneut per Mail einloggen.

Weniger Reibung bei der Kontoerstellung

Zumindest bei der Erstanlage eines Kontos ist dieser Weg der reibungsfreiere, denn nach der Eingabe der eigenen E-Mailadresse und dem Anklicken des Links ist man bereits handlungsfähig. Kein Nachdenken über ein neues Passwort hält die Kontenerstellung auf.

Gerade für Services, die mit einer hohen Anzahl von spontanen, vielleicht nur selten wiederkehrenden Nutzer*innen zu tun haben, kann dies ein entscheidender Punkt sein.

Ein Stolperstein können hier nur die generellen Probleme mit E-Mail sein, wie eine Klassifizierung der E-Mails als Spam und damit ein vergebliches Warten der Nutzer*innen auf ihren Link.

Aus Sicht der Nutzer*innen

Schon in früheren Folgen des Security Now Podcasts kam bei Diskussionen um die Wahl eines guten Passworts bzw. der Frage ob man noch ohne Passwortmanager ‚leben‘ kann hin und wieder der Hinweis von Hörer*innen, dass sie bei manchen Diensten nur noch irgendwas in das Passwortfeld eintippen und sich nicht merken, nur um dann im Fall des Falls den Passwortreset zu verwenden. So ein Nutzungsmuster wird durch das Login per Link perfekt unterstützt.

Unpraktisch ist es aber in allen Szenarien, in denen häufige Logins notwendig sind. Das Passwort ist hier ein gewisser Weise ein Login Beschleuniger. Gerade bei Szenarien im Unternehmensumfeld wäre es vermutlich keine gute Idee, wenn man seinen Nutzer*innen jeden Tag so ein Loginverfahren zumuten würde. Gangbar könnte es dann sein, wenn es mit sehr langlebigen Logins verknüpft wird und das Mailkonto gut gesichert ist.

Fazit: Eine relevante Technologie mindestens für Nischen

Ich finde die Idee eines Logins per Link durchaus spannend, es bietet eine Bandbreite von Umsetzungsmöglichkeiten, zum Beispiel bei der Lebensdauer der dadurch erzeugten Loginsitzungen. Eine Variante könnte es auf dem Smartphone sein diese Links per SMS/RCS oder Chatanwendung zuzustellen. Oder direkt aus einer eigenen App und zwar in diesem Szenario:

Nahtloser Übergang von einer nativen App in eine Webanwendung

Ein Unternehmen hat eine native App, in der sich die Nutzer*innen normalerweise eingeloggt bewegen. Nicht alle Funktionen der Unternehmensanwendungen sind allerdings in der App erreichbar, an manchen Stellen werden Links in Webanwendungen angeboten.

Midjourney. Prompt: the rough sketch of a smartphone on the wall of a cave

Wenn die Webanwendungen über eine Integration in eine Single Sign-on Lösung verfügen, die in der Lage ist Logins per Link zu bedienen, könnte ein aus Sicht der Nutzer*innen nahtloser Übergang von nativer App in die Webanwendungen so aussehen:

  1. Nutzer*in verwendet die App und ist darin angemeldet
  2. In der App wird ein Link in eine logingeschützte Unternehmensanwendung geöffnet
  3. Die App holt sich vor dem Öffnen des Webbrowsers über eine entsprechende API aus dem Loginsystem einen Loginlink bzw. die ‚magischen‘ Bestandteile dieser Links wie das zufällige Token. Die App gestaltet den Aufruf des Webbrowsers mit der Adresse der Zielanwendung dann in dieser Weise:
  4. Der Aufruf wird über das Loginsystem gelenkt, welches das mitgegebene ‚magische‘ Token auswerten und damit das Login durchführen kann. Das Loginsystem macht dann die Weiterleitung an die jeweilige Webanwendung
  5. Die Webanwendung macht ggf. nochmal eine Schleife über das Loginsystem, per SSO gelingt der Zugriff dann aber ohne erneutes Login

Das komplexe technische Wechselspiel ist dabei vor den Nutzer*innen komplett verborgen und wirkt damit nahtlos. Aus Sicherheitsgründen können die Lebensdauern von so erzeugten Loginsitzungen ggf. stark begrenzt werden, da die App beim nächsten Aufruf wieder ein neues Token generieren kann. In diesem Konzept bleibt vom ‚passwortlosen Login per E-Mail‘ letztlich nur das geheime Token übrig, welches nun zwischen den beteiligten Systemkomponenten ausgetauscht wird, ohne das eine Nutzerinteraktion notwendig ist.

PS.

Die in diesem Artikel verwendeten Bilder wurden mit Midjourney generiert und sollten das Thema des ’steinzeitlichen‘ Mittels E-Mail aufgreifen, welches im Vergleich zu State of the Art Technologien wie Passkeys fast wie Höhlenmalerei wirkt. Aber einfach nicht totzukriegen ist ✊🏻

Wie man Login Cookies vor Diebstahl schützt: Eine Ideensammlung

Beim Aufbau eines zeitgemäßen, webbasierten Loginsystems konzentriert man sich oft zunächst auf den Teil, der bis zum erfolgreichen Login stattfindet: Wie lege ich Passworte sicher ab im System? Wie baue ich eine 2-Faktor-Authentifizierung auf? Wie verhindere ich massenhafte Passwortrateversuche? Kann ich die Resistenz gegen Phishing ausbauen?

In diesem Post geht es aber darum den Teil, der danach passiert, gegen Angriffsszenarien abzusichern und das ist der Teil, in dem sich das Loginsystem dann ‚merkt‘, dass ein erfolgreiches Login durchgeführt wurde und dann nach eigenen Regeln entscheidet, wann es Nutzer*innen erneut nach ihren Logindaten fragt. In Bezug auf das Loginsystem wird im weiteren vom Identity Provider (IdP) gesprochen.

Wie merkt sich ein IdP ein früheres Login

Ein Identity Provider sitzt im Mittelpunkt einer Systemarchitektur, er hat die Aufgabe allen angeschlossenen Systemen die Loginprüfung und Benutzervalidierung abzunehmen und ist damit der singuläre Punkt, in den zur Verbesserung der damit verbundenen Sicherheitsaspekte investiert werden muss. Diese Graphik stammt aus einer Präsentation, die im BIS Kontext einmal gezeigt wurde um diese Struktur zu visualisieren:

Strukturen einer Systems, bei dem ein Identity Provider verschiedene Webanwendungen integriert

Gleichzeitig ist der IdP die Stelle, die ein Single Sign-on umsetzt: Nach dem ersten Login in eine der angeschlossenen Anwendungen kann das Login in die nächste Anwendung ohne für die Nutzer*innen spürbaren, erneuten Loginvorgang erfolgen. Dazu muss der Identity Provider ein Mittel haben um sicher feststellen zu können, dass es bereits so ein erfolgreiches Login gab, zu welcher Nutzerin es gehört und ob es noch gültig und integer ist.

Da es hier um webbasierte Anwendungen geht wird im Weiteren von Cookies gesprochen. Denn für die folgenden Betrachtungen ist es mehr oder weniger unerheblich, ob hier tatsächlich Cookies eingesetzt werden, versteckte Formularfelder oder andere cookie-lose Techniken wie JWTs. Auch ob der Inhalt aus umfangreichen Informationen über die Nutzer*innen und ihre Berechtigungen besteht, oder nur aus einem zufälligen String, spielt keine wesentliche Rolle, denn letztlich geht es immer um ein Informationspaket, welches dem IdP vom Webbrowser präsentiert wird:

Login Cookies als Einfallstor für Angriffe

Da das Login Cookie ausreicht, um die entsprechenden Nutzer*innen gegenüber den IdP zu repräsentieren, ist es ein Weg um den Systemzugriff zu erhalten ohne die eigentlichen Logindaten zu besitzen. Auf diese Weise sind selbst Zugriffe auf Konten möglich, die mit ansonsten komplett diebstahlsicheren Logins etwa über FIDO Keys ausgestattet sind. Der erfolgreiche Angriff auf den Identitätsdienst Okta in diesem Jahr ist hier ein interessantes Beispiel:

Wenn man die beiden Posts, die Okta am 3. November und am 29. November 2023 veröffentlicht hat, nach vollzieht, so konnten die Angreifer Zugriff auf das Kundensupportsystem von Okta erhalten und daraus sogn. HAR-Dateien extrahieren und aus diesen wiederum Login Cookies. Diese HTTP-Archive enthalten alles, was der Webbrowser in Bezug auf eine Webseite kennt, der Warnhinweis auf Googles HAR-Analysetool ist daher entsprechend deutlich:

HAR-Dateien enthalten vertrauliche Daten:

  • den Inhalt der Seiten, die Sie während der Aufzeichnung herunterladen
  • Ihre Cookies, mit denen jeder, der Zugriff auf die HAR-Datei hat, Ihr Konto mit Ihrer Identität nutzen könnte
  • alle während der Aufzeichnung übermittelten Informationen: personenbezogene Daten, Passwörter, Kreditkartennummern usw.
Warnhinweis aus dem HAR-Analysetool von Google

Die Art des Angriffs auf Okta war besonders komplex, aber auch jede Person, die kurz an einem fremden Rechner sitzt, ist prinzipiell in der Lage die Cookies aus einem Webbrowser zu holen, ebenso jede Schadsoftware, die sich im PC oder im Webbrowser eingenistet hat:

Das Risiko wird dabei um so größer, je langlebiger die Cookies sind. Aber wie kann man einen Diebstahl verhindern?

Den Diebstahl kann man nicht verhindern

Generell gibt es für Webanwendungen wie einen Identity Provider heute keine Möglichkeit, die eigenen Geheimnisse perfekt zu schützen. Natürlich muss man dafür sorgen, dass die Cookies nicht einfach für andere Webseiten/-anwendungen auslesbar sind und sie nur verschlüsselt zu übertragen sollte heute eine Selbstverständlichkeit sein.

Genauso wenig darf es möglich sein gültige Cookies ‚aus dem Nichts‘ zu erschaffen, zum Beispiel in dem laufende Nummerierungen vorhergesagt oder die Inhalte bekannt gewordener Cookies modifiziert und zum Beispiel in ihrer Lebensdauer verlängert werden.

Im einfachsten Fall ist das Login Cookie etwas mit diesen Eigenschaften:

  • Der Inhalt ist einfach ein langer Zufallsstring
  • Die Zuordnung dieses Strings zu den konkreten Nutzer*innen erfolgt im IdP z. B. durch eine Datenbankabfrage
  • Auch die Prüfung der Lebensdauer / Gültigkeit erfolgt auf Serverseite auf Basis einer sicheren Informationsquelle wie einer Datenbank mit den bekannten Login Cookies

Dieser Ansatz ist nicht für jede Architektur geeignet, aber er ist einfach ein simples Konstrukt, auf dem sich im weiteren aufbauen lässt. Generell enthält dieses Modell noch nichts, was einen Diebstahl unterbinden oder auch nur erschweren würde, jede Person, die in ihrem Webbrowser dieses Cookie einsetzt wird danach vom IdP als die ursprüngliche Nutzerin akzeptiert und kann in ihrem Namen arbeiten.

Wenn sich ein Diebstahl aber nicht sicher verhindern lässt, dann bleibt nur der Versuch ihn möglichst schnell zu erkennen. Danach können dann Maßnahmen umgesetzt werden, darunter die sofortige Invalidierung des Cookies, potentiell gefolgt von einer Untersuchung, ob es sich wirklich um einen echten Angriff gehandelt hat.

Indicators of compromise

In der IT-Forensic wird ein Artefakt, welches auf eine Kompromittierung hindeutet, als Indicator of compromise (IoC) bezeichnet. So ein Artefakt ist dabei oft nicht für sich allein genommen hilfreich, erst die Betrachtung über mehrere Vorgänge hinweg und dabei beobachtete Veränderungen der verschiedenen Indikatoren können dann Auslöser sein. Aber welche brauchbaren Indikatoren haben wir überhaupt bei Loginvorgängen zur Verfügung:

IP-Adresse

Eine generell vorhandene Information ist die Adresse des Geräts, von dem aus ein Zugriff erfolgt. In der strengsten Auslegung würde ein Login Cookie dann verworfen, wenn es von einer anderen IP-Adresse geliefert wird, als bei der Erstellung verwendet wurde. Das ist aber abgesehen von Fällen, in denen Nutzer*innen immer fixe Adressen haben, keine vernünftige Lösung. Bzw. sie würde im Effekt darauf hinauslaufen, dass ein Single Sign-on faktisch nicht mehr erfolgt und Nutzer*innen sich oft neu anmelden müssen.

IP-Adressbereiche

Interessanter kann eine Prüfung auf Adressbereiche sein: Wenn sich ein Login Cookie nur in den Subnetzen verwenden lässt, in denen es erstellt wurde, ist das Diebstahlspotential deutlich verringert, zumindest wenn man externe Angreifer betrachtet.

Allerdings kann es in einer Universität damit ebenfalls bei weiten Teilen der Nutzerschaft zu einem faktischen Verlust des Single Sign-ons kommen: Nutzungsgruppen wie Studierende wechseln regelmäßig mit ihren Geräten zwischen den Funknetzen der Mobilfunkbetreiber und dem WLAN der Universität und bewegen sich dort in deutlich unterschiedlichen Netzen.

ASN Ebene

Eine noch höhere Ebene sind die AS – die Autonomous Systems – des Internets und die ihnen zugeordneten Nummern, die ASNs. Okta beschreibt in seinem späteren Post dieses Sicherheitsfeature:

Admin Session Binding: As communicated in the Security Incident RCA, customers can now enable an Early Access feature in Okta that requires admins to reauthenticate if their session is reused from an IP address with a different ASN (Autonomous System Number). Okta strongly recommends customers enable this feature to further secure admin sessions.

Quelle: Okta

Da die AS eine so große Struktur im Internet sind, ist dies ein vermutlich ein für viele Anwendungen interessantes Level, welches Zugriffe aus ganz anderen Teilen der Welt aufzeigt, aber nicht so übersensibel ist, wie die vorherigen Ansätze.

Ein Problem ist hier offenbar, dass sich die Zuordnung von IP-Adressen zu ASNs nicht kostenfrei erhalten lässt. Zumindest gibt es Dienstleister wie IP-Info, die mit ASN Datenbanken handeln.

Geolokation

Der Ort, von dem ein Zugriff kam, ist ebenfalls ein interessanter Indikator. Allerdings lässt sich der Zusammenhang zwischen einer IP-Adresse und der physischen Lokation nur ungefähr ermitteln und hier braucht es in jedem Fall einen Dienstleister, wie z. B. die schon zuvor genannte IP-Info, die auch so ein Produkt im Angebot hat.

Auch wenn die Geolokation nicht wirklich sicher zu bestimmen ist kann sie insbesondere dann interessant sein, wenn es darum geht die Nutzer*innen bei fragwürdigen Zugriffen einzubinden: Diese können mit der Information, dass ein Zugriff mit ihren Kontodaten aus irgendeinem IPv6 Netz erfolgt ist, nichts anfangen. Aber die Aussage, dass ein Login auf der anderen Seite der Welt erfolgt ist, könnte sie doch zum Handeln bewegen.

Für die automatisierte Beurteilung, ob ein Zugriff verdächtig erscheint, sind dann aber noch weitere Fragen zu klären. Insbesondere die, ab welcher Distanz ein Zugriff als verdächtig einzustufen ist. Wenn man von Bielefeld ausgeht, wäre dann München Ok, aber London schon nicht mehr? Was ist, wenn ein Nutzer sein Login Cookie in Ägypten angelegt hat, und damit nach Bielefeld zurückkehrt? Und was ist mit Nutzer*innen, die regelmäßig VPN-Dienste verwenden, die sie an wechselnden Punkten der Welt im Internet auftauchen lassen?

Browser Kennzeichen

Auch der Webbrowser, für den ein Cookie ursprünglich ausgestellt wurde, ist ein Merkmal, welches sich nicht vollständig ändern sollte in der normalen Nutzung. Das einfachste Merkmal ist der User Agent String. Mein Chrome Browser gibt sich beim Verfassen dieses Textes so gegenüber Webservern aus:

Mozilla/5.0 (X11; CrOS x86_64 14541.0.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36

Das Chrome hier etwas von Mozilla, Apple, KHTML und Safari nennt hat mit der langen Entwicklung der Webbrowser zu tun. Abgesehen davon gibt es zwei Schwierigkeiten:

  1. Ein Angreifer kann eine Webbrowser Kennung leicht fälschen, gerade im Fall eines Diebstahls von HAR-Dateien wie bei Okta liegen alle dazu notwendigen Daten vor. Selbst wenn diese Informationen nicht vorliegen sollten lassen sie sich erraten, denn es gibt nicht viele Möglichkeiten
  2. Die schnelle Weiterentwicklung von Webbrowsern ändert diese Signaturen spätestens alle paar Wochen. Dies kann man allerdings auch als Sicherheitsfeature sehen und als externen Trigger für die Invalidierung eines Login Cookies nehmen

Ein guter Indikator für einen Diebstahl wäre es, wenn ein Cookie mit einem komplett anderen Webbrowsertyp verwendet würde, oder auf einem anderen Betriebssystem. Aber auch, wenn bei dem verwendeten Webbrowser ein Versionsrückschritt stattfinden würde. Für die Verarbeitung der User Agent Strings gibt es Pakete, zum Beispiel ua_parser.

Generell lässt sich ein Webbrowser auch noch anders identifizieren, die Werbeindustrie ist hier nicht müde Merkmale für ein Fingerprinting zu sammeln, welches Nutzer*innen gegen ihren Willen verfolgen kann. Aber solche Mittel sind für diesen Zweck vermutlich nicht wirklich relevant.

Browser Fingerprinting

Nachtrag: Mein Kollege Nico hat die kurze Abhandlung des Themas Fingerprinting hier kritisiert, daher will ich den Absatz noch etwas ausbauen: Es gibt Angebote wie Fingerprint.js, die zahlreiche Faktoren aus einem Webbrowser extrahieren um damit einen eindeutigen Identifikator zu erstellen. Das Versprechen ist es hier Besucher*innen einer Webseite selbst dann tracken zu können, wenn diese in ein Inkognito-Tab wechseln. Allerdings setzen die Schöpfer*innen dieses Pakets die Zuverlässigkeit eher niedrig ein:

Since FingerprintJS processes and generates the fingerprints from within the browser itself, the accuracy is limited (40% – 60%).

Für die hier diskutierten Zwecke ist das zu wenig, im Durchschnitt wäre dann ja ca. jeder zweite Fingerprint nicht verlässlich. Wobei noch unklar ist, in welcher Richtung: Wird beim gleichen Benutzer immer mal wieder ein abweichendes Ergebnis geliefert? Das wäre besonders ungünstig, da es die Rate der Fehlalarme hoch treiben würde. Oder geht es eher in die andere Richtung, werden für viele Nutzer*innen die gleichen Identifikatoren errechnet? Das würde den Effekt entsprechend relativieren.

Allerdings ist es in gemanagten Umgebungen, in denen zahlreiche Nutzer*innen sehr ähnliche bis völlig identische Umgebungen verwenden, vermutlich sowieso schwierig unterschiedliche Identifikatoren zu erzeugen.

Ea gibt von diesem Anbieter auch eine serverseitige Lösung, bei der eine 99,5% Akkuratesse versprochen wird. Die dabei laut Werbetext verwendeten Verfahren gehen dann aber weit in den Bereich eines Verhaltensfingerprintings:

Fingerprint Identification is able to achieve 99.5% accuracy, because it processes the browser attributes on the server and also analyzes vast amounts of auxiliary data (e.g. IP addresses, time of visit patterns, URL changes, etc.).

Insgesamt erscheint mir so ein Ansatz wie eine Mischung aus schwer zu kalkulierender Verlässlichkeit gepaart mit einem potentiell massiven Datenschutzproblem, zumindest wenn man so ein Fingerprinting bei einem externen Dienstleister stattfinden lässt.

Führen eines Verwendungszählers

Mit der Erkenntnis des vorherigen Abschnitts, wonach sich die Versionsnummer des verwendeten Webbrowsers nicht zurückentwickeln kann, lässt sich eine Funktion implementieren, die zumindest bei einem in aktiver Benutzung befindlichen Login Cookie den längerfristigen Missbrauch sicher verhindern kann:

Wenn man den Zufallsstring, der im Cookie steckt, mit einem Verwendungszähler kombiniert, der bei jedem Aufruf größer wird, fällt die Nutzung des Cookies an zwei unterschiedlichen Stellen direkt auf:

Einer der beiden Nutzer wird ein Cookie mit einer Version liefern, die schon abgelaufen ist, und so ein Ereignis wäre ein sehr deutlicher Indikator für eine Kompromittierung. Im Fall des Okta Hacks wären mit so einer Konstruktion möglicherweise alle gestohlenen Cookies wertlos gewesen, da schon die erste Verwendung zu ihrer Invalidierung geführt hätte.

Der IdP müsste dazu das Login Cookie bei jeder Verwendung aktualisieren und in der Datenbank einen Zähler führen, der immer weiter erhöht wird. Varianten bei der Implementierung können dabei darin bestehen, dass man den Zähler bei ‚1‘ beginnen lässt und dann immer um eins erhöht, oder beide Werte mit einer Zufallskomponente belegt, um Vorhersagen zu erschweren.

Generell scheint dieser Ansatz eine hohe Sicherheit zu bieten, sofern sich das Cookie in aktiver Verwendung befindet. Keinen Schutz würde er bieten, wenn die Nutzerin das Cookie selbst gar nicht mehr im Webbrowser hat bzw. den Webbrowser lange nicht nutzt. Was zum nächsten Punkt führt:

Cookies ohne Verwendung schneller invalidieren

Auch in einem System, in dem die Login Cookies generell langlebig sein sollen, macht es Sinn offenbar nicht mehr verwendete Cookie schneller zu löschen, um die Angriffsfläche zu reduzieren. Um solche Cookies zu finden müssen Zeitstempel für die Nutzung der Cookies gehalten werden. Auswertungen darauf können dann offenbar inaktive Cookies in der Datenbank finden und entfernen.

Dieser Inaktivitätszeitraum bis zur Löschung kann dann vielleicht nur eine oder zwei Wochen lang sein. Lang genug, um ein verlängertes Wochenende zu überleben, aber nicht viel länger.

Nutzer*innen die Invalidierung von nicht mehr benötigten Cookies ermöglichen

Auch die Nutzer*innen selbst einzubinden kann ein weiterer Faktor sein, um abhanden gekommene Cookies schadlos zu machen. Hier würde eine Anzeigeseite benötigt, die alle aktiven Cookies auflistet mit weiteren Informationen dazu, damit Nutzer*innen entscheiden können, ob sie noch relevant sind. Die Nutzer*innen brauchen dann eine Möglichkeit nicht mehr notwendige Cookies zu löschen.

Generelles Nutzerverhalten

Schließlich kann auch das Verhalten der einzelnen Nutzer*innen Indikatoren bieten: Ist eine Person normalerweise nie am Wochenende im System unterwegs oder an Feiertagen? Und dann immer zwischen 9 und 17 Uhr? Dann kann der Zugriff außerhalb solcher Zeiten zumindest dazu führen, dass das Login erneut vorgenommen werden muss.

Solche Auswertungen müssen aber, zumindest wenn sie personenscharf gemacht werden und nicht aus generellen Regeln entspringen, in datenschutz- und personalrechtlicher Hinsicht geprüft und abgesichert werden. Hier gerät man ggf. tief in das Spannungsfeld zwischen IT Sicherheit, die möglichst viele Daten sammeln will, und anderen Regelungen, die genau das Gegenteil verlangen.

Fazit

Es gibt also eine ganze Reihe von denkbaren Indikatoren, die man – wenn schon nicht zum Schutz vor Diebstahl – dann wenigstens zur Abmilderung seiner Schadfolgen einführen kann. Meine Favoriten sind dabei diese:

  1. Nutzer*innen müssen sehen, welche Cookies für ihren Account aktiv sind, und sie bereinigen können
  2. Inaktive Cookies schneller bereinigen als aktive
  3. Der Verwendungszähler bei Cookies ist einfach zu implementieren und bietet zugleich einen hohen Schutz
  4. User Agent String des Webbrowsers: Hier könnte man zunächst die ganz einfache Implementierung testen, die bei jeder Änderung dieser Kennzeichnung das Cookie invalidiert
  5. ASN und Geolokation, da insbesondere die Geolokation weitere Anwendungen hat, z. B. bei der Information von Nutzer*innen über Logins von neuen Geräten

Grundsätzlich braucht es für alle diese Vorgehensweisen eine Datenbank der aktiven Login Cookies, die die entsprechenden Informationen wie den Zeitpunkt der letzten Verwendung, den User Agent String, etc. aufnimmt und damit für vergleichende Auswertungen zugänglich macht.

Umgang mit anschlagenden Indikatoren

Wenn wir nun einen IdP haben, der alle diese Indikatoren hat, eine umfangreiche Datenbank mit dem Verlauf dieser Indikatoren führt und vielleicht sogar automatisierte Auswertungen machen kann, die über einzelne Nutzer*innen hinweg gehen um ein Gesamtbild zu erhalten, wie gehen wir dann damit um, dass einer oder mehrere Indikatoren anschlagen? Hier ist eine große Spannbreite vorstellbar:

  • Stilles Löschen des verdächtigen Cookies und Neulogin der Nutzer*innen: Hier würde der IdP das vom Webbrowser kommenden Cookie nicht mehr akzeptieren und aus seiner Datenbank entfernen und aus Sicht der Nutzer*innen einfach ein erneutes Login verlangen. Diese Vorgehensweise erzeugt im IT Betrieb keine weitere Arbeit, würde aber einen erfolgten, zumindest teilweise erfolgreichen Angriff nicht weiter auffallen lassen
  • Information an die Nutzer*innen: Hier würde eine Information an die Nutzer*innen beim Loginvorgang stattfinden, die auf ‚ungewöhnliche Aktivitäten‘ in ihrem Konto hinweist und sie auffordert eine Prüfung durchzuführen. Für so eine Prüfung müsste es allerdings eine Grundlage geben wie z. B. die Auswertung der Zugriffsprotokolle samt entsprechender Informationen. Dieses Vorgehen hat aber vermutlich wenig Zweck: Nutzer*innen würden erfahrungsgemäß die Hinweise entweder ignorieren, oder sich aufgeschreckt an den IT Support mit dem Wunsch wenden, diese Prüfungen für sie durchzuführen
  • Hintergrundauswertungen mit Information an die Systemadministration: Hier würden aus den Indikatoren generierte Alarme zunächst an die zuständige IT Administration gegeben, die sie bewerten müsste. Wenn der IT Betrieb entsprechend aufgestellt ist könnte dies die Reaktionszeit bei echten Vorfällen deutlich verkürzen und es könnte eine übergreifende Sichtweise eingenommen werden. Auf der anderen Seite dürften die Indikatoren und die ausgelösten Alarme dann nicht so sensibel sein, dass es hier zu häufigen Fehlalarmen und damit zur Ermüdung der zuständigen Personen kommt. Ein SIEM System könnte aber vielleicht ein guter Abnehmer für solche Signale sein und sie dann mit Indikatoren aus anderen Systemen zusammenführen

Ein ANTRL 4 Setup mit Maven

ANTRL – ANother Tool for Language Recognition – ist ein leistungsfähiges Werkzeug um Lexer und Parser aus einer Grammatik zu generieren, mit denen sich dann die so definierte Sprache verarbeiten lässt. ANTLR kann den Parsercode in verschiedenen Zielsprachen generieren, ist aber selbst in Java geschrieben. Es sollte sich daher direkt in ein Java Projekt mit Maven Build integrieren lassen. 

Da es mich dann doch einige Zeit mit Google und ChatGPT gekostet und am Ende noch einen Blick in den Quellcode erfordert hat um herauszufinden, wie das genau funktioniert, will ich das hier einmal aufschreiben. Aber zunächst zwei Video Empfehlungen:

Wie soll mein Maven Projekt aussehen

Es soll ein JAR aus dem Projekt herausfallen, welches als Abhängigkeit in einem größeren Projekt genutzt wird. Ziel ist es dabei, den aus der Grammatik erzeugten Parser direkt mit Code zu verknüpfen, der ihn konkret einsetzt. Also muss der ANTLR Code im Idealfall im Verzeichnis liegen, welches Maven für die Quellcodes verwendet. Das Projekt hat grundsätzlich eine Standardstruktur mit separaten Verzeichnissen für die ANTLR Bestandteile:

ANTLRProjekt
└ src/
  └ main/
    └ java/
      └ hen/bru/antlr/
        └ App.java
        └ aappro/
          └ <generierte ANTLR Klassen>
    └ antlr/
      └ <ANTLR Grammatik,.g4-Datei>
  └ test/
└ target/

Der Begriff ‚aappro‘ kommt aus dem konkreten Anwendungsfall, der mit der Approbationsordnung für Ärzte (ÄApprO) zu tun hat.

Anlage der Grammatik

Für die Grammatikdatei legt man unter main/ einfach den Ordner antlr/ an und darin AApprOAusdruck.g4:

...
    └ antlr/
      └ AApprOAusdruck.g4
...

Wenn man in seiner IDE ein Tool wie den ANTLR4 language support for Visual Studio Code hat legt dieses ggf. dann schon los und erzeugt an einer Stelle außerhalb des CLASSPATH generierte Dateien, die man zur Vorschau verwenden kann.

ANTLR Maven Plugin ergänzen

Um den Maven Prozess nutzen zu können, wird in der pom.xml eine Konfiguration in der hier gezeigten Art ergänzt. Zusammen mit den Abhängigkeiten erhält man z. B. das:

<project xmlns="http://maven.apache.org/POM/4.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>hen.bru.antrl</groupId>
  <artifactId>AntlrTest</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>AntlrTest</name>
  <properties>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
  </properties>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>org.antlr</groupId>
      <artifactId>antlr4-runtime</artifactId>
      <version>4.13.1</version>
    </dependency>
    <dependency>
      <groupId>org.antlr</groupId>
      <artifactId>antlr4</artifactId>
      <version>4.13.1</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.1</version>
        <configuration>
          <release>17</release>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.antlr</groupId>
        <artifactId>antlr4-maven-plugin</artifactId>
        <version>4.13.1</version>
        <executions>
          <execution>
            <id>antlr</id>
            <goals>
              <goal>antlr4</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>

Wenn man nun maven compile aufruft wird gleich die Generierung der Klassen aus der Grammatik durchgeführt. Aber hier tritt das erste Problem auf: Die Klassen werden per Default im /target-Verzeichnis abgelegt, wo sie VS Code zumindest nicht ohne weitere Konfiguration für die Entwicklung von darauf aufbauendem Code im Projekt erkennt.

Den Pfad für die generierten Dateien anpassen

Um den Defaultpfad zu ändern muss im plugin-Abschnitt eine configuration ergänzt werden:

...
      <plugin>
        <groupId>org.antlr</groupId>
        <artifactId>antlr4-maven-plugin</artifactId>
        <version>4.13.1</version>
        <executions>
          <execution>
            <id>antlr</id>
            <configuration>
              <outputDirectory>${project.build.sourceDirectory}/hen/bru/antlr/aappro</outputDirectory>
            </configuration>
            <goals>
              <goal>antlr4</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
...

Damit wird das gewünschte outputDirectory spezifiziert und nun werden die generierten Quellcodes dort abgelegt, wo sie die IDE – und auch Maven weiterhin – findet. Aber in einem eigenen Package, damit sie sich ggf. einfach auf einen Schlag löschen lassen. Das ist manchmal der schnellste Weg, wenn sich die Toolchain verknotet hat.

Das fehlende Package im Java Code

Nun tritt aber das nächste Problem auf: Die generierten Java Klassen haben keine package-Definition und der Compiler beschwert sich darüber zurecht. Ein Irrweg zur Lösung waren die header-Definitionen, die man in der Grammatikdatei einfügen kann:

grammar AApprOAusdruck;

@parser::header { package hen.bru.antlr.aappro; }
@lexer::header { package hen.bru.antlr.aappro; }
...

Damit bringt man zwar die Paketdefinition in die Klassen, die zu Lexer und Parser gehören, aber nicht in die Listener- und Visitorklassen. Das hat früher mal so funktioniert, wurde aber in Zuge eines Bugfixes abgestellt.

Generell hat es mich überrascht, wie kompliziert es schien diese doch eigentlich generell übliche Vorgehensweise – wer legt schon seine Java Klassen ganz an die Spitze seiner Pakethierarchie!? – umzusetzen. Der entscheidende Hinweis war dann, dass sich in der Kommandozeilenversion des Tools ein -package-Parameter befindet, der genau diese umfassende Wirkung hat.

Was ich dann erst mit Blick in den Quellcode – zum Glück möglich bei Open Source Software – verstanden habe ist, wie man in Maven diesen Parameter setzt. Und zwar so:

...
      <plugin>
        <groupId>org.antlr</groupId>
        <artifactId>antlr4-maven-plugin</artifactId>
        <version>4.13.1</version>
        <executions>
          <execution>
            <id>antlr</id>
            <configuration>
              <outputDirectory>${project.build.sourceDirectory}/hen/bru/antlr/aappro</outputDirectory>
              <visitor>true</visitor>
              <listener>false</listener>
              <arguments>-package,hen.bru.antlr.aappro</arguments>
            </configuration>
            <goals>
              <goal>antlr4</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
...

Das entscheidende ist hier der arguments-Parameter und das man hier -package und den Paketnamen nicht per Leerzeichen wie auf der Kommandozeile, sondern per Komma trennen muss. Dann funktioniert es perfekt. Die beiden anderen Optionen steuern nun noch die Generierung der Listener-Klassen (hier unterdrückt) der Visitor-Klassen (hier gewünscht).

Und damit läuft es dann endlich rund: Nach jeder Änderung der Grammatik erzeugt ein Maven Lauf die neuen, generierten Klassen und die lassen sich nahtlos im selbst erstellten Code verwenden.

Passworte richtig hashen

TL;DR: Dieser Post setzt auf den vorherigen Post zu Lastpass auf und betrachtet die Fragen, die man sich als IT Betrieb dazu stellen sollte, wie man Passworte – generell Logindaten/Credentials – sicher ablegen kann: Welche Verfahren gibt es, welche sind zeitgemäß, und wie lange würde es heute wohl dauern bis Angreifer, die die komplette Logindatenbank stehlen konnten, die Daten entschlüsseln und für sich nutzbar machen können.

Der letzte Post über den Wechsel von Lasspass zu Bitwarden hat ein Thema gestreift, welches danach auch in Gesprächen unter Kollegen noch einmal vertieft wurde und mich schon früher beschäftigt hat:

Wie legt man als IT Betrieb die Passworte der eigenen Nutzer*innen so in den Systemen ab, dass sie möglichst (lange) sicher sind? Selbst im Falle eines Einbruchs in der Art, wie ihn Lastpass erfahren hat?

Es geht hier also um ein Szenario, bei dem Angreifer die gesamten Passworte bzw. Logincredentials abgreifen können, sei es aus den produktiven Systemen, oder wie bei Lastpass aus Backups. Und dann mit allen ihnen zur Verfügung stehenden Ressourcen versuchen können diese zu entschlüsseln.

Warum den Angreifern überhaupt Stolpersteine in den Weg legen?

Wenn Angreifer schon so tief in die Systeme vorgedrungen sind: Was macht es dann noch für einen Sinn sich Gedanken darüber zu machen, ob Passworte mehr oder weniger einfach zugänglich irgendwo herumliegen? Dafür gibt es mehrere Gründe:

  • In Szenarien wie bei Lastpass, bei denen die Daten aus Backups geholt wurden, sind die Angreifer nicht in die produktive Infrastruktur vorgedrungen (zumindest hofft man das). Gut gesicherte Passworte bringen hier die Angreifer zunächst nicht viel weiter
  • Selbst wenn Angreifer tiefer in die Systeme vorgedrungen sind haben sie vielleicht noch nicht die Zugänge, die sie brauchen um noch größeren Schaden anzurichten. Auch hier schützen nicht einfach zugängliche Passworte davor, dass es Angreifer zu leicht haben
  • Schließlich ist dies auch ein Schutz nach innen: Wenn es auch der IT Abteilung selbst nicht möglich ist Passworte im Klartext zu ermitteln kommt man gar nicht erst in die Versuchung risikoreiche ‚Abkürzungen‘ zu nehmen (‚Moment, ich suche Ihnen gerade Ihr vergessenes Passwort raus‘, ‚Wir können uns doch mal als meyer37 anmelden um zu prüfen, was genau bei dem Kollegen nicht funktioniert, dass machen wir immer so.‘, …)

Die Gründe, warum eine IT Abteilung manchmal gerne Passworte im Klartext hätte – z. B. um schwache Passworte zu finden, oder um sie in neu gegründete Systeme überführen zu können – müssen hier letztlich als nachrangig eingestuft werden.

Verschlüsseln oder hashen

Um Passworte nicht im Klartext abzulegen, aber vielleicht doch die Option zu behalten diesen Klartext verfügbar zu machen, könnte man die Passworte verschlüsseln, z. B. mit einem symmetrischen Verfahren wie AES. Im Fall eines Einbruchs in die eigenen IT Systeme besteht allerdings das Risiko, dass dann auch der oder die Schlüssel mit entwendet werden. Bei so einer Vorgehensweise müsste schon ein durchaus wesentlicher Aufwand betrieben werden um die Verschlüsselung selbst wieder sicher zu machen. So ist es den Angreifern beim Lastpass Hack gelungen die Schlüssel zu dem eigentlich verschlüsselten Backup zu erhalten.

Seit langen ist daher die Ablage von Passworten in Form eines Hashes Standard. Hier wird das Passwort unter Verwendung eines Hashfunktion in ein Format – den Hashwert – überführt, welches sich durch diese Eigenschaften auszeichnet:

  • Aus dem Hashwert lässt sich der Originalwert – hier das Passwort – nur sehr schwer wieder ermitteln, im Idealfall nicht viel schneller als durch Durchprobieren aller möglichen Eingaben
  • Der Hashwert hat immer ein identisches Format z. B. mit der gleiche Länge, unabhängig davon wie der Eingabewert war

Zwei klassische Hashfunktionen sind MD5 und SHA-1. Das sind Beispiele für Hashwerte:

EingabewertMD5 HashSHA-1 Hash
abc900150983cd24fb0d6963f7d28e17f72a9993e364706816aba3e25717850c26c9cd0d89d
Der Hashwert hat immer ein identischen Format wie die gleiche Länge, unabhängig davon wie lang der Eingabewert war78eb98ec466e8b9dfd1ffcac23ccd690b5447826036922409c4f77f50ead0432fb5da892
Beispiele für Hashing

Bei einem Loginvorgang werden dann die von Nutzer*innen eingegebenen Passworte erneut durch die Hashfunktion geschickt und dann dieses Ergebnis mit dem beim Setzen des Passwortes erzeugten Hash verglichen. Bei so einer Vorgehensweise braucht es keine geheimen Schlüssel oder dergleichen, der Hash an sich ist ’sicher‘ genug. Wenn er denn richtig gewählt wird und um das schon vorweg zu nehmen: MD5 und SHA-1 sind heute nicht mehr sicher genug! Aber dazu kommen wir gleich, zuerst noch zwei Kochzutaten:

Den Regenbogen versalzen (und pfeffern)

Die Eigenschaft von Hashfunktionen, für die gleiche Eingabe immer zum gleichen Hashwert zu führen, hat bei der Verwendung zur Passwortsicherung zwei Nachteile

  1. Es ist für einen Angreifer, der eine große Menge von gehashten Passworten erhalten hat, direkt erkennbar welche Nutzer*innen identische Passworte nutzen. Hier kann man also mit einem erfolgreich entschlüsselten Passwort gleich mehrere Konten übernehmen
  2. Die Arbeit des Passwortbrechens kann schon vor dem Angriff geleistet werden, in dem man lange im Voraus für riesige Mengen von möglichen Passworten die Hashwerte berechnet und dann nur noch in einer Tabelle – für die sogar eine besonders effiziente Struktur mit dem Namen Rainbow Table entwickelt wurde – nachsehen, welcher Hashwert zu welchem Passwort gehört

Es gibt aber ein einfaches Mittel um Angreifern zumindest diese Abkürzungen zu vermiesen: Bevor das Passwort in die Hashfunktion gesteckt wird vermischt man es noch mit einem zufälligen Wert, der für jedes Passwort individuell erzeugt wird. Erst die Kombination aus diesem Zufallswert – für den sich der Name Salt eingebürgert hat – und dem Passwort wird in die Hashfunktion gesteckt. In der Passwortverwaltung speichert man dann das Salt zusammen mit dem Hashwert, da es für die Überprüfung eines beim nächsten Login eingegebenen Passworts benötigt wird.

Der Angreifer muss dann die Hashwerte für das jeweilige Salt berechnen und wenn dies groß genug ist lohnt sich kein Rainbow Table, da dieser die Kombinationen von allen Salts – wirklich allen, wenn es ein echter Zufallswert ist – und möglichen bzw. wahrscheinlichen Passworten enthalten müsste. Jedes Passwort muss also einzeln und mit entsprechendem Rechenaufwand ermittelt werden.

Eine weitere Ergänzung kann dann ein Pepper-Wert sein: Dieser funktioniert ähnlich wie das Salt, er ist also ein zufälliger Wert, der mit dem Passwort vermengt wird, er wird aber nicht zusammen mit dem Passworthash abgelegt, sondern zum Beispiel in der Konfiguration des Servers, der die Loginvorgänge abwickelt. Er ist also für alle Passworte identisch.

Wann bringt dies einen Schutz? Wenn ausschließlich die Datenbank mit den hashten (und gesalzenen) Passworten abhanden gekommen ist, aber nicht die Serverkonfiguration mit dem Pepper, dann kann ein Angreifer mit diesen Daten nichts mehr anfangen, da ihm ein entscheidendes Geheimnis fehlt um zu überprüfen, ob er ein Passwort richtig geraten hat.

Falls hingegen die Daten der kompletten IT Landschaft gestohlen wurden ist es nur eine Frage der Komplexität dieser Landschaft, ob es Angreifern gelingt zu verstehen wie das Ganze funktioniert und wo der Pfeffer wächst.

Gutes Hashen, schlechtes Hashen

Es gibt eine große Anzahl von Hashfunktionen und nicht alle sind gleich gut geeignet für die Erzeugung von Passworthashes. Tatsächlich sind die oben genannten Funktionen MD5 und SHA-1 nach heutigem Stand überhaupt nicht mehr geeignet, wie sich später in den Abschätzungen für die Entschlüsselungsdauern zeigen wird.

Warum sind sie nicht geeignet? Dieses Hashes wurden für andere Zwecke entwickelt und zwar zur Prüfung ob Dokumente bzw. Datenpakete unverändert sind. In dem ich ein PDF oder ein Softwarepaket durch so eine Hashfunktion schicke kann ich den erhaltenen Wert zur Prüfung mitgeben, ob das Dokument noch so ist, wie es ursprünglich einmal erzeugt oder verschickt wurde. Alle großen Softwarepakete – hoffe ich jedenfalls – bieten auf ihren Downloadseiten auch die Prüfsummen (Hashwerte) an – die der Hersteller selbst ermittelt hat. Wer es ganz genau nimmt erzeugt diese Prüfsumme nach dem Download auf seinem Rechner dann selbst und vergleicht. Nur wenn die Werte Zeichen für Zeichen übereinstimmen kann man sicher sein, dass die Datei noch so ist, wie sie vom Ersteller einmal produziert wurde.

Bei diesen Nutzungen von Hashfunktionen kommt es auf zwei Dinge an: Es muss sehr schwer sein für eine gegebene Prüfsumme ein anderes – gefälschtes – Dokument zu erzeugen, welches die gleiche Prüfsumme ergibt. Und zweitens: Performance. Diese klassischen Hashverfahren sollen möglich wenig Rechenzeit verbrauchen, damit sie auch bei hohen Durchsatzraten einsetzbar sind.

Performance ist genau das, was wir bei Passworthashes nicht wollen!

Die Möglichkeit eine Hashfunktion schnell auszuführen spielt beim Loginvorgang nur eine begrenzte Rolle, ob unsere Nutzer*innen bei diesem Schritt eine Sekunde warten müssen oder nicht werden sie kaum bemerken bzw. es bei diesem seltenen Vorgang akzeptieren. Für einen Angreifer, der Milliarden von Passworthashes erzeugen muss, macht es hingegen einen riesigen Unterschied, ob ein Hash sich in einer Microsekunde berechnen lässt, oder in einer Millisekunde.

Es gibt dabei die grundlegende Schwierigkeit, dass unsere eigenen Server, die die Logins verarbeiten und den Passworthash dabei erzeugen müssen, nicht so performant sein werden wie die spezialisierte Hardware, die Angreifer ggf. ins Feld führen können. Wir müssen also generell in Kauf nehmen, dass Angreifer in der Lage sein werden viel schneller Hashes zu erzeugen als wir selbst. Die Frage ist nur, wie viel schneller?

Die klassischen, performanten Hashfunktionen wie die SHA-2 Familie lassen sich eigentlich nur auf eine Weise für Passworthashes einsetzen: Durch Erhöhung der Rundenzahl. Damit ist gemeint, dass man den aus dem Passwort (und Salt und Pepper) berechneten Hash erneut in die Hashfunktion steckt. In dem Post zu Lastpass steckt dieser Aspekt in der Frage wie viele Runden im PBKDF2-Verfahren gemacht werden sollten. Hier geht es also ggf. um Millionen von Runden, bei denen der Hashwert immer wieder neu berechnet wird. Für ein produktives Loginsystem sind dabei vermutlich noch viel höhere Werte möglich, da man im Gegensatz zu einem Passwortmanager keine Rücksicht auf ggf. leistungsschwächere Smartphoneprozessoren nehmen muss.

Trotzdem bleibt hier das Grundproblem, dass eine Funktion verwendet wird, die letztlich performant sein soll. Aber es gibt heute Alternativen:

Unperformante Hashfunktionen: Bcyrpt, scrypt und Argon2

Das Design einer Hashfunktion, die eine ’schlechte‘ Performance zeigen soll, hat ihre eigene Komplexität und hier hat es immer neue Entwicklungen gegeben. Diese Funktionen sollen generell solche Eigenschaften haben:

  1. Sie müssen natürlich die gleichen Eigenschaften einer Hashfunktion haben, die zuvor genannt wurden
  2. Es soll auch mit spezialisierter Hardware nicht dramatisch viel einfacher sein diese Funktionen auszuführen als mit Standardhardware
  3. Im Algorithmus sind ‚Stellschrauben‘ vorhanden, die es erlauben den Rechenaufwand und bei neueren Funktionen auch den Speicherbedarf einzustellen. Je nach Verfahren in Abhängigkeit voneinander oder auch nicht
  4. Seitenkanalattacken sollen möglichst schwierig sein. Also Wege, bei denen sich z. B. über die Laufzeit des Algorithmus oder den Stromverbrauch der Hardware Informationen über das verarbeitete Passwort gewinnen lassen

Das sind die heute relevantesten Verfahren in der chronologischen Reihenfolge:

bcrypt

Diese Funktion wurde schon 1999 vorgestellt und verbessert die Passwortsicherheit im Vergleich zu den schnellen Hashes bereits deutlich. Sie verfügt über einen einstellbaren Kostenfaktor, den man an die Leistungsfähigkeit der eigenen Loginserver anpassen kann, um so einen Mittelweg zwischen der Wartezeite für die eigenen Nutzer*innen zu finden und dem Aufwand für Angreifer.

Bcrypt hat aus heutiger Sicht das Ziel nicht vollständig erreicht auch mit spezieller Hardware nicht deutlich schneller ausgeführt werden zu können: Gerade der eher geringe Speicherbedarf ermöglicht eine massive Parallelisierung der Hashwertberechnungen.

scrypt

Diese ca. 10 Jahre nach bcrypt vorgestellte Funktion ist bewusst mit einem ‚hohen‘, nicht reduzierbarem Speicherbedarf konzipiert worden. Dies verhindert den Einsatz von günstiger Hardware für massenhafte Berechnungen deutlich, während die eigenen Server damit normalerweise kein Problem haben.

Es kann sowohl der Rechnenzeit- wie auch der Speicherbedarf eingestellt werden, allerdings nicht unabhängig voneinander. Trotzdem gibt es Untersuchungen, bei denen scrypt in bestimmten Parametersetzungen schlechter – also effizienter ausführbar – abschneidet, als bcrypt. Auch gilt es aus kryptographischer Sicht immer noch als ‚junges‘ Verfahren und löst daher manchmal die Sorge aus, dass es vielleicht noch nicht erkannte Probleme hat.

Argon2

Dieses erstmals in 2014 vorgestellt Verfahren, welches dann noch Weiterentwicklungen erfahren hat, gewann in 2015 die sogn. Password Hashing Competition. Generell ist es damit das aktuellste der drei hier genannten Verfahren, mit den Vor- und Nachteilen, die das mit sich bringt:

Argon2 ist am flexibelsten bei den Einstellungen für Rechenzeit und Speicherbedarf und in Kenntnis der durch spezialisierte Hardware verfügbaren Rechenleistung entwickelt worden. Auf der anderen Seite in kryptographischer Sicht noch jünger und damit potentiell angreifbarer.

In OWASP Password Storage Cheatsheet werden konkrete Empfehlungen für die Parametrisierung dieser Funktionen gegeben.

Wie schnell lassen sich Passworte heute cracken

Es gibt Videos wie dieses, in dem man sich anschauen kann wie man hashcat, ein beliebtes ‚password recovery‘ Tool, einfach an den Start bringt. Aber die Rechenleistung des eigenen Rechners vermittelt einem nur ein ungenügendes Bild davon, was Angreifern potentiell zur Verfügung steht. Interessanter ist da der jährliche Password Table von Hive Systems (nicht zu verwechseln mit der Hive Ransomware Gruppe). Die folgenden Graphiken und Zahlen stammen aus dem Bericht 2022.

Hive Systems hat jeweils ermittelt wie viele Hashes in unterschiedlichen Hashverfahren mit damals verfügbaren Graphikkarten pro Sekunde berechnet werden können und auf dieser Basis geschätzt, wie lange es dauern würde die Hashes für alle denkbaren Passworte einer bestimmten Länge und Zusammensetzung zu berechnen. Und sie haben auch gleich verglichen welche Rechenleistung in der Cloud verfügbar wäre! Es gibt z. B. von Amazon kleine GPU Cluster, die man für überschaubare Kosten mieten kann.

Diese Graphik zeigt die Crackingdauern für Passworte im MD5 Hash mit dem größten damals in der Amazon Cloud verfügbaren Cluster mit 8 GPUs. Während die getestete Graphikkarte auf ca. 70 Milliarden MD5 Hashes pro Sekunde kommt, ist der Cluster in der Cloud in der Lage mehr als 500 Milliarden Hashes zu berechnen. Damit kommt Hive auf diese Tabelle:

Dauer zum Cracken von MD5 gehashten Passworten in der Amazon Cloud. Quelle: Hive Systems

Ein 8 Zeichen langes Passwort – wohlgemerkt jedes 8 Zeichen lange Passwort! – kann also in der Cloud in weniger als einer Stunde errechnet werden. Wenn man bedenkt, dass die meisten von uns keine wirklich zufälligen Passworte verwenden mit Groß- und Kleinschreibung und Zahlen und weiteren Zeichen, wird es meist noch viel schneller gehen. Daher sind auch Passworte mit mindestens 12 Zeichen, wie sie das BSI aktuell empfiehlt, nicht lange sicher, wenn sie als MD5 Hash gespeichert werden.

Der Artikel von Hive vergleicht dabei die in 2022 aktuellen Zahlen mit der vorherigen Auswertung in 2020. Und kann deutliche Rechenleistungssteigerungen zeigen. Ein Passwort, dass heute noch 5 Jahre zur Ermittlung brauchen würde, ist daher in einem Jahr vielleicht schon in der Hälfte der Zeit knackbar.

Und letztlich sind diese Zahlen bzw. die hier eingesetzte Hardware keine Obergrenze: Es gibt spezielle Hardware mit deutlich mehr Leistung und Software wie die von Elcomsoft, die in der Lage ist die Arbeit auf zehntausende von Rechnern zu verteilen.

In den weiteren Auswertungen zeigt sich dann der Vorteil von bcrypt. Diese Graphik basiert auf dem gleichen Hardwareszenario, nur dieses Mal mit bcrypt Hashes:

Dauer zum Cracken von bcrypt gehashten Passworten in der Amazon Cloud. Quelle: Hive Systems

Mit bcrypt ist die Anzahl der Hashes pro Sekunde im Amazon GPU Cluster auf eine Million zurückgefallen. Es geht aus dem Artikel leider nicht hervor, mit welchem Kostenfaktor die Hashes erzeugt wurden. Da die Erhöhung des Kostenfaktors um 1 die Rechenzeit für einen Hash in etwa verdoppelt ist es ein deutlicher Unterschied, ob der Faktor 1 oder 15 war.

In dieser Konstellation müssen Angreiferdeutlich mehr Hardware einsetzen, oder gut darin sein den Suchraum einzugrenzen, um in vernünftiger Zeit zu einem Erfolg zu kommen. Auch wenn bcrypt heute nicht mehr als das modernste Verfahren gilt, ist es weiterhin in der Lage Angriffe auf Passworthashes deutlich zu verlangsamen.

Und trotzdem: Es kommt weiterhin auf die Passwortqualität an

Man sieht an den Auswertungen deutlich, welche Verantwortung als IT Betrieb man bei der sicheren Ablage von Logindaten hat. Aber man sieht auch: Wenn die verwendeten Passworte schlecht sind – zu kurz, zu einfach, in vielen anderen Diensten verwendet – nutzt auch das beste Hashverfahren nichts.

Eine Absicherung der Infrastruktur muss also auf allen Ebenen zugleich erfolgen, damit sie auch in dem hier beschriebenen Szenario wirksam werden kann. Und eine 2-Faktor-Authentifizierung kann helfen den unmittelbaren Schaden eines Verlusts der Passworte zu begrenzen. Sofern die dafür notwendigen Geheimnisse nicht gleich mit gestohlen wurden.