Pasar cadenas codificadas en base64 en URL

Respuestas:

206

No, necesitaría codificarlo en url, ya que las cadenas de base64 pueden contener los caracteres "+", "=" y "/" que podrían alterar el significado de sus datos. Parezca una subcarpeta.

La base válida de 64 caracteres está debajo.

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=
Thiyagaraj
fuente
44
La codificación de URL es una pérdida de espacio, especialmente porque la base64 en sí misma deja muchos caracteres sin usar.
Michał Górny
21
No estoy seguro de entender lo que está diciendo: la codificación de URL no alterará ninguno de los caracteres, excepto los últimos tres caracteres en la lista anterior, y eso es para evitar que se interpreten incorrectamente ya que tienen otros significados en URLS. Lo mismo ocurre con base64, los datos originales pueden ser binarios o cualquier cosa, pero están codificados en una forma que puede transmitirse fácilmente mediante protocolos simples.
Thiyagaraj
3
En primer lugar, debes escapar de '+' también, ya que puede convertirse en espacio. En segundo lugar, hay al menos unos pocos caracteres que son seguros para usar en URL y no se usan en el juego de caracteres 'estándar'. Su método puede incluso aumentar el tamaño de los datos transferidos tres veces en ciertas situaciones; mientras reemplaza esos personajes con algún otro hará el truco mientras conserva la misma longitud. Y también es una solución bastante estándar.
Michał Górny
8
en.wikipedia.org/wiki/Base64#URL_applications : dice claramente que escapar 'hace que la cadena sea innecesariamente más larga' y menciona la variante alternativa de juego de caracteres.
Michał Górny
1
Debido a esta respuesta, diagnostiqué que mi problema era exactamente lo que mencionaba. Algunos de los 64 caracteres básicos (+, /, =) estaban siendo alterados debido al procesamiento de URL. Cuando URL codificó la cadena base 64, el problema se resolvió.
Chuck Krutsinger el
272

Hay especificaciones adicionales de base64. (Vea la tabla aquí para detalles). Pero esencialmente necesita 65 caracteres para codificar: 26 minúsculas + 26 mayúsculas + 10 dígitos = 62.

Necesita dos más ['+', '/'] y un relleno de caracteres '='. Pero ninguno de ellos es compatible con URL, así que solo usa caracteres diferentes para ellos y listo. Los estándares del cuadro anterior son ['-', '_'], pero puede usar otros caracteres siempre que los decodifique de la misma manera, y no necesite compartirlos con otros.

Recomiendo simplemente escribir sus propios ayudantes. Como estos de los comentarios en la página del manual de php para base64_encode :

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

function base64_url_decode($input) {
 return base64_decode(strtr($input, '._-', '+/='));
}
Joe Flynn
fuente
53
Gran solución, excepto que la coma no está sin reservar en las URL. Recomiendo usar '~' (tilde) o '.' (punto) en su lugar.
kralyk 01 de
11
@kralyk: Recomiendo simplemente usar urlencodecomo lo sugiere la respuesta de rodrigo-silveira. Crear dos nuevas funciones para guardar pocos caracteres en la longitud de la URL, es como entrar en su casa pasando por la ventana en lugar de simplemente usar la puerta.
Marco Demaio
55
@MarcoDemaio, sin saber cómo se usará, es imposible decir que solo son unos pocos personajes. Cada carácter codificado tendrá el triple de longitud, y ¿por qué "+++ ..." no sería una cadena base64 válida? Las URL tienen límites de navegador, y triplicar una URL puede hacer que alcance esos límites.
leewz
10
@RandalSchwartz tilde es seguro para URL. Desde RFC3986:unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
kralyk
3
Como ,debería ser urlencoded %2C, sugiero usar en ._- lugar de -_,como la única variante en en.wikipedia.org/wiki/Base64#Variants_summary_table que mantiene el final =
PaulH
75

@joeshmo O en lugar de escribir una función auxiliar, puede simplemente urlencode la cadena codificada en base64. Esto haría exactamente lo mismo que su función auxiliar, pero sin la necesidad de dos funciones adicionales.

$str = 'Some String';

$encoded = urlencode( base64_encode( $str ) );
$decoded = base64_decode( urldecode( $encoded ) );
rodrigo-silveira
fuente
2
El resultado no es exactamente el mismo. urlencode usa 3 caracteres para codificar caracteres no válidos y la solución de joeshmo usa 1. No es una gran diferencia, pero sigue siendo un desperdicio.
Josef Borkovec
1
@JosefBorkovec ¿En serio? Entonces esto también significaría que la misma cantidad de bytes base64-> url-> codificada podría ser una variedad de diferentes longitudes resultantes, mientras que la otra solución da una longitud predecible, ¿verdad?
humanityANDpeace
@humanityANDpeace Sí, urlencode es una solución de mierda porque triplica el tamaño de ciertas cadenas base64. Tampoco puede reutilizar el búfer ya que la salida es mayor que la entrada.
Navin
44
La expansión de 1 a 3 caracteres ocurre en 3 de 64 caracteres en promedio, por lo que es una sobrecarga del 9% (2 *
3/64
Tenga cuidado con el /carácter si lo pasa no como un parámetro GET, sino como una ruta en la URL. Cambiará tu camino si no lo reemplazas /con algo más en ambos lados.
NeverEndingQueue
41

Nota introductoria Me inclino a publicar algunas aclaraciones ya que algunas de las respuestas aquí fueron un poco engañosas (si no incorrectas).

La respuesta es NO , no puede simplemente pasar un parámetro codificado en base64 dentro de una cadena de consulta URL ya que los signos más se convierten en un ESPACIO dentro de la matriz global $ _GET. En otras palabras, si envió test.php? MyVar = stringwith + sign a

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

el resultado sería:
stringwith sign

La manera fácil de resolver esto es simplemente urlencode()su cadena base64 antes de agregarla a la cadena de consulta para escapar de los caracteres +, = y / a los códigos% ##. Por ejemplo, urlencode("stringwith+sign")devuelvestringwith%2Bsign

Cuando procesa la acción, PHP se encarga de decodificar la cadena de consulta automáticamente cuando llena el $ _GET global. Por ejemplo, si envié test.php? MyVar = stringwith% 2Bsign a

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

el resultado sería:
stringwith+sign

Usted no quiere a urldecode()la cadena devuelta $ _GET como s + 'se convertirán en espacios.
En otras palabras, si envié el mismo test.php? MyVar = stringwith% 2Bsign a

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

El resultado es inesperado:
stringwith sign

Sería seguro para rawurldecode()la entrada, sin embargo, sería redundante y, por lo tanto, innecesario.

Jeffory J. Beckers
fuente
1
Buena respuesta. Puede usar el código PHP sin las etiquetas de inicio y finalización en este sitio si la pregunta está etiquetada como php (también suele estar claro por el contexto de la pregunta). Si agrega dos espacios al final de una línea, verá el <br>, por lo que no es necesario escribir mucho HTML. Espero que esto ayude, edité su respuesta un poco para mejorarla aún más.
Hakre
Gracias por mencionar que PHP decodifica la URL por usted. Eso me salva de caer dentro de una madriguera de conejo.
Cocest el
Gran respuesta -> No desea codificar url () la cadena $ _GET devuelta ya que los + se convertirán en espacios. Sin embargo, sería seguro codificar sin procesar () la entrada
MarcoZen
14

Si y no.

El juego de caracteres básico de base64 puede en algunos casos colisionar con las convenciones tradicionales utilizadas en las URL. Pero muchas de las implementaciones de base64 le permiten cambiar el conjunto de caracteres para que coincida mejor con las URL o incluso vienen con una (como Python urlsafe_b64encode()).

Otro problema que puede enfrentar es el límite de la longitud de la URL o, más bien, la falta de dicho límite. Debido a que los estándares no especifican ninguna longitud máxima, los navegadores, servidores, bibliotecas y otro software que trabaja con el protocolo HTTP pueden definir sus propios límites. Puedes echar un vistazo a este artículo: Preguntas frecuentes sobre WWW: ¿Cuál es la longitud máxima de una URL?

Michał Górny
fuente
8

Es una codificación base64url que puedes probar, es solo una extensión del código de joeshmo anterior.

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
fuente
Esto funciona para datos codificados con JavaBase64.getUrlEncoder().withoutPadding().encodeToString()
4

No creo que esto sea seguro porque, por ejemplo, el carácter "=" se usa en la base sin procesar 64 y también se usa para diferenciar los parámetros de los valores en un HTTP GET.

Mischa
fuente
1

En teoría, sí, siempre y cuando no exceda la longitud máxima de cadena de consulta y / o url para el cliente o servidor.

En la práctica, las cosas pueden ponerse un poco más complicadas. Por ejemplo, puede desencadenar una HttpRequestValidationException en ASP.NET si el valor contiene un "on" y se deja en el final "==".

Nicole Calinoiu
fuente
no mencionas los caracteres +, / o = que invalidan las URL en ciertos casos.
Will Bickford el
0

Para la codificación segura de URL, como base64.urlsafe_b64encode(...)en Python, el siguiente código me funciona al 100%

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

Sí, siempre es seguro. por supuesto, base64 contiene: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/= pero una cadena codificada en base64 generalmente no tiene +. +se convertirá en un espacio en blanco, da como resultado una cadena decodificada incorrecta. /es seguro en un par de parámetros get. =siempre está al final de la cadena codificada en base64 y el lado del servidor puede resolver =directamente.

gouchaoer
fuente
Supongo que esto es correcto, ya que los experimentos que he realizado con la codificación base64 (sin codificación de URL) han tenido éxito, pero me pregunto si hay alguna documentación que pueda proporcionar para respaldar esto.
Sean the Bean
1
dices "siempre seguro" pero luego dices "generalmente no tiene +". Entonces te estás contradiciendo a ti mismo. El signo + parece causar problemas si lo tiene en su cadena base64.
Nick Humrich el