在URL中传递base64编码的字符串


Answers:


206

不,您需要对其进行url编码,因为base64字符串可以包含“ +”,“ =”和“ /”字符,这些字符可能会改变数据的含义-看起来像一个子文件夹。

有效的base64字符如下。

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=

4
URLencoding浪费空间,尤其是因为base64本身留下了许多未使用的字符。
米哈尔戈尔诺-

21
我不确定我能理解您的意思-网址编码不会更改除上面列表中的最后三个字符以外的任何字符,这是为了防止它们被错误地解释,因为它们在URL中具有其他含义。base64也是一样,原始数据可以是二进制或其他任何形式,但以易于使用简单协议轻松传输的形式进行编码。
Thiyagaraj

3
首先,您也应该转义“ +”,因为它可能会转换为空间。其次,至少有几个字符可以安全地在URL中使用,而不能在“标准”字符集中使用。在某些情况下,您的方法甚至可以将传输的数据大小增加三倍。而用其他字符替换这些字符将在保持相同长度的同时达到目的。这也是非常标准的解决方案。
米哈尔戈尔诺-

8
en.wikipedia.org/wiki/Base64#URL_applications-它清楚地表明转义“使字符串不必要地变长了”,并提到了备用字符集变体。
米哈尔戈尔诺-

1
由于有了这个答案,我诊断出我的问题正是它所提到的。由于URL处理,一些基数64个字符(+,/,=)已被更改。当我对基数为64的字符串进行URL编码时,此问题已解决。
Chuck Krutsinger 2015年

272

还有其他base64规格。(有关详细信息,请参见此处的表)。但实际上,您需要65个字符进行编码:26个小写字母+ 26个大写字母+ 10位数字= 62。

您还需要两个['+','/']和一个填充字符'='。但是它们都不是url友好的,因此只需为它们使用不同的字符就可以了。上表中的标准字符为['-','_'],但您可以使用其他字符,只要您对它们进行相同的解码即可,而无需与其他人共享。

我建议只写自己的助手。像这样在base64_encodephp手册页上的注释中:

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

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

53
很好的解决方案,但URL中不保留逗号。我建议使用“〜”(波浪号)或“。”。(点)。
kralyk

11
@kralyk:我建议urlencode按照Rodrigo-silveira的回答建议使用。创建两个新函数以节省URL长度的几个字符,就像通过窗口进入您的房子而不仅仅是使用门一样。
Marco Demaio 2014年

5
@MarcoDemaio,在不知道如何使用的情况下,不可能说只有几个字符。每个编码字符的长度都是原来的三倍,为什么“ +++ ...”不是有效的base64字符串?网址具有浏览器限制,将网址加倍可能会使您达到这些限制。
leewz

10
@RandalSchwartz波浪号 URL安全的。从RFC3986:unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
kralyk

3
既然,应该urlencode到%2C,我建议使用._- 而不是-_,en.wikipedia.org/wiki/Base64#Variants_summary_table中的唯一变体那样,使之保持尾随=
PaulH 2016年

75

@joeshmo或不用编写辅助函数,也可以对base64编码的字符串进行urlencode。这将与您的辅助函数完全相同,但是不需要两个额外的函数。

$str = 'Some String';

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

2
结果并不完全相同。urlencode使用3个字符对无效字符进行编码,而joeshmo的解决方案使用1个字符。虽然差异不大,但仍然很浪费。
Josef Borkovec

1
@JosefBorkovec真的吗?那么这也意味着相同数量的base64-> url-> encoded字节可以是各种不同的结果长度,而另一种解决方案可以预测长度,对吗?
humanityANDpeace

@humanityANDpeace是的,urlencode是一个糟糕的解决方案,因为它使某些base64字符串的大小增加了三倍。由于输出大于输入,因此您也不能重用缓冲区。
纳文

4
从1到3个字符的扩展平均发生在64个字符中的3个上,因此这是9%的开销(2 *
3/64

/如果不将字符作为GET参数,而是作为URL中的路径传递,请小心字符。如果您没有/在两侧都替换其他东西,它将改变您的路径。
NeverEndingQueue

41

介绍性说明我倾向于发表一些澄清,因为此处的某些答案有些误导(如果不是错误的话)。

答案是否定的,您不能简单地在URL查询字符串中传递base64编码的参数,因为加号已转换为$ _GET全局数组内的SPACE。换句话说,如果您将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%2Bsign发送给

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

结果是意外的:
stringwith sign

rawurldecode()输入将是安全的,但是它将是多余的,因此是不必要的。


1
好答案。如果问题被标记为php,则可以在此站点上使用不带开始和结束标记的PHP代码(通常从问题的上下文中也很明显)。如果您在一行的末尾添加两个空格,您将看到<br>,因此无需键入太多HTML。希望对您有所帮助,我对您的答案做了一些修改,以进一步改善它。
hakre 2012年

感谢您提到PHP为您解码URL。这样可以避免我掉进兔子洞里。
Cocest

好的答案->您不想对返回的$ _GET字符串进行urldecode(),因为+会转换为空格。rawurldecode()输入是安全的,但是
MarcoZen

14

是的,没有。

在某些情况下,base64的基本字符集可能会与URL中使用的传统约定冲突。但是许多base64实现都允许您更改字符集以更好地匹配URL,甚至与URL一起提供(例如Python urlsafe_b64encode())。

您可能面临的另一个问题是URL长度的限制,或者更确切地说,是没有这样的限制。由于标准未指定任何最大长度,因此使用HTTP协议的浏览器,服务器,库和其他软件可能会定义其自身的限制。您可以看一下本文:WWW常见问题解答:URL的最大长度是多少?


8

您可以尝试使用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));
}

这适用于使用Java编码的数据Base64.getUrlEncoder().withoutPadding().encodeToString()

4

我不认为这是安全的,因为例如在原始基数64中使用了“ =”字符,并且还在将参数与HTTP GET中的值区分开来。


1

从理论上讲,是的,只要您不超过客户端或服务器的最大url和/或查询字符串长度即可。

在实践中,事情可能会变得有些棘手。例如,如果该值恰好包含一个“ on”,而您留下了结尾的“ ==”,则它可以在ASP.NET上触发HttpRequestValidationException。


您没有提及+,/或=字符,这些字符在某些情况下会使网址无效。
Will Bickford

0

对于url安全编码,例如base64.urlsafe_b64encode(...)在Python中,以下代码对我有效100%

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

-10

是的,它总是安全的。当然base64包含: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/= 但是base64编码的字符串通常没有++将转换为空格,导致解码字符串错误。/在获取参数对中是安全的。=始终位于base64编码字符串的末尾,服务器端可以=直接解析。


我猜这是正确的,因为我对base64编码(无url编码)所做的实验已经成功,但是我想知道是否有任何文档可以支持此操作?
肖恩·比恩

1
您说“始终安全”,但随后又说“通常没有+”。所以你矛盾自己。如果您的base64字符串中包含+号,则会引起问题。
尼克·休里希
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.