Передача строк в кодировке base64 в URL

Безопасно ли передавать необработанные строки в кодировке base64 через параметры GET?


person Alix Axel    schedule 03.09.2009    source источник
comment
Нет, связанный вопрос новее. Таким образом, связанный вопрос становится дубликатом этого ...   -  person serge    schedule 09.03.2017


Ответы (9)


Нет, вам нужно будет закодировать его URL-адресом, поскольку строки base64 могут содержать символы «+», «=» и «/», которые могут изменить значение ваших данных - выглядят как подпапка.

Ниже приведены допустимые символы base64.

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=
person Thiyagaraj    schedule 03.09.2009
comment
Кодирование URL-адресов - это пустая трата места, особенно потому, что сам base64 оставляет неиспользованными многие символы. - person Michał Górny; 03.09.2009
comment
Я не уверен, что понимаю, о чем вы говорите - кодировка URL-адреса не изменит ни один из символов, кроме последних трех символов в списке выше, и это сделано для предотвращения их неправильной интерпретации, поскольку они имеют другое значение в URL-адресах. То же самое касается base64, исходные данные могут быть двоичными или какими угодно, но они закодированы в форме, которая может быть легко передана с использованием простых протоколов. - person Thiyagaraj; 03.09.2009
comment
Во-первых, вы также должны убрать знак «+», так как он может быть преобразован в пробел. Во-вторых, есть как минимум несколько символов, которые можно безопасно использовать в URL-адресах и которые не используются в «стандартной» кодировке. Ваш метод может даже увеличить размер передаваемых данных в три раза в определенных ситуациях; при замене этих символов на другие позволит сохранить ту же длину. И это тоже вполне стандартное решение. - person Michał Górny; 04.09.2009
comment
Пока ваш аргумент верен, прочтите это - en.wikipedia.org/wiki/Base64 Может быть, вы поймете причины, по которым его выбрали, немного яснее. - person Thiyagaraj; 04.09.2009
comment
en.wikipedia.org/wiki/Base64#URL_applications - здесь ясно сказано, что экранирование ' делает строку излишне длиннее »и упоминает альтернативный вариант кодировки. - person Michał Górny; 04.09.2009
comment
Из-за этого ответа я диагностировал свою проблему как именно то, о чем он упоминал. Некоторые из базовых 64 символов (+, /, =) были изменены из-за обработки URL. Когда я закодировал URL-адрес строки base 64, проблема была решена. - person Chuck Krutsinger; 30.01.2015
comment
@ MichałGórny Если вы используете JSON в качестве параметра GET, кодировка Base 64 (в зависимости от ваших данных), вероятно, уменьшит размер строки запроса. (И прежде чем вы скажете, что это глупая идея, мы используем JSON в строках запроса, чтобы облегчить глубокие ссылки в нашем приложении.) Для нашего приложения этот подход позволил сократить примерно на 30%. (Честно говоря, еще большего сокращения можно добиться, полностью отказавшись от Base64 и вместо этого написав наши собственные сериализаторы JSON (де), которые используют символы, удобные для кодирования URL (например, ([' вместо {["). - person rinogo; 26.10.2015
comment
Я предполагаю, что вы имеете в виду, что сокращение произошло из-за использования base64 перед кодированием url, что для меня имеет смысл, потому что кодирование url действительно неэффективно. - person Arlen Beiler; 13.09.2019
comment
Вы забыли пробелы ... Если это base64 двоичного файла, он может включать пробелы (которые иногда игнорируются, но не всегда) ... - person spa900; 04.12.2020
comment
@ spa900 - набор 64-символьной кодировки двоичного файла, на который вы ссылаетесь, должен отличаться от стандартного Base64, который НЕ включает пробел. Он использует только ПЕЧАТНЫЕ символы (таблица находится в вики-ссылке комментариев выше). - person ToolmakerSteve; 12.12.2020

Есть дополнительные спецификации base64. (Подробности см. В таблице здесь). Но по сути вам нужно 65 символов для кодирования: 26 строчных + 26 прописных + 10 цифр = 62.

Вам понадобятся еще два ['+', '/'] и символ заполнения '='. Но ни один из них не поддерживает URL, поэтому просто используйте для них разные символы, и все готово. Стандартные символы из приведенной выше таблицы - это ['-', '_'], но вы можете использовать другие символы, если вы их декодируете одинаково, и вам не нужно делиться с другими.

Я бы порекомендовал написать собственных помощников. Как это из комментариев на странице руководства php для base64_encode:

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

function base64_url_decode($input) {
 return base64_decode(strtr($input, '._-', '+/='));
}
person Joe Flynn    schedule 29.04.2011
comment
Отличное решение, за исключением того, что в URL-адресах есть запятая. Я рекомендую использовать '~' (тильда) или '.' (точка) вместо этого. - person kralyk; 01.02.2013
comment
@kralyk: Я рекомендую просто использовать urlencode, как это было предложено ответом Родриго-Сильвейры. Создание двух новых функций для экономии нескольких символов в длине URL-адреса, это все равно что войти в ваш дом, проходя через окно, а не просто использовать дверь. - person Marco Demaio; 26.02.2014
comment
@MarcoDemaio, не зная, как он будет использоваться, невозможно сказать, что это всего лишь несколько символов. Каждый закодированный символ будет иметь тройную длину, и почему +++ ... не будет действительной строкой base64? URL-адреса имеют ограничения браузера, и утроение URL-адреса может привести к их достижению. - person leewz; 04.09.2015
comment
Как ни странно, @kralyk предлагает тильду, и все же тильда не безопасный для URL-адресов символ! Вокруг плавает много дезинформации. :) - person Randal Schwartz; 29.09.2015
comment
@RandalSchwartz тильда безопасна для URL. Из RFC3986: unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" - person kralyk; 30.09.2015
comment
Ах, это относительно недавнее изменение. Я использовал устаревшую информацию. - person Randal Schwartz; 01.10.2015
comment
Поскольку URL-адрес , должен иметь кодировку %2C, я предлагаю использовать ._- вместо -_,, как единственный вариант в en. wikipedia.org/wiki/Base64#Variants_summary_table, который сохраняет конечный = - person PaulH; 03.07.2016
comment
Обратите внимание, что это не совсем спасение: может случиться так, что последний символ вашего URL-адреса станет ., который в этом случае не будет считаться частью URL-адреса некоторыми почтовыми клиентами. Тем не менее, я все же рекомендую замену, предложенную здесь, потому что некоторые почтовые клиенты оптимизируют // на / в URL-адресах, а также не принимают конечные =-знаки как часть URL-адреса. - person MaPePeR; 08.01.2019
comment
Чтобы уточнить: не изобретайте собственный 64-разрядный адрес, безопасный для URL. Используйте base64url. . Это использует minus и underlineequals для панели), как описывает ответ Джо Флинна. - person ToolmakerSteve; 12.12.2020

@joeshmo Или вместо того, чтобы писать вспомогательную функцию, вы можете просто urlencode кодировать строку в кодировке base64. Это будет делать то же самое, что и ваша вспомогательная функция, но без необходимости в двух дополнительных функциях.

$str = 'Some String';

$encoded = urlencode( base64_encode( $str ) );
$decoded = base64_decode( urldecode( $encoded ) );
person rodrigo-silveira    schedule 21.12.2011
comment
Результат не совсем тот. urlencode использует 3 символа для кодирования недопустимых символов, а решение joeshmo использует 1. Это не большая разница, но все равно пустая трата. - person Josef Borkovec; 01.03.2013
comment
@JosefBorkovec Правда? Тогда это также будет означать, что одно и то же количество байтов, закодированных в base64- ›url-›, может иметь различную результирующую длину, в то время как другое решение дает предсказуемую длину, верно? - person humanityANDpeace; 29.03.2014
comment
@humanityANDpeace Да, urlencode - дерьмовое решение, потому что оно втрое увеличивает размер некоторых строк base64. Вы также не можете повторно использовать буфер, так как вывод больше, чем ввод. - person Navin; 06.01.2016
comment
Расширение с 1 до 3 символов происходит в среднем на 3 из 64 символов, поэтому накладные расходы составляют 9% (2 * 3/64) - person PaulH; 03.07.2016
comment
Будьте осторожны с символом /, если вы передаете его не как параметр GET, а как путь в URL-адресе. Это изменит ваш путь, если вы не замените / чем-то другим с обеих сторон. - person NeverEndingQueue; 01.09.2017
comment
base64 не следует декодировать до тех пор, пока не будет выполнен синтаксический анализ URL-адреса, поэтому ошибка + или / как часть URL-адреса после декодирования base64 не должна быть проблемой. Сначала проанализируйте путь URL-адреса, а затем, если в пути есть сегменты base64, декодируйте их по отдельности. То же самое и с параметрами URL. - person theferrit32; 22.03.2018
comment
Не должна ли вторая строка быть urldecode (base64_decode ($ encoded)); Мне это кажется обратным. - person Mfoo; 28.03.2019
comment
URL-кодирование содержимого параметров запроса может быть проблематичным для некоторых клиентов отдыха, мы столкнулись с этой точной проблемой при кодировании наших параметров запроса Base64 перед их отправкой, при использовании программных клиентов, таких как RestAssured или Groovy http-соединение, это будет работать хорошо, но при использовании Postman или Curl содержимое параметра запроса было другим. Причина, по-видимому, в том, что некоторые клиенты выполняют дополнительную кодировку URL-адреса, поэтому параметры запроса в конечном итоге отправляются на сервер с двойным кодированием. - person raspacorp; 11.07.2019
comment
Мой выбор. В Java: url = URLEncoder.encode(Base64.getEncoder().encodeToString(value), StandardCharsets.UTF_8) Base64.getDecoder().decode(URLDecoder.decode(code, StandardCharsets.UTF_8)) - person Grigory Kislin; 30.04.2020
comment
К сожалению, часть этого ответа неверна. urldecode выполняется автоматически, когда php заполняет $ _GET, и повторное выполнение urldecode будет неправильным для +. Подробности см. В ответе Джеффори Беккерса. - person ToolmakerSteve; 12.12.2020

Вводное примечание Я склонен опубликовать несколько пояснений, поскольку некоторые ответы здесь были немного вводящими в заблуждение (если не неверными).

Ответ - НЕТ, вы не можете просто передать параметр в кодировке base64 в строке запроса URL, поскольку знаки плюса преобразуются в ПРОБЕЛ внутри глобального массива $ _GET. Другими словами, если вы отправили test.php? MyVar = stringwith + sign в

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

результат будет:
stringwith sign

Самый простой способ решить эту проблему - просто urlencode() строку base64 перед добавлением ее в строку запроса, чтобы избежать символов +, = и / в кодах% ##. Например, urlencode("stringwith+sign") возвращает stringwith%2Bsign

Когда вы обрабатываете действие, PHP автоматически расшифровывает строку запроса, когда заполняет глобальную переменную $ _GET. Например, если я отправил test.php? MyVar = stringwith% 2Bsign в

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

результат:
stringwith+sign

Вы не хотите urldecode() возвращенную строку $ _GET, поскольку + будут преобразованы в пробелы.
Другими словами, если я отправил тот же test.php? MyVar = stringwith% 2B подписать на

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

результат неожиданный:
stringwith sign

Было бы безопасно ввести rawurldecode() ввод, однако он будет избыточным и, следовательно, ненужным.

person Jeffory J. Beckers    schedule 25.09.2012
comment
Хороший ответ. Вы можете использовать PHP-код без начальных и конечных тегов на этом сайте, если вопрос помечен как php (также чаще всего ясно из контекста вопроса). Если вы добавите два пробела в конце строки, вы увидите <br>, поэтому нет необходимости вводить много HTML. Надеюсь, это поможет, я немного отредактировал ваш ответ, чтобы еще больше улучшить его. - person hakre; 26.09.2012
comment
Спасибо, что упомянули, что PHP декодирует URL за вас. Это спасает меня от падения в кроличью нору. - person Cocest; 05.12.2019
comment
Отличный ответ - ›Вы не хотите использовать urldecode () возвращенную строку $ _GET, поскольку + будут преобразованы в пробелы. Однако было бы безопасно использовать rawurldecode () для ввода, - person MarcoZen; 05.06.2020

Да и нет.

Базовая кодировка base64 в некоторых случаях может противоречить традиционным соглашениям, используемым в URL-адресах. Но многие реализации base64 позволяют вам изменить кодировку для лучшего соответствия URL-адресам или даже пойти с ней (например, Python _ 1_).

Еще одна проблема, с которой вы можете столкнуться, - это ограничение длины URL или, скорее, отсутствие такого ограничения. Поскольку стандарты не определяют максимальную длину, браузеры, серверы, библиотеки и другое программное обеспечение, работающее с протоколом HTTP, могут определять свои собственные ограничения.

person Michał Górny    schedule 03.09.2009

Это кодировка base64url, которую вы можете попробовать, это просто расширение кода 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));
}
person Andy    schedule 21.07.2015
comment
Это работает для данных, закодированных с помощью Java Base64.getUrlEncoder().withoutPadding().encodeToString() - person ; 27.03.2019
comment
Эта версия base64url_decode () нарушала мой JSON. - person Svetoslav Marinov; 24.06.2021

Я не думаю, что это безопасно, потому что, например, символ «=» используется в исходной базе 64, а также используется для отличия параметров от значений в HTTP GET.

person Mischa    schedule 03.09.2009

Теоретически да, если вы не превышаете максимальную длину строки запроса url и / oor для клиента или сервера.

На практике все может быть немного сложнее. Например, он может вызвать исключение HttpRequestValidationException в ASP.NET, если значение содержит «on», а вы оставите в конце «==».

person Nicole Calinoiu    schedule 03.09.2009
comment
вы не упоминаете символы +, / или =, которые в некоторых случаях делают URL-адреса недействительными. - person Will Bickford; 03.09.2009

Для безопасного кодирования URL, например base64.urlsafe_b64encode(...) в Python, приведенный ниже код работает для меня на 100%

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