|
|
Opslået på 31/07/2023 18.36.01
|
|
|
|

En solrig morgen sad jeg foran min bærbare og omstrukturerede noget C#-kode. Alt går godt, og det bliver en produktiv dag. Så tilføjede jeg for mange lighedstegn til den konstante streng letteralt, og tingene eksploderede. Produktiviteten er væk. Søndagens rolige genopbygning er bag os. Selv solen besluttede at gemme sig bag skyerne.
Efter at have brugt 30 til 40 minutter på at finde ud af, hvad jeg gjorde forkert, indså jeg, at det ikke var mig. Det er Microsoft. Tilsyneladende stødte jeg på en gammel fejl i Base64-dekodningsfunktionen.Convert.FromBase64StringDenne fejl har helt sikkert eksisteret siden .NET 1.1 blev introduceret i 2003. Wow! Det er gammelt. Og det er ikke særlig svært at reproducere. Godt gjort:
Teknisk set er dette ulovlig Base64. Den juridiske version er "abc=". Bemærk, kun ét fyldtegn =. Base64-kodning repræsenterer hver 6. bit binær input i ét ASCII-tegn. Det betyder, at hvert 4. tegn i en Base64-kodet streng repræsenterer 3 bytes. Når de kodede data ikke er et multiplum af 3 bytes, tilføjer Base64-encoderen et fyldtegn for at gøre Base64 til et multiplum af 4 tegn. Dette vil generere en Base64-streng, der korrekt udfyldes med "abc=". Hvis du tilføjer en anden =, vil den blive ugyldig.
Base64 "abc=" dekodes som to bytes [105, 183]. Det er rigtigt. At tilføje et ekstra fyldtegn til sidst bør ikke rigtig ændre den kodede værdi. Det er som at tilføje et mellemrum til slutningen af en sætning. Ja, det er der, men det ændrer ikke meningen med sætningen. Men .NET mener ikke det. "abc==" dekodes som en byte [109]. Ikke nok med at den blev kortere, hvilket var mærkeligt, fordi vi gjorde inputtet længere. Det er også blevet anderledes. Den første byte går fra 105 til 109. Og den gav heller ikke en undtagelse. Tilføj en anden =, og du får en undtagelse. Fantastiske!
Kodeks:
Udgang:
'abc=' -> [105, 183] 'abc==' -> [109] Det er virkelig utroligt, at ingen har lagt mærke til det i så mange år. Eller den blev fundet, men ikke repareret. Base64 er meget vigtig i informationsudvekslingen på netværket. Den kan ses overalt. Dog har .NET ikke fjernet den fejlbehæftede Base64-dekoder i årevis.
Først kunne jeg ikke tro det og begyndte at undersøge det. Jeg googlede i et stykke tid og fandt ikke meget. Så postede jeg på StackOverflow og havde heller ikke meget held. Da jeg først fandt ud af, hvad der foregik, måtte jeg endda svare på mine egne spørgsmål. Efter at have søgt på GitHub i et stykke tid, stødte jeg på en løsning lavet i .NET Core i juli 2018. Så den nyeste .NET Core-version håndterer dette problem korrekt og kaster en undtagelse:
Ubehandlet undtagelse: System.FormatException: Inputtet er ikke en gyldig Base-64-streng, da det indeholder et ikke-base 64-tegn, mere end to udfyldningstegn eller et ulovligt tegn blandt Udfylder karakterer. ved System.Convert.FromBase64CharPtr(Char* inputPtr, Int32 inputLength) på System.Convert.FromBase64String(String s) på Program.DecodeAndPrint (streng base64) i ./base64/Program.cs:linje 13 på Program.Main() i ./base64/Program.cs:linje 8 Det tog dem omkring 15 år at finde og løse problemet. Interessant nok prøvede ingen rigtig at rette det specifikt. Dette skete, da de omskrev koden for at gøre den hurtigere:
Convert.FromBase64() har en subtil fejl, hvor det andet ulovligt polstrede tegn i slutningen af strengen får dekodningen til at "lykkes" ved at fjerne det næstsidste tegn.
Vi er på . Denne fejl blev utilsigtet rettet, da API'et blev optimeret i NetCore 2.1. Tilføj tests for at logge fejl og sørg for, at vi ikke går baglæns. Så dette problem er løst i .NET Core 2.2. Men i den nyeste version af .NET Framework 4.7.2 har den stadig problemer. Det ser ud til, at den også er ødelagt i Mono.
Workarounden i .NET 4.7.2 er at genopfylde den forkert udfyldte streng med noget i retning af dette:
Oprindelig:Hyperlink-login er synlig.
|
Tidligere:Azure DevOps (viii) Kompilerer ASP.NET MVC-projekter ved hjælp af Pipelines BuildNæste:En ny timer i .NET 6, PeriodicTimer, bruges
|