Vieną saulėtą rytą, aš sėdėjau priešais savo nešiojamąjį kompiuterį restruktūrizuojant kai C # kodą. Viskas vyksta gerai ir tai bus produktyvi diena. Tada pridėjau per daug lygybės ženklų prie pastovios eilutės pažodžiui, ir viskas sprogo. Produktyvumo nebėra. Ramus sekmadienio atstatymas jau praeityje. Net saulė nusprendė pasislėpti už debesų.
Praleidęs 30–40 minučių bandydamas išsiaiškinti, ką darau ne taip, supratau, kad tai ne aš. Tai "Microsoft". Matyt, aš užkliuvau ant senos klaidos Base64 dekodavimo funkcija.Konvertuoti.FromBase64StringŠi klaida tikrai egzistavo nuo tada, kai 2003 m. buvo pristatytas .NET 1.1. Oho! Tai sena. Ir tai nėra labai sunku atkurti. Geras darbas:
Techniškai tai yra neteisėtas Base64. Teisinė versija yra "abc=". Atkreipkite dėmesį tik į vieną užpildo simbolį =. Base64 kodavimas reiškia kas 6 dvejetainės įvesties bitus viename ASCII simboliu. Tai reiškia, kad kas 4 simboliai Base64 užkoduotoje eilutėje reiškia 3 baitus. Kai užkoduoti duomenys nėra 3 baitų kartotinis, Base64 kodavimo įrenginys prideda užpildo simbolį, kad Base64 būtų 4 simbolių kartotinis. Tai sugeneruos Base64 eilutę, kuri tinkamai užpildyta "abc=". Pridėjus kitą = jis bus negaliojantis.
Base64 "abc=" yra iššifruotas kaip du baitai [105, 183]. Teisingai. Pridėjus dar vieną užpildymo simbolį pabaigoje, užkoduota reikšmė tikrai neturėtų pasikeisti. Tai tarsi tarpo pridėjimas sakinio pabaigoje. Taip, jis yra, bet tai nekeičia sakinio prasmės. Tačiau .NET taip nemano. "abc==" dekoduojamas kaip baitas [109]. Jis ne tik sutrumpėjo, o tai buvo keista, nes mes pailginome įvestį. Jis taip pat tapo kitoks. Pirmasis baitas eina nuo 105 iki 109. Ir tai taip pat nebuvo išimtis. Pridėkite kitą = ir gausite išimtį. Nuostabi!
Kodas:
Išvesties:
'abc=' -> [105, 183] 'abc==' -> [109] Tikrai nuostabu, kad niekas to nepastebėjo tiek metų. Arba jis buvo rastas, bet neištaisytas. "Base64" yra labai svarbus keičiantis informacija tinkle. Tai galima pamatyti visur. Tačiau .NET jau daugelį metų neatsikratė ydingo Base64 dekoderio.
Iš pradžių negalėjau patikėti ir pradėjau tyrinėti. Kurį laiką pagooglinau ir neradau daug. Tada aš paskelbtas StackOverflow ir negavo daug sėkmės arba. Kai aš supratau, kas vyksta, aš net turėjo atsakyti į savo klausimus. Kurį laiką ieškojęs "GitHub", 2018 m. liepą aptikau ".NET Core" pataisymą. Taigi naujausia .NET Core versija teisingai sprendžia šią problemą ir pateikia išimtį:
Neapdorota išimtis: System.FormatException: įvestis nėra leistina Base-64 eilutė, nes joje yra ne pagrindinis 64 simbolis, daugiau nei du užpildymo simboliai arba neleistinas simbolis tarp Simbolių užpildymas. System.Convert.FromBase64CharPtr(Char* inputPtr, Int32 inputLength) System.Convert.FromBase64String(String s) Program.DecodeAndPrint(String base64) ./base64/Program.cs:13 eilutėje Program.Main() ./base64/Program.cs:line 8 Jiems prireikė maždaug 15 metų, kad surastų ir išspręstų problemą. Įdomu tai, kad niekas iš tikrųjų nebandė to konkrečiai ištaisyti. Taip atsitiko, kai jie perrašė kodą, kad jis būtų greitesnis:
Convert.FromBase64() turi subtilią klaidą, kai antras nelegaliai užpildytas simbolis eilutės pabaigoje sukelia dekodavimą "sėkmingai", pašalinant priešpaskutinį simbolį.
Mes esame . Ši klaida buvo netyčia ištaisyta, kai API buvo optimizuota NetCore 2.1. Pridėkite testų, kad užregistruotumėte klaidas ir įsitikintumėte, kad negrįžtame atgal. Taigi ši problema išspręsta .NET Core 2.2. Tačiau dabartinėje naujausioje ".NET Framework 4.7.2" versijoje vis dar kyla problemų. Atrodo, kad jis sugedęs ir Mono.
.NET 4.7.2 sprendimas yra iš naujo užpildyti neteisingai užpildytą eilutę kažkuo panašiu:
Originalus:Hipersaito prisijungimas matomas.
|