Przekazywanie zakodowanych ciągów base64 w adresie URL


Odpowiedzi:


206

Nie, musisz go zakodować, ponieważ ciągi base64 mogą zawierać znaki „+”, „=” i „/”, które mogą zmieniać znaczenie twoich danych - wyglądają jak podfolder.

Prawidłowe znaki base64 są poniżej.

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=

4
Kodowanie adresów URL to strata miejsca, zwłaszcza że sama baza64 pozostawia wiele znaków nieużywanych.
— Michał Górny,

21
Nie jestem pewien, czy rozumiem, co mówisz - kodowanie adresów URL nie zmieni żadnego ze znaków poza trzema ostatnimi znakami z powyższej listy, a to zapobiegnie ich nieprawidłowej interpretacji, ponieważ mają one inne znaczenie w adresach URL. To samo dotyczy base64, oryginalne dane mogą być binarne lub cokolwiek, ale są zakodowane w formie, którą można łatwo przesłać za pomocą prostych protokołów.
— Thiyagaraj

3
Po pierwsze, powinieneś także uciec od znaku „+”, ponieważ może on zostać przekształcony w przestrzeń. Po drugie, istnieje co najmniej kilka znaków, które można bezpiecznie używać w adresach URL i nie są one używane w „standardowym” zestawie znaków. Twoja metoda może nawet trzykrotnie zwiększyć rozmiar przesyłanych danych w niektórych sytuacjach; zastępując te postacie innymi, załatwi sprawę, zachowując tę ​​samą długość. Jest to również dość standardowe rozwiązanie.
— Michał Górny,

8
en.wikipedia.org/wiki/Base64#URL_applications - wyraźnie mówi, że ucieczka „sprawia, że ​​łańcuch jest niepotrzebnie dłuższy” i wspomina o alternatywnym wariancie zestawu znaków.
— Michał Górny,

1
Z powodu tej odpowiedzi zdiagnozowałem mój problem jako dokładnie to, o czym wspomniałem. Niektóre podstawowe 64 znaki (+, /, =) były zmieniane z powodu przetwarzania adresów URL. Gdy kodowałem adres URL podstawowego ciągu 64, problem został rozwiązany.
— Chuck Krutsinger

272

Istnieją dodatkowe specyfikacje base64. (Szczegóły podano w tabeli tutaj ). Ale zasadniczo potrzebujesz 65 znaków do zakodowania: 26 małych liter + 26 wielkich liter + 10 cyfr = 62.

Potrzebujesz jeszcze dwóch ['+', '/'] i padding char '='. Ale żaden z nich nie jest przyjazny dla adresów URL, więc po prostu użyj dla nich różnych znaków i gotowe. Standardowe z powyższej tabeli to ['-', '_'], ale możesz używać innych znaków, o ile dekodujesz je tak samo i nie musisz dzielić się z innymi.

Polecam po prostu napisać własnych pomocników. Podobnie jak w komentarzach na stronie podręcznika php dla base64_encode :

function base64_url_encode($input) {
 return strtr(base64_encode($input), '+/=', '._-');
}

function base64_url_decode($input) {
 return base64_decode(strtr($input, '._-', '+/='));
}

53
Świetne rozwiązanie, z wyjątkiem przecinków w adresach URL. Polecam użycie „~” (tylda) lub „.” (kropka) zamiast.
— kralyk

11
@kralyk: Polecam po prostu, urlencodejak sugeruje odpowiedź rodrigo-silveira. Utworzenie dwóch nowych funkcji w celu zaoszczędzenia kilku znaków w adresie URL to jak wejście do domu przez okno zamiast po prostu korzystania z drzwi.
— Marco Demaio

5
@MarcoDemaio, nie wiedząc, jak zostanie użyty, nie można powiedzieć, że to tylko kilka znaków. Każdy zakodowany znak będzie miał potrójną długość i dlaczego „+++ ...” nie byłby prawidłowym ciągiem base64? Adresy URL mają ograniczenia przeglądarki, a trzykrotny URL może spowodować, że je przekroczysz.
— leewz

10
@RandalSchwartz tylda jest bezpieczna pod adresem URL. Z RFC3986:unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
— kralyk

3
Ponieważ ,należy to zaadresować %2C, sugeruję użycie ._- zamiast -_,jak jedynego wariantu w en.wikipedia.org/wiki/Base64#Variants_summary_table, który utrzymuje końcowy =
— PaulH

75

@joeshmo Lub zamiast pisać funkcję pomocnika, możesz po prostu urlencode kodowany ciąg base64. To zrobiłoby dokładnie to samo, co funkcja pomocnika, ale bez potrzeby dwóch dodatkowych funkcji.

$str = 'Some String';

$encoded = urlencode( base64_encode( $str ) );
$decoded = base64_decode( urldecode( $encoded ) );

2
Wynik nie jest dokładnie taki sam. urlencode używa 3 znaków do kodowania nieważnych znaków, a rozwiązanie joeshmo używa 1. To nie jest duża różnica, ale to wciąż marnotrawstwo.
— Josef Borkovec

1
@JosefBorkovec Naprawdę? Oznaczałoby to również, że zakodowana ta sama liczba bajtów base64-> url-> może mieć różną różną wynikową długość, podczas gdy inne rozwiązanie daje przewidywalną długość, prawda?
— humanityANDpeace

@humanityANDpeace Tak, urlencode jest gównianym rozwiązaniem, ponieważ trzykrotnie zwiększa rozmiar niektórych ciągów base64. Nie można również ponownie użyć bufora, ponieważ dane wyjściowe są większe niż dane wejściowe.
— Navin

4
Rozszerzenie od 1 do 3 znaków występuje średnio na 3 z 64 znaków, więc jest to 9% narzut (2 *
— 3/64

Uważaj na /znak, jeśli przekazujesz go nie jako parametr GET, ale jako ścieżkę w adresie URL. Zmieni to twoją ścieżkę, jeśli nie zastąpisz /czegoś innego po obu stronach.
— NeverEndingQueue,

41

Uwaga wstępna Skłaniam się do opublikowania kilku wyjaśnień, ponieważ niektóre z odpowiedzi tutaj były nieco mylące (jeśli nie nieprawidłowe).

Odpowiedź brzmi NIE , nie można po prostu przekazać parametru zakodowanego w base64 w ciągu zapytania do adresu URL, ponieważ znaki plus są konwertowane na SPACJĘ w globalnej tablicy $ _GET. Innymi słowy, jeśli wysłałeś test.php? MyVar = stringwith + sign to

//test.php
print $_GET['myVar'];

wynik byłby:
stringwith sign

Łatwym sposobem rozwiązania tego jest po prostu urlencode()ciąg base64 przed dodaniem go do ciągu zapytania, aby uciec od znaków +, = i / do kodów% ##. Na przykład urlencode("stringwith+sign")zwracastringwith%2Bsign

Podczas przetwarzania akcji PHP automatycznie dekoduje ciąg zapytania, gdy zapełni on globalną wartość $ _GET. Na przykład, jeśli wysłałem test.php? MyVar = stringwith% 2Bsign to

//test.php
print $_GET['myVar'];

wynikiem byłoby:
stringwith+sign

Zdajesz nie chcą urldecode()zwrócony ciąg $ _GET jak s + 'zostaną zamienione na spacje.
Innymi słowy, jeśli wysłałem ten sam test.php? MyVar = stringwith% 2Bsign to

//test.php
$string = urldecode($_GET['myVar']);
print $string;

wynik jest nieoczekiwany:
stringwith sign

Byłby bezpieczny dla rawurldecode()danych wejściowych, jednak byłby zbędny, a zatem niepotrzebny.


1
Niezła odpowiedź. Możesz użyć kodu PHP bez początkowych i końcowych znaczników na tej stronie, jeśli pytanie jest oznaczone php (również najczęściej wynika to z kontekstu pytania). Jeśli dodasz dwie spacje na końcu linii, zobaczysz <br>, więc nie musisz pisać dużo HTML. Mam nadzieję, że to pomoże. Zredagowałem trochę twoją odpowiedź, aby jeszcze bardziej ją poprawić.
— hakre

Dziękujemy za wspomnienie, że PHP dekoduje dla ciebie adres URL. To ratuje mnie przed wpadnięciem do króliczej nory.
— Cocest,

Świetna odpowiedź -> Nie chcesz urldecode () zwracanego ciągu $ _GET, ponieważ znaki + zostaną przekonwertowane na spacje. Bezpiecznie byłoby jednak wprowadzić kod źródłowy rawurld ()
— MarcoZen

14

Tak i nie.

Podstawowy zestaw znaków base64 może w niektórych przypadkach kolidować z tradycyjnymi konwencjami stosowanymi w adresach URL. Jednak wiele implementacji base64 pozwala na zmianę zestawu znaków w celu lepszego dopasowania adresów URL lub nawet dostarczenia go z jednym (np. Pythona urlsafe_b64encode()).

Innym problemem, z którym możesz się spotkać, jest limit długości adresu URL, a raczej jego brak. Ponieważ standardy nie określają maksymalnej długości, przeglądarki, serwery, biblioteki i inne oprogramowanie współpracujące z protokołem HTTP mogą określać własne ograniczenia. Możesz rzucić okiem na ten artykuł: Często zadawane pytania na temat WWW: Jaka jest maksymalna długość adresu URL?


8

Jest to kod base64url, który możesz wypróbować, to tylko rozszerzenie powyższego kodu joeshmo.

function base64url_encode($data) {
return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}

function base64url_decode($data) {
return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT));
}

Działa to w przypadku danych zakodowanych w JavieBase64.getUrlEncoder().withoutPadding().encodeToString()

4

Nie sądzę, że jest to bezpieczne, ponieważ np. Znak „=” jest używany w surowej bazie 64 i jest także używany do odróżniania parametrów od wartości w HTTP GET.


1

Teoretycznie tak, o ile nie przekroczysz maksymalnej długości ciągu adresu URL i / lub zapytania dla klienta lub serwera.

W praktyce może być trochę trudniej. Na przykład może wywołać wyjątek HttpRequestValidationException na platformie ASP.NET, jeśli wartość zawiera „on”, a ty zostawisz końcowe „==”.


nie wspominasz o znakach +, / lub =, które w niektórych przypadkach powodują, że adresy URL są nieprawidłowe.
— Will Bickford,

0

Dla bezpiecznego base64.urlsafe_b64encode(...)kodu URL, jak w Pythonie poniższy kod działa dla mnie w 100%

function base64UrlSafeEncode(string $input)
{
   return str_replace(['+', '/'], ['-', '_'], base64_encode($input));
}

-10

Tak, zawsze jest bezpiecznie. oczywiście base64 zawiera: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/= ale łańcuch zakodowany base64 zwykle nie ma +. +zostanie przekonwertowany na puste miejsce, co spowoduje nieprawidłowy dekodowanie ciągu. /jest bezpieczny w parze parametrów get. =jest zawsze na końcu łańcucha zakodowanego w base64, a strona serwera może rozwiązać =bezpośrednio.


Zgaduję, że jest to poprawne, ponieważ eksperymenty, które przeprowadziłem z kodowaniem base64 (bez kodowania adresu URL) zakończyły się powodzeniem, ale zastanawiam się, czy jest jakaś dokumentacja, którą mógłbyś dostarczyć, aby to zrobić?
— Sean the Bean

1
mówisz „zawsze bezpieczny”, ale potem mówisz „zwykle nie ma +”. Więc zaprzeczasz sobie. Szwy + powodują problemy, jeśli masz je w ciągu base64.
— Nick Humrich
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.