Truyền chuỗi mã hóa base64 trong URL


243

Có an toàn để vượt qua các chuỗi mã hóa cơ sở thô thông qua các tham số GET không?



4
Không có nó - câu hỏi liên kết là mới hơn. Vì vậy, nó làm cho câu hỏi được liên kết trở thành một bản sao của câu hỏi này ...
serge

Câu trả lời:


206

Không, bạn sẽ cần mã hóa url, vì các chuỗi base64 có thể chứa các ký tự "+", "=" và "/" có thể thay đổi ý nghĩa của dữ liệu của bạn - trông giống như một thư mục con.

Dưới đây là ký tự base64 hợp lệ.

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=

4
URLencoding là một sự lãng phí không gian, đặc biệt là bản thân base64 khiến nhiều ký tự không được sử dụng.
Michał Górny

21
Tôi không chắc tôi hiểu những gì bạn đang nói - Mã hóa URL sẽ không thay đổi bất kỳ ký tự nào ngoại trừ ba ký tự cuối cùng trong danh sách ở trên và điều đó là để ngăn chúng không được hiểu sai vì chúng có ý nghĩa khác trong URLS. Điều tương tự cũng xảy ra với Base64, dữ liệu gốc có thể là nhị phân hoặc bất cứ thứ gì, nhưng nó được mã hóa dưới dạng có thể được truyền dễ dàng bằng các giao thức đơn giản.
Thiyagaraj

3
Đầu tiên, bạn cũng nên thoát '+' vì nó có thể được chuyển đổi thành không gian. Thứ hai, có ít nhất một vài ký tự an toàn để sử dụng trong URL và không được sử dụng trong bộ ký tự 'tiêu chuẩn'. Phương pháp của bạn thậm chí có thể tăng kích thước của dữ liệu được chuyển ba lần trong các tình huống nhất định; trong khi thay thế các ký tự đó bằng một số ký tự khác sẽ thực hiện thủ thuật trong khi vẫn giữ nguyên độ dài. Và đó cũng là giải pháp khá chuẩn.
Michał Górny

8
vi.wikipedia.org/wiki/Base64#URL_appluggest - nó nói rõ rằng việc thoát 'làm cho chuỗi dài hơn một cách không cần thiết' và đề cập đến biến thể bộ ký tự thay thế.
Michał Górny

1
Vì câu trả lời này, tôi đã chẩn đoán vấn đề của mình là chính xác những gì nó đề cập. Một số 64 ký tự cơ bản (+, /, =) đã bị thay đổi do xử lý URL. Khi tôi URL mã hóa chuỗi 64 cơ sở, vấn đề đã được giải quyết.
Chuck Krutsinger

272

Có thêm thông số kỹ thuật base64. (Xem bảng ở đây để biết chi tiết). Nhưng về cơ bản, bạn cần 65 ký tự để mã hóa: 26 chữ thường + 26 chữ hoa + 10 chữ số = 62.

Bạn cần thêm hai ['+', '/'] và phần đệm char '='. Nhưng không ai trong số họ thân thiện với url, vì vậy chỉ cần sử dụng các ký tự khác nhau cho họ và bạn đã thiết lập. Các tiêu chuẩn từ biểu đồ trên là ['-', '_'], nhưng bạn có thể sử dụng các ký tự khác miễn là bạn giải mã chúng giống nhau và không cần chia sẻ với người khác.

Tôi khuyên bạn chỉ nên viết người trợ giúp của riêng bạn. Giống như những nhận xét này từ trang hướng dẫn sử dụng php cho base64_encode :

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

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

53
Giải pháp tuyệt vời, ngoại trừ dấu phẩy không bị hạn chế trong các URL. Tôi khuyên bạn nên sử dụng '~' (dấu ngã) hoặc '.' (chấm) thay vào đó.
kralyk

11
@kralyk: Tôi khuyên bạn chỉ nên sử dụng urlencodetheo đề xuất của câu trả lời của Rodrigo-silveira. Tạo hai chức năng mới để lưu vài ký tự theo chiều dài url, giống như vào nhà bạn đi qua cửa sổ thay vì chỉ sử dụng cửa.
Marco Demaio

5
@MarcoDemaio, không biết nó sẽ được sử dụng như thế nào, không thể nói rằng đó chỉ là một vài ký tự. Mỗi ký tự được mã hóa sẽ có độ dài gấp ba và tại sao "+++ ..." không phải là một chuỗi base64 hợp lệ? URL có giới hạn trình duyệt và tăng gấp ba URL có thể khiến bạn đạt các giới hạn đó.
leewz

10
@RandalSchwartz dấu ngã an toàn URL. Từ RFC3986:unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
kralyk

3
,nên được mã hóa thành url %2C, tôi khuyên bạn nên sử dụng ._- thay vì -_,giống như biến thể duy nhất trong en.wikipedia.org/wiki/Base64#Variants_summary_table giữ dấu vết =
PaulH

75

@joeshmo Hoặc thay vì viết hàm trợ giúp, bạn chỉ có thể urlencode chuỗi mã hóa base64. Điều này sẽ làm chính xác như chức năng trợ giúp của bạn, nhưng không cần hai chức năng bổ sung.

$str = 'Some String';

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

2
Kết quả không hoàn toàn giống nhau. urlencode sử dụng 3 ký tự để mã hóa các ký tự không hợp lệ và giải pháp của joeshmo sử dụng 1. Đó không phải là một sự khác biệt lớn, nhưng nó vẫn là một sự lãng phí.
Josef Borkovec

1
@JosefBorkovec Thật sao? Sau đó, điều này cũng có nghĩa là cùng một số byte cơ sở64-> url-> được mã hóa có thể có nhiều độ dài kết quả khác nhau, trong khi giải pháp khác cho chiều dài dự đoán, phải không?
nhân

@humanityANDpeace Có, urlencode là một giải pháp tồi tệ vì nó tăng gấp ba kích thước của các chuỗi base64 nhất định. Bạn cũng không thể sử dụng lại bộ đệm vì đầu ra lớn hơn đầu vào.
Navin

4
Trung bình mở rộng từ 1 đến 3 ký tự xảy ra trên 3 trên 64 ký tự, vì vậy nó chiếm 9% trên không (2 *
3/64

Hãy cẩn thận với /ký tự nếu bạn vượt qua nó không phải là tham số GET, mà là một đường dẫn trong URL. Nó sẽ thay đổi đường dẫn của bạn nếu bạn không thay thế /bằng thứ khác ở cả hai phía.
NeverEinatingQueue

41

Giới thiệu Lưu ý Tôi có xu hướng đăng một vài làm rõ vì một số câu trả lời ở đây có một chút sai lệch (nếu không chính xác).

Câu trả lời là KHÔNG , bạn không thể đơn giản chuyển một tham số được mã hóa base64 trong chuỗi truy vấn URL vì các dấu cộng được chuyển đổi thành SPACE bên trong mảng toàn cầu $ _GET. Nói cách khác, nếu bạn đã gửi test.php? MyVar = stringwith + đăng nhập vào

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

kết quả sẽ là:
stringwith sign

Cách dễ dàng để giải quyết vấn đề này chỉ đơn giản là urlencode()chuỗi base64 của bạn trước khi thêm nó vào chuỗi truy vấn để thoát các dấu +, = và / ký tự thành mã% ##. Ví dụ,urlencode("stringwith+sign") trả vềstringwith%2Bsign

Khi bạn xử lý hành động, PHP sẽ tự động giải mã chuỗi truy vấn khi nó tạo ra toàn cầu $ _GET. Ví dụ: nếu tôi đã gửi test.php? MyVar = stringwith% 2Bsign to

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

kết quả sẽ là:
stringwith+sign

Bạn không muốn urldecode()chuỗi $ _GET được trả về vì + sẽ được chuyển đổi thành khoảng trắng.
Nói cách khác, nếu tôi đã gửi cùng test.php? MyVar = stringwith% 2Bignign to

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

kết quả thật bất ngờ:
stringwith sign

Nó sẽ an toàn cho rawurldecode()đầu vào, tuy nhiên, nó sẽ dư thừa và do đó không cần thiết.


1
Câu trả lời tốt đẹp. Bạn có thể sử dụng mã PHP mà không có thẻ bắt đầu và kết thúc trên trang web này nếu câu hỏi được gắn thẻ php (cũng thường là nó rõ ràng từ ngữ cảnh của câu hỏi). Nếu bạn thêm hai khoảng trắng ở cuối dòng, bạn sẽ thấy <br>, vì vậy không cần phải nhập nhiều HTML. Tôi hy vọng điều này có ích, tôi đã chỉnh sửa câu trả lời của bạn một chút để cải thiện nó nhiều hơn nữa.
hakre

Cảm ơn bạn đã đề cập rằng PHP giải mã URL cho bạn. Điều đó cứu tôi khỏi rơi vào bên trong một cái hố thỏ.
Cocest

Câu trả lời tuyệt vời -> Bạn không muốn urldecode () chuỗi $ _GET được trả về vì + sẽ được chuyển đổi thành khoảng trắng. Tuy nhiên, sẽ an toàn với rawurldecode (), tuy nhiên,
MarcoZen

14

Có và không.

Bộ ký tự cơ bản của base64 trong một số trường hợp có thể va chạm với các quy ước truyền thống được sử dụng trong URL. Nhưng nhiều triển khai cơ sở64 cho phép bạn thay đổi bộ ký tự để phù hợp với các URL tốt hơn hoặc thậm chí đi kèm với một (như của Python urlsafe_b64encode()).

Một vấn đề khác bạn có thể gặp phải là giới hạn độ dài URL hoặc đúng hơn - thiếu giới hạn đó. Vì các tiêu chuẩn không chỉ định bất kỳ độ dài tối đa nào, trình duyệt, máy chủ, thư viện và phần mềm khác hoạt động với giao thức HTTP có thể xác định giới hạn của chính nó. Bạn có thể xem bài viết này: Câu hỏi thường gặp về WWW: Độ dài tối đa của URL là bao nhiêu?


8

Đây là một mã hóa base64url mà bạn có thể thử, nó chỉ là phần mở rộng của mã joeshmo ở trên.

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));
}

Điều này hoạt động đối với dữ liệu được mã hóa bằng JavaBase64.getUrlEncoder().withoutPadding().encodeToString()

4

Tôi không nghĩ rằng điều này là an toàn vì ví dụ: ký tự "=" được sử dụng trong cơ sở thô 64 và cũng được sử dụng để phân biệt các tham số với các giá trị trong HTTP GET.


1

Về lý thuyết, có, miễn là bạn không vượt quá độ dài chuỗi truy vấn và / oor tối đa cho máy khách hoặc máy chủ.

Trong thực tế, mọi thứ có thể trở nên phức tạp hơn một chút. Ví dụ: nó có thể kích hoạt một HTTPRequestValidationException trên ASP.NET nếu giá trị xảy ra có chứa "bật" và bạn để lại dấu vết "==".


bạn không đề cập đến các ký tự +, /, hoặc = làm cho các url không hợp lệ trong một số trường hợp nhất định.
Will Bickford

0

Đối với mã hóa an toàn url, như base64.urlsafe_b64encode(...)trong Python mã bên dưới, hoạt động với tôi 100%

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

-10

Có, nó luôn luôn an toàn. tất nhiên base64 chứa: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/= nhưng một chuỗi được mã hóa base64 thường không có +. +sẽ được chuyển đổi thành một khoảng trắng, dẫn đến chuỗi giải mã sai. /là an toàn trong một cặp tham số get. =luôn ở cuối chuỗi mã hóa base64 và phía máy chủ có thể giải quyết =trực tiếp.


Tôi đoán điều này là chính xác, vì các thử nghiệm tôi đã thực hiện với mã hóa base64 (không mã hóa url) đã thành công, nhưng tôi tự hỏi liệu có tài liệu nào bạn có thể cung cấp để sao lưu này không?
Sean the Bean

1
bạn nói "luôn an toàn" nhưng sau đó bạn nói "thường không có +". Vì vậy, mâu thuẫn của bạn. Dấu + dấu để gây ra vấn đề nếu bạn có nó trong chuỗi base64.
Nick Humrich
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.