Melewati string disandikan base64 di URL

Jawaban:

206

Tidak, Anda perlu menyandi-urlnya, karena string base64 dapat berisi karakter "+", "=" dan "/" yang dapat mengubah arti data Anda - terlihat seperti sub-folder.

Karakter base64 yang valid ada di bawah ini.

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=
Thiyagaraj
sumber
4
URLencoding adalah pemborosan ruang, terutama karena base64 itu sendiri meninggalkan banyak karakter yang tidak digunakan.
Michał Górny
21
Saya tidak yakin saya mengerti apa yang Anda katakan - Pengkodean URL tidak akan mengubah salah satu karakter kecuali tiga karakter terakhir dalam daftar di atas, dan itu untuk mencegah mereka dari ditafsirkan secara salah karena mereka memiliki arti lain dalam URL. Hal yang sama berlaku untuk base64, data asli bisa berupa biner atau apa pun, tetapi dikodekan dalam bentuk yang dapat ditransmisikan dengan mudah menggunakan protokol sederhana.
Thiyagaraj
3
Pertama, Anda harus melarikan diri '+' juga karena dapat dikonversi menjadi ruang. Kedua, setidaknya ada beberapa karakter yang aman untuk digunakan dalam URL dan tidak digunakan dalam rangkaian karakter 'standar'. Metode Anda bahkan dapat meningkatkan ukuran data yang ditransfer tiga kali dalam situasi tertentu; sementara mengganti karakter tersebut dengan yang lain akan melakukan trik sambil mempertahankan panjang yang sama. Dan itu juga solusi standar.
Michał Górny
8
en.wikipedia.org/wiki/Base64#URL_applications - dikatakan dengan jelas bahwa melarikan diri 'membuat string tidak perlu lebih lama' dan menyebutkan varian charset alternatif.
Michał Górny
1
Karena jawaban ini, saya mendiagnosis masalah saya persis seperti yang disebutkan. Beberapa 64 karakter dasar (+, /, =) sedang diubah karena pemrosesan URL. Ketika saya menyandikan URL base 64 string, masalahnya telah teratasi.
Chuck Krutsinger
272

Ada spesifikasi base64 tambahan. (Lihat tabel di sini untuk rinciannya). Tetapi pada dasarnya Anda membutuhkan 65 karakter untuk menyandikan: 26 huruf kecil + 26 huruf besar + 10 digit = 62.

Anda membutuhkan dua lagi ['+', '/'] dan char padding '='. Tapi tidak satu pun dari mereka yang ramah url, jadi gunakan saja karakter yang berbeda untuk mereka dan Anda siap. Yang standar dari bagan di atas adalah ['-', '_'], tetapi Anda bisa menggunakan karakter lain selama Anda mendekodekannya sama, dan tidak perlu berbagi dengan yang lain.

Saya sarankan hanya menulis pembantu Anda sendiri. Suka ini dari komentar di halaman manual php untuk base64_encode :

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

function base64_url_decode($input) {
 return base64_decode(strtr($input, '._-', '+/='));
}
Joe Flynn
sumber
53
Solusi hebat, kecuali koma tidak dipasok dalam URL. Saya sarankan menggunakan '~' (tilde) atau '.' (titik) sebagai gantinya.
kralyk
11
@ kralyk: Saya merekomendasikan hanya menggunakan urlencodeseperti yang disarankan oleh jawaban rodrigo-silveira. Membuat dua fungsi baru untuk menghemat beberapa karakter dalam panjang url, itu seperti masuk ke rumah Anda melewati jendela alih-alih hanya menggunakan pintu.
Marco Demaio
5
@MarcoDemaio, tanpa mengetahui bagaimana itu akan digunakan, tidak mungkin untuk mengatakan bahwa itu hanya beberapa karakter. Setiap karakter yang disandikan akan memiliki panjang tiga kali lipat, dan mengapa tidak "+++ ..." menjadi string base64 yang valid? URL memiliki batas peramban, dan tiga kali lipat URL mungkin membuat Anda mencapai batas itu.
leewz
10
@RandalSchwartz tilde yaitu URL-aman. Dari RFC3986:unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
kralyk
3
Karena ,harus dimasukkan ke urlencoded %2C, saya sarankan menggunakan ._- alih-alih -_,seperti satu-satunya varian di en.wikipedia.org/wiki/Base64#Variants_summary_table yang membuat trailing =
PaulH
75

@ joeshmo Atau alih-alih menulis fungsi pembantu, Anda bisa urlencode string base64 yang dikodekan. Ini akan melakukan hal yang sama persis dengan fungsi pembantu Anda, tetapi tanpa perlu dua fungsi tambahan.

$str = 'Some String';

$encoded = urlencode( base64_encode( $str ) );
$decoded = base64_decode( urldecode( $encoded ) );
rodrigo-silveira
sumber
2
Hasilnya tidak persis sama. urlencode menggunakan 3 karakter untuk mengkodekan karakter yang tidak valid dan solusi joeshmo menggunakan 1. Ini bukan perbedaan besar, tetapi masih sia-sia.
Josef Borkovec
1
@ JosefBorkovec Benarkah? Maka ini juga akan berarti jumlah byte yang sama base64-> url-> yang dikodekan bisa berupa berbagai panjang yang dihasilkan berbeda, sedangkan solusi lain memberikan panjang yang dapat diprediksi, kan?
humanityANDpeace
@ humanityANDpeace Ya, urlencode adalah solusi menyebalkan karena tiga kali lipat ukuran string base64 tertentu. Anda juga tidak dapat menggunakan kembali buffer karena output lebih besar dari input.
Navin
4
Ekspansi dari 1 hingga 3 karakter terjadi pada 3 dari 64 karakter rata-rata, sehingga merupakan biaya overhead 9% (2 *
3/64
Hati-hati dengan /karakter jika Anda meneruskannya bukan sebagai parameter GET, tetapi sebagai jalur di URL. Ini akan mengubah jalur Anda jika Anda tidak mengganti /dengan yang lain di kedua sisi.
NeverEndingQueue
41

Catatan Pengantar Saya cenderung memposting beberapa klarifikasi karena beberapa jawaban di sini sedikit menyesatkan (jika tidak salah).

Jawabannya adalah TIDAK , Anda tidak bisa hanya melewatkan parameter yang disandikan base64 dalam string kueri URL karena tanda plus dikonversi ke SPACE di dalam array global $ _GET. Dengan kata lain, jika Anda mengirim test.php? MyVar = stringwith + sign to

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

hasilnya adalah:
stringwith sign

Cara mudah untuk menyelesaikan ini adalah dengan cukup urlencode()menggunakan string base64 Anda sebelum menambahkannya ke string kueri untuk keluar dari kode +, =, dan / karakter ke kode% ##. Misalnya, urlencode("stringwith+sign")kembalistringwith%2Bsign

Saat Anda memproses tindakan, PHP menangani penguraian kode string secara otomatis saat mengisi $ _GET global. Sebagai contoh, jika saya mengirim test.php? MyVar = stringwith% 2Bergabung ke

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

hasilnya adalah:
stringwith+sign

Anda tidak ingin urldecode()string $ _GET yang dikembalikan karena + akan dikonversi menjadi spasi.
Dengan kata lain jika saya mengirim test.php yang sama ? MyVar = stringwith% 2Bsign ke

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

hasilnya tidak terduga:
stringwith sign

Akan aman untuk rawurldecode()input, namun, itu akan berlebihan dan karena itu tidak perlu.

Jeffory J. Beckers
sumber
1
Jawaban bagus. Anda dapat menggunakan kode PHP tanpa tag awal dan akhir di situs ini jika pertanyaannya adalah tag php (juga paling sering jelas dari konteks pertanyaan). Jika Anda menambahkan dua spasi di akhir baris Anda akan melihat <br>, jadi tidak perlu mengetik banyak HTML. Saya harap ini membantu, saya sedikit mengedit jawaban Anda untuk lebih meningkatkannya.
hakre
Terima kasih telah menyebutkan bahwa PHP menerjemahkan URL untuk Anda. Itu menyelamatkan saya dari jatuh ke dalam lubang kelinci.
Cocest
Jawaban Hebat -> Anda tidak ingin urldecode () string $ _GET yang dikembalikan karena + akan dikonversi menjadi spasi. Akan lebih aman untuk menggunakan
kode mentah
14

Iya dan tidak.

Charset dasar base64 dalam beberapa kasus mungkin berbenturan dengan konvensi tradisional yang digunakan dalam URL. Tetapi banyak implementasi base64 memungkinkan Anda untuk mengubah charset agar sesuai dengan URL yang lebih baik atau bahkan datang dengan satu (seperti Python urlsafe_b64encode()).

Masalah lain yang mungkin Anda hadapi adalah batas panjang URL atau lebih tepatnya - kurangnya batas tersebut. Karena standar tidak menentukan panjang maksimal, browser, server, perpustakaan dan perangkat lunak lain yang bekerja dengan protokol HTTP dapat menentukan batasnya sendiri. Anda dapat melihat artikel ini: FAQ WWW: Berapa panjang maksimum URL?

Michał Górny
sumber
8

Ini adalah encode base64url yang dapat Anda coba, hanya perpanjangan kode joeshmo di atas.

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));
}
Andy
sumber
Ini berfungsi untuk data yang disandikan dengan JavaBase64.getUrlEncoder().withoutPadding().encodeToString()
4

Saya tidak berpikir bahwa ini aman karena misalnya karakter "=" digunakan dalam basis mentah 64 dan juga digunakan dalam membedakan parameter dari nilai dalam GET HTTP.

Mischa
sumber
1

Secara teori, ya, selama Anda tidak melebihi panjang string url dan / atau kueri maksimum untuk klien atau server.

Dalam praktiknya, berbagai hal bisa menjadi sedikit lebih rumit. Misalnya, ini dapat memicu HttpRequestValidationException di ASP.NET jika nilainya mengandung "on" dan Anda membiarkannya mengekor "==".

Nicole Calinoiu
sumber
Anda tidak menyebutkan +, /, atau = karakter yang membuat url tidak valid dalam kasus tertentu.
Will Bickford
0

Untuk penyandian aman url, seperti base64.urlsafe_b64encode(...)pada Python kode di bawah ini, berfungsi untuk saya untuk 100%

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

Ya, selalu aman. tentu saja base64 berisi: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/= tetapi string yang disandikan base64 biasanya tidak memiliki +. +akan dikonversi menjadi ruang kosong, menghasilkan string yang salah diterjemahkan. /aman dalam pasangan parameter get. =selalu di akhir string yang disandikan base64 dan sisi server dapat menyelesaikan =secara langsung.

gouchaoer
sumber
Saya kira ini benar, karena percobaan yang telah saya lakukan dengan pengkodean base64 (tanpa pengkodean url) telah berhasil, tetapi saya ingin tahu apakah ada dokumentasi yang dapat Anda berikan untuk mendukungnya?
Sean the Bean
1
Anda mengatakan "selalu aman" tetapi kemudian Anda mengatakan "biasanya tidak memiliki +". Jadi, Anda bertentangan dengan diri Anda sendiri. Tanda + jahitan menyebabkan masalah jika Anda memilikinya dalam string base64 Anda.
Nick Humrich