|
|
Veröffentlicht am 31.07.2023 18:36:01
|
|
|
|

An einem sonnigen Morgen saß ich vor meinem Laptop und strukturierte C#-Code. Alles läuft gut und es wird ein produktiver Tag. Dann habe ich zu viele Gleichheitszeichen zum konstanten String-Literal hinzugefügt, und alles explodierte. Die Produktivität ist weg. Der ruhige Wiederaufbau am Sonntag liegt hinter uns. Sogar die Sonne beschloss, sich hinter den Wolken zu verstecken.
Nachdem ich 30 bis 40 Minuten damit verbracht hatte herauszufinden, was ich falsch machte, wurde mir klar, dass ich es nicht war. Es ist Microsoft. Anscheinend bin ich auf einen alten Fehler in der Base64-Dekodierungsfunktion gestoßen.Convert.FromBase64StringDieser Fehler gibt es definitiv schon seit der Einführung von .NET 1.1 im Jahr 2003. Beeindruckend! Das ist alt. Und es ist nicht sehr schwer, sie zu vermehren. Gut Gemacht:
Technisch gesehen ist das illegales Base64. Die rechtliche Version lautet "abc=". Beachte: nur ein Füllzeichen =. Die Base64-Codierung repräsentiert alle 6 Bits der binären Eingabe in einem ASCII-Zeichen. Das bedeutet, dass alle 4 Zeichen in einer Base64-codierten Zeichenkette 3 Bytes darstellen. Wenn die kodierten Daten kein Vielfaches von 3 Bytes sind, fügt der Base64-Encoder ein Füllzeichen hinzu, sodass Base64 ein Vielfaches von 4 Zeichen ist. Dies erzeugt eine Base64-Zeichenkette, die korrekt mit "abc=" gefüllt ist. Das Hinzufügen eines weiteren = wird es ungültig.
Base64 "abc=" wird als zwei Bytes decodiert [105, 183]. Das stimmt. Das Hinzufügen eines weiteren Padding-Zeichens am Ende sollte den codierten Wert eigentlich nicht verändern. Es ist, als würde man am Ende eines Satzes einen Leerraum hinzufügen. Ja, es ist da, aber es ändert nicht die Bedeutung des Satzes. Aber .NET sieht das nicht so. "abc==" wird als Byte decodiert [109]. Nicht nur wurde es kürzer, was seltsam war, weil wir die Eingabe verlängert hatten. Es ist auch anders geworden. Das erste Byte geht von 105 auf 109. Und es gab auch keine Ausnahme. Füge ein anderes = hinzu und du bekommst eine Ausnahme. Verblüffend!
Code:
Ausgabe:
'abc=' -> [105, 183] 'abc==' -> [109] Es ist wirklich erstaunlich, dass das seit so vielen Jahren niemand bemerkt hat. Oder es wurde gefunden, aber nicht repariert. Base64 ist sehr wichtig für den Informationsaustausch im Netzwerk. Es ist überall zu sehen. Allerdings hat .NET den fehlerhaften Base64-Decoder seit Jahren nicht mehr entfernt.
Zuerst konnte ich es kaum glauben und begann zu recherchieren. Ich habe eine Weile gegoogelt und nicht viel gefunden. Dann habe ich auf StackOverflow gepostet und hatte auch wenig Glück. Als ich herausgefunden hatte, was los war, musste ich sogar meine eigenen Fragen beantworten. Nach einer Weile auf GitHub stieß ich im Juli 2018 auf eine Lösung, die in .NET Core erstellt wurde. Die neueste .NET Core-Version behandelt dieses Problem also korrekt und wirft eine Ausnahme:
Unhandled Exception: System.FormatException: Die Eingabe ist kein gültiger Base-64-String, da sie ein Nicht-Basis-64-Zeichen, mehr als zwei Füllzeichen oder ein illegales Zeichen unter den Charaktere aufpolstern. bei System.Convert.FromBase64CharPtr(Char* inputPtr, Int32 inputLength) bei System.Convert.FromBase64String(String s) bei Program.DecodeAndPrint (String base64) in ./base64/Program.cs:Zeile 13 bei Program.Main() in ./base64/Program.cs:Zeile 8 Es dauerte etwa 15 Jahre, bis sie das Problem gefunden und behoben hatten. Interessanterweise hat niemand wirklich versucht, es gezielt zu beheben. Das geschah, als sie den Code umschrieben, um ihn schneller zu machen:
Convert.FromBase64() hat einen subtilen Fehler, bei dem das zweite, illegal gepolsterte Zeichen am Ende der Zeichenkette das Dekodieren "erfolgreich" macht, indem es das vorletzte Zeichen entfernt.
Wir sind bei . Dieser Fehler wurde unbeabsichtigt behoben, als die API in NetCore 2.1 optimiert wurde. Fügen Sie Tests hinzu, um Fehler zu protokollieren, und stellen Sie sicher, dass wir nicht rückwärts gehen. Dieses Problem ist also in .NET Core 2.2 behoben. Aber in der aktuell neuesten Version des .NET Framework 4.7.2 gibt es immer noch Probleme. Es sieht auch so aus, als wäre es in Mono kaputt.
Der Workaround in .NET 4.7.2 besteht darin, die falsch befüllte Zeichenkette mit etwas wie diesem zu füllen:
Original:Der Hyperlink-Login ist sichtbar.
|
Vorhergehend:Azure DevOps (viii) Kompiliert ASP.NET MVC-Projekte mit Pipelines BuildNächster:Ein neuer Timer in .NET 6, PeriodicTimer, wird verwendet
|