1 Punkte von GN⁺ 3 시간 전 | 1 Kommentare | Auf WhatsApp teilen
  • Im 6-stelligen E-Mail-Bestätigungsfeld des Schweizer Government-Login-Systems AGOV konnten Zahlen auf französischen AZERTY-Tastaturen nicht verarbeitet werden, sodass die Kontoerstellung vollständig blockiert war.
  • Das JavaScript des Eingabefelds fing Tastenanschläge ab und speicherte den Bestätigungscode in einer separaten Variable, wobei es die Shift-Taste ignorierte; damit wurden AZERTY-Layouts, bei denen für Ziffern Shift nötig ist, faktisch ausgeschlossen.
  • Derselbe Fehler trat in verschiedenen Kombinationen aus Firefox, Chromium, Chrome, Safari sowie Linux und macOS auf, funktionierte aber mit QWERTY-Tastaturen normal, wodurch sich das Problem nicht auf Browser oder Betriebssystem, sondern auf das Tastaturlayout eingrenzen ließ.
  • Auch der offizielle Support war nur nach derselben E-Mail-Bestätigung nutzbar, und es gab keine Alternativen wie E-Mail oder Telefon, sodass Nutzer, die sich nicht einloggen konnten, den Login-Bug nicht einmal melden konnten.
  • Wenn statt nativer Eingabefelder komplexe Tastenlogik verwendet wird und Produkt sowie Support-Kanäle an denselben Authentifizierungsablauf gekoppelt sind, brechen Zugänglichkeit und Störungsbearbeitung gemeinsam zusammen; nötig sind daher einfache DOM-basierte Eingaben und unabhängige Support-Kanäle.

AGOV als digitale Identitätsinfrastruktur

  • Digitale Identität ist zuletzt zu einem zentralen Streitpunkt im Web geworden und bringt zahlreiche Abhängigkeiten und Kontroversen mit sich.
  • Das Schweizer Government-Login-System AGOV ist seit 2024 in Betrieb und hat 1,6 Millionen Konten erreicht.
  • Es wird als Login-Mittel für verschiedene Behördendienste ausgeweitet, darunter Arbeitslosenversicherung und die verpflichtende Steuererklärung.

Registrierung stoppt beim E-Mail-Bestätigungsschritt

  • Das AGOV-Registrierungsverfahren beginnt nach Eingabe einer E-Mail-Adresse mit der Eingabe eines 6-stelligen Bestätigungscodes.
  • Die UI für den Bestätigungscode besteht aus insgesamt sechs Eingabefeldern, eines pro Ziffer.
    • Auch nach Eingabe einer Zahl springt der Fokus nicht zum nächsten Feld.
    • Im aktuellen Feld sammeln sich weiter Zahlen an, und es wechselt in einen roten Fehlerzustand.
    • Selbst wenn man manuell Feld für Feld weitergeht, erscheint am Ende der Fehler field required.
  • Es wurde versucht, die DOM-Werte direkt in den Entwicklerwerkzeugen zu ändern, aber es gab keine sichtbaren Formularwerte, und auch in der Web-Konsole wurde kein Fehler protokolliert.
  • Auch mit einer anderen E-Mail-Adresse oder einer Fake-Adresse wie test@example.com war das Ergebnis identisch.
    • example.com ist gemäß RFC 6761 eine reservierte Domain.

Browser- und Betriebssystemhypothesen ausgeschlossen

  • Zunächst lag die Vermutung nahe, dass die Kombination aus Firefox und Linux nicht unterstützt werde oder CAPTCHA fehlschlage.
    • Unmittelbar bevor das Formular für den Bestätigungscode erscheint, wird eine Verbindung zu eu-api.friendlycaptcha.eu aufgebaut.
    • In den offiziellen Anforderungsdokumenten sind als unterstützte Betriebssysteme nur Windows und macOS aufgeführt.
    • Andererseits nennen die Hinweise zu Sicherheitsschlüsseln auch Linux und Firefox als unterstützt.
  • In den folgenden sechs Umgebungskombinationen trat überall derselbe Fehler auf.
    • Firefox, Chromium und Chrome unter Linux
    • Firefox, Safari und Chrome unter macOS
  • Auf dem Arbeitslaptop sprang der Fokus nach der Eingabe automatisch ins nächste Feld, und auch die Fehlermeldung Code entered is incorrect für einen falschen statt leeren Code erschien korrekt.
  • Auch auf dem macOS-Computer eines Freundes akzeptierten alle drei Browser den Bestätigungscode.
  • Für eine langfristige Interaktion mit Behördendiensten konnte man sich nicht auf einen vom Arbeitgeber bereitgestellten Computer verlassen; selbst wenn die Registrierung auf dem Arbeitsgerät möglich war, blieb das Risiko, sich auf dem privaten Laptop später nicht einloggen zu können.

Support-Struktur blockierte sogar die Fehlermeldung

  • Der offizielle Support war nur über ein Webformular erreichbar, und auch dort musste zuerst der E-Mail-Bestätigungscode eingegeben werden.
  • In den FAQ steht, dass Support der teilnehmenden Stellen während der Geschäftszeiten nur über das Erstellen eines Online-Tickets angeboten wird.
  • Abgesehen von der Postadresse der Swiss Federal Chancellery gab es weder E-Mail-Adresse noch Telefonnummer.
  • Auch die Feedback-Funktion für Lob, Kritik oder Anfragen zu AGOV verlangte einen Login mit AGOV oder einem gleichwertigen Konto.
  • Nutzer, bei denen die E-Mail-Bestätigung scheiterte, gerieten wegen derselben Authentifizierung in eine zirkuläre Abhängigkeit und konnten das Problem nicht einmal melden.
  • AGOV Access und unterstützte Geräte

    • Die AGOV Access Android-App hatte eine Bewertung von 1,4 Sternen, doch in den Google-Play-Reviews ließ sich derselbe Bestätigungscode-Fehler nicht finden.
    • In den Bewertungen gab es viele Wünsche nach Unterstützung für das sicherheits- und datenschutzorientierte Android-Derivat GrapheneOS.
    • Laut den offiziellen FAQ funktioniert die App nicht mit GrapheneOS, weil ein Härtungs-Framework zum Schutz vor unbefugten Änderungen damit nicht kompatibel ist.
    • Die Federal Chancellery habe den Anbieter angewiesen, Kompatibilität sicherzustellen.
    • Aktuell sind als zweiter Faktor für Registrierung und Login nur zugelassene Standard-iOS-/Android-Smartphones oder Sicherheitsschlüssel erlaubt; in beiden Fällen muss zuvor die E-Mail-Bestätigung erfolgreich durchlaufen werden.

Die Ursache im JavaScript gefunden

  • Die von der Seite geladenen Ressourcen waren zwar überschaubar, doch die nicht obfuskierte, nur minimierte Haupt-JavaScript-Datei war 2,4 MB groß und umfasste ausgeschrieben über 100.000 Zeilen.
  • Durch Suche nach dem String field required ließ sich die Logik finden, die den Status des Bestätigungscodes setzt.
    • Wenn keine Variable für den Bestätigungscode vorhanden ist, wird der Status auf REQUIRED gesetzt.
    • Stimmt die Länge nicht mit der geforderten Codelänge überein, wird WRONG verwendet.
    • Bei passender Länge wird je nach Ergebnis der serverseitigen E-Mail-Bestätigung VALID oder ein Fehlerstatus gesetzt.
  • Die Funktion verificationCodeEntered fängt Tasteneingaben ab und sammelt den Bestätigungscode in einer JavaScript-Variable.
    • Enter führt den Bestätigungs-Callback aus.
    • Backspace löscht den aktuellen Wert.
    • Pfeiltasten und Tab bewegen den Fokus zwischen den Eingabefeldern.
    • Normale Tasten werden mit Number(S.key) in Zahlen umgewandelt und anschließend im Code gespeichert.
    • Tasten wie Control, Meta, Shift, v, r usw. werden nicht verarbeitet, sondern führen zu einer Rückgabe.
  • Da beim Absenden des Formulars keine DOM-Werte gelesen werden, spiegeln Änderungen an den Eingabefeldern per Entwicklerwerkzeugen oder Browser-Erweiterungen sich nicht im separat verwalteten JavaScript-Zustand wider.

Warum auf AZERTY nur Zahlen blockiert waren

  • Beim französischen Standard-AZERTY-Layout ist für die Eingabe von Ziffern die Shift-Taste erforderlich.
  • Weil der Code Shift-Eingaben ignorierte, konnten auf AZERTY die Ziffern selbst nicht als Bestätigungscode gespeichert werden.
  • Der Arbeitscomputer verwendete ein englisches QWERTY-Layout, und unter den Personen, die beim Testen halfen, war niemand Franzose.
    • Dadurch sah es so aus, als seien unter den getesteten Geräten nur zwei private Laptops defekt.
  • Nachdem das Tastaturlayout im Betriebssystem auf ein anderes Layout umgestellt wurde, funktionierte die Eingabe auch auf den privaten Laptops normal.
    • Umgekehrt ließ sich derselbe Fehler reproduzieren, wenn ein zuvor funktionierendes Gerät auf das französische Layout umgestellt wurde.
  • Das in der Schweiz übliche französischsprachige Standard-Keyboard gehört zur in Mitteleuropa verbreiteten QWERTZ-Familie.
    • Es erlaubt effizientes Tippen auf Französisch und Deutsch, und für Ziffern ist kein Shift nötig, sodass derselbe Fehler dort nicht auftritt.
  • Laut dem Swiss Federal Statistical Office leben in der Schweiz rund 171.000 Personen mit französischer Staatsangehörigkeit; Grenzgänger, die mit der Schweizer Regierung interagieren müssen, sind darin nicht enthalten.

Grenzen der Untersuchung bis zur Offenlegung des Quellcodes

  • Laut AGOV-FAQ soll der AGOV-Quellcode zur Erfüllung gesetzlicher Vorgaben im Dezember 2026 veröffentlicht werden.
  • Artikel 9 EMBAG verlangt, dass Bundesstellen den Quellcode von Software offenlegen, die sie zur Erfüllung ihrer Aufgaben selbst entwickelt oder entwickeln lassen.
    • Ausnahmen gelten, wenn Rechte Dritter oder Sicherheitsgründe die Veröffentlichung verhindern oder einschränken.
  • Veröffentlicht werden sollen die AGOV-Versionen, die die Projektziele erreicht haben, einschließlich AGOV e-ID Verifier; spätere Versionen sollen mit nach dem Release vorbereiteten Release Notes veröffentlicht werden.
  • Obwohl einige Dienste AGOV bereits als Pflicht-Login verwenden, war der Quellcode noch nicht öffentlich, weshalb Nutzer Bugs weder direkt an Entwickler melden noch Workarounds leicht teilen konnten.

Nach der Registrierung überprüfter Umfang der Identitätsprüfung

  • Nach dem Wechsel des Tastaturlayouts wurde die E-Mail-Adresse bestätigt und die Registrierung mit einem Sicherheitsschlüssel abgeschlossen.
  • Während der Registrierung wurden Name, Telefonnummer und Geburtsdatum eingegeben, diese Angaben wurden jedoch nicht verifiziert.
  • In der grundlegenden Registrierungsphase wurden nur zwei Dinge geprüft.
    • Dass die E-Mail-Adresse tatsächlich existiert
    • Dass der zweite Faktor entweder ein zugelassenes Modell eines Sicherheitsschlüssels ist oder die AGOV-Access-App auf einem zugelassenen Android- oder iOS-Gerät ausgeführt wird
  • AGOV ist robust gegen Kontoübernahmen durch Remote-Phishing, verhindert aber in der Basiseinschreibung nicht, dass jemand mit dem Namen und den Identitätsdaten einer anderen Person ein Konto anlegt.
  • Weitere Prüfung ergab, dass für als sensibel eingestufte Dienste eine Identitätsprüfung erforderlich ist.
    • Unmittelbar nach der Registrierung war auf solche Dienste noch nicht zugegriffen worden.
  • Der Bug wurde über das Support-Formular gemeldet, eine Antwort blieb jedoch aus.

Lehren aus dem Design

  • Fragiles Eingabe- und Support-Design

    • Eine auffällige UI mit sechs Eingabefeldern und komplexer JavaScript-Logik ist nicht robust.
    • Besser wäre ein einziges natives Browser-Eingabefeld, dessen visuelle Form nur per CSS gestaltet wird.
    • Wenn Formularlogik vollständig vom DOM getrennt wird, lassen sich beim Absenden keine DOM-Werte lesen, und selbst fortgeschrittene Nutzer oder Browser-Erweiterungen können Eingaben nicht korrigieren.
    • Gibt es nur einen Support-Kanal, verschwindet bei einer Störung dieses Kanals auch jede Kontaktmöglichkeit; deshalb braucht es einen zweiten Kanal wie E-Mail oder Telefon.
    • Wenn Produkt und Support-Kanal dieselbe Login-Logik verwenden, gehen Bugmeldungen von Nutzern verloren, die sich gar nicht einloggen können.
    • Viele Internetdienste betreiben aus demselben Grund Statusseiten auf einer separaten Domain.
    • Wenn Support-Anfragen erst nach E-Mail-Bestätigung möglich sind, reduziert das zwar Spam, aber auch echte Störungsmeldungen realer Nutzer.
    • Wird Quellcode erst veröffentlicht, nachdem manche Systeme die Nutzung bereits verpflichtend gemacht haben, sind Problemlösung durch Nutzer sowie das Teilen von Bugs und Workarounds eingeschränkt.
    • Gesetzlich vorgeschriebene Quelloffenlegung ist nicht nur ein Compliance-Punkt, sondern auch für die Untersuchung realer Störungen nützlich.
  • Das offene Web half bei der Untersuchung

    • Da die relevante JavaScript-Logik nicht obfuskiert war, ließ sich die Ursache schon mit einigen String-Suchen finden.
    • Weder ein fortgeschrittener Decompiler noch ein teures LLM waren nötig.
    • Wäre der Code obfuskiert oder nach WebAssembly kompiliert gewesen, hätte die Ursachenanalyse deutlich mehr Zeit gekostet.
    • Der Code wurde nicht nur für genehmigte geschlossene Betriebssysteme ausgeliefert, sondern über das offene Web, sodass er zumindest in minimierter Form heruntergeladen und untersucht werden konnte.
  • Bedingungen, die die Ursachenermittlung ermöglichten

    • Durch den Vergleich mehrerer Laptops mit unterschiedlichen Tastaturlayouts ließ sich die Wahrscheinlichkeit eines browser- oder netzwerkspezifischen Problems früh senken.
    • Allerdings kostete die systematische Erfassung der Bildschirme für jede Browser-Kombination zunächst Zeit, um auszuschließen, dass es sich um einen Bedienfehler handelte.

1 Kommentare

 
GN⁺ 3 시간 전
Lobste.rs-Kommentare
  • Eine der Praktiken, die ich im Internet besonders hasse, ist, wenn Websites Tastatureingaben abfangen und eigenmächtig verarbeiten, statt sie einfach an den Browser durchzureichen
    Websites, die Kopieren und Einfügen in Passwortfeldern verbieten, sind viel häufiger, aber das gehört in dieselbe Kategorie und wirkt vielleicht sogar noch schlimmer

    • Ich verstehe nicht, warum man Funktionen, die der Browser mit HTML und CSS bereits standardmäßig unterstützt, unbedingt noch einmal in JavaScript nachbauen muss
      Meist erhöht das die Komplexität nur aus fadenscheinigen Gründen
  • Ein Eingabefeld pro Zeichen ist wie eine Seuche
    Irgendein Unternehmen hat das eingeführt, weil es schick aussah, und jetzt baut jeder seine eigene Version davon

    • Es würde mich nicht überraschen, wenn dieses UI die Erfolgsquote bei der Eingabe von Einmalcodes tatsächlich erhöht
      Nutzer erkennen sofort, dass es sich nicht um ein Passwortfeld handelt, auch ohne den Text genau zu lesen
  • Ein verwandtes Beispiel: Medium once had a bug like this which prevented entering the character 'Ś'

  • Ich habe über andere Implementierungen nachgedacht, bin aber am Ende auf keine bessere Lösung als ein gewöhnliches <input type="text" /> gekommen
    Selbst bei CSS-Dekorationen, die es zu anders als ein normales Eingabefeld aussehen lassen, zögere ich. Man könnte den eingegebenen Wert in große Kästchen gespiegelt anzeigen, aber dann muss man alle möglichen Probleme lösen, etwa was passiert, wenn der Nutzer mehr als die erlaubte Länge eingibt, und der Nutzen ist den Aufwand nicht wirklich wert. Höchstens Schriftart und Größe des Eingabefelds würde ich ändern

    • Der häufigste Fehler bei OTPs ist, eine einzelne Ziffer falsch einzugeben, also etwa 1224 statt 1234
      Die schnellste Korrektur ist, auf die zweite 2 zu klicken und 3 zu drücken, aber das lässt sich mit reinem HTML+CSS nicht umsetzen
    • Ich gebe zu, dass es eine ziemlich alberne Idee ist, aber ich frage mich, ob man einem einzelnen <input type="text" pattern="[0-9]+" minlength=6 maxlength=6> einen ungewöhnlichen Zeichenabstand geben könnte, damit es optisch wie sechs Kästchen aussieht
      Der einfachere Weg wäre, dass der Nutzer in ein einzelnes Textfeld eingibt und JavaScript an einer anderen Stelle im DOM sechs Kästchen zeichnet, die dann über das bei jedem Tastendruck ausgelöste input-Event aktualisiert werden
      Welche Variante für die Barrierefreiheit besser wäre, ist schwer zu sagen. Aus Sicht von Screenreadern könnte Letzteres mit einem normalen <input> plus dekorativem <canvas alt=""> sogar besser sein, und auch die Tastaturbedienung würde nicht seltsam werden. Aber für Nutzer, die andere Hilfsmittel als Screenreader verwenden, kann ein visuell verstecktes <input> eine Katastrophe für die Barrierefreiheit sein, daher wäre ich damit sehr vorsichtig
  • Wie viele Dienste könnte man in der E-Mail den Code zusammen mit einem Aktivierungslink bereitstellen

    Code eingeben: XX XX XX
    
    Oder auf den Link klicken: <Weiterleitung + Aktivierungslink mit Code>  
    

    Auch das könnte dasselbe Problem lösen

    • Nutzer daran zu gewöhnen, auf Links in E-Mails zu klicken, halte ich für einen Rückschritt bei der Phishing-Abwehr
    • Wenn man die Website auf dem Laptop geöffnet hat und die E-Mail auf dem Handy erhält, ist Kopieren und Einfügen nicht besonders bequem
      Man könnte das für eine Ausnahmesituation halten, aber genau darum geht es bei Barrierefreiheit: auch mit solchen Ausnahmen richtig umzugehen
  • Tridactyl hat genau dasselbe Problem: https://github.com/tridactyl/tridactyl/issues/3257
    Es wurde erstmals 2019 gemeldet; vielleicht führt dieser Vorfall immerhin dazu, dass man es aus Scham endlich behebt

  • Das zeigt erneut, dass es viel mehr Aufwand kostet, kaputte oder langsame Websites zu bauen als Websites, die einfach funktionieren