为什么我们使用Base64?

时间:2010-08-21 15:21:09

标签: algorithm character-encoding binary ascii base64

Wikipedia

  

当需要编码需要通过设计用于处理文本数据的媒体进行存储和传输的二进制数据时,通常使用Base64编码方案。这是为了确保数据在运输过程中保持完整而不进行修改。

但是,数据是否总是以二进制形式存储/传输,因为我们的机器存储二进制文件的内存只取决于你如何解释它?因此,无论您将位模式010011010110000101101110编码为ASCII中的Man还是将其编码为Base64中的TWFu,您最终都会存储相同的位模式。

如果最终编码是零和1,并且每台机器和媒体都可以处理它们,那么如果数据表示为ASCII或Base64,这有什么关系呢?

“旨在处理文本数据的媒体”是什么意思?他们可以处理二进制=>他们可以处理任何事情。


谢谢大家,我想我现在明白了。

当我们发送数据时,我们无法确定数据是否会以与我们预期相同的格式进行解释。因此,我们发送以双方都理解的某种格式(如Base64)编码的数据。这样,即使发送方和接收方以不同方式解释相同的内容,但由于它们对编码格式达成一致,因此数据不会被错误地解释。

来自Mark Byers example

如果我想发送

Hello
world!

一种方法是以ASCII格式发送它,如

72 101 108 108 111 10 119 111 114 108 100 33

但是字节10可能无法正确解释为另一端的换行符。因此,我们使用ASCII的子集来编码它

83 71 86 115 98 71 56 115 67 110 100 118 99 109 120 107 73 61 61

以相同数量的信息传输的更多数据为代价,确保接收器能够以预期的方式解码数据,即使接收器恰好对字符集的其余部分有不同的解释。

13 个答案:

答案 0 :(得分:235)

你的第一个错误是认为ASCII编码和Base64编码是可以互换的。他们不是。它们用于不同的目的。

  • 使用ASCII编码文本时,首先要使用文本字符串并将其转换为字节序列。
  • 在Base64中编码数据时,从一系列字节开始并将其转换为文本字符串。

要理解为什么Base64首先是必要的,我们需要一点计算历史。


计算机以二进制 - 0和1进行通信 - 但人们通常希望与更丰富的表单数据(如文本或图像)进行通信。为了在计算机之间传输该数据,首先必须将其编码为0和1,然后发送,然后再次解码。以文本为例 - 有许多不同的方法来执行此编码。如果我们都能就单一编码达成一致意见会更简单,但遗憾的是情况并非如此。

最初创建了许多不同的编码(例如Baudot code),每个字符使用不同的位数,直到最终ASCII成为每个字符7位的标准。但是,大多数计算机以字节为单位存储二进制数据,每个数据包含8位,因此ASCII不适合传输此类数据。有些系统甚至会擦掉最重要的位。此外,跨系统的行结束编码的差异意味着ASCII字符10和13有时也被修改。

为了解决这些问题,引入了Base64编码。这允许您将aribtrary字节编码为已知可安全发送而不会损坏的字节(ASCII字母数字字符和几个符号)。缺点是使用Base64对消息进行编码会增加其长度 - 每3个字节的数据被编码为4个ASCII字符。

要可靠地发送文本,您可以首先使用您选择的文本编码(例如UTF-8)编码为字节,然后 Base64编码生成的二进制数据到一个可以安全发送编码为ASCII的文本字符串。接收方必须撤消此过程以恢复原始消息。这当然要求接收方知道使用了哪些编码,并且这些信息通常需要单独发送。

从历史上看,它已用于编码电子邮件中的二进制数据,其中电子邮件服务器可能会修改行尾。一个更现代的例子是将Base64编码用于embed image data directly in HTML source code。这里有必要对数据进行编码以避免像'<'这样的字符。和'>'被解释为标签。


这是一个有效的例子:

我希望发送包含两行的短信

Hello
world!

如果我将其作为ASCII(或UTF-8)发送,它将如下所示:

72 101 108 108 111 10 119 111 114 108 100 33

在某些系统中,字节10已损坏,因此我们可以将这些字节作为Base64字符串进行64位编码:

SGVsbG8sCndvcmxkIQ==

使用ASCII编码时,如下所示:

83 71 86 115 98 71 56 115 67 110 100 118 99 109 120 107 73 61 61

这里的所有字节都是已知的安全字节,因此任何系统都很可能会破坏此消息。我可以发送此消息而不是原始消息,让接收方反转该过程以恢复原始消息。

答案 1 :(得分:53)

以XML格式编码二进制数据

假设您要在XML文档中嵌入几个图像。图像是二进制数据,而XML文档是文本。但XML无法处理嵌入式二进制数据。那你怎么做的?

一种选择是在base64中对图像进行编码,将二进制数据转换为XML可以处理的文本。

代替:

<images>
  <image name="Sally">{binary gibberish that breaks XML parsers}</image>
  <image name="Bobby">{binary gibberish that breaks XML parsers}</image>
</images>

你这样做:

<images>
  <image name="Sally" encoding="base64">j23894uaiAJSD3234kljasjkSD...</image>
  <image name="Bobby" encoding="base64">Ja3k23JKasil3452AsdfjlksKsasKD...</image>
</images>

XML解析器将能够正确解析XML文档并提取图像数据。

答案 2 :(得分:35)

为什么不关注the RFC that currently defines Base64

  

数据的基本编码用于   许多情况下存储或转移
  环境中的数据,也许是为了   遗产原因,仅限于   US-ASCII [1] data.Base编码可以   也可用于新的应用程序   没有遗留限制的,   只是因为它使它成为可能   用文本操纵对象   编辑器。

     

过去,不同的应用程序   有不同的要求和   因此有时实施基础   编码略有不同   方法。今天,协议规范   有时使用基本编码   一般,特别是“base64”,   没有准确的描述或   参考。多用途互联网邮件   经常使用扩展名(MIME)[4]   作为base64的参考没有   考虑到后果   换行或非字母   字符。这个目的   规范是建立共同的   字母和编码   注意事项。希望如此   减少其他方面的歧义   文件,导致更好   互操作性。

Base64最初被设计为允许将二进制数据作为多用途Internet邮件扩展的一部分附加到电子邮件的方法。

答案 3 :(得分:26)

专为文本数据设计的媒体当然最终也是二进制文件,但文本媒体通常会使用某些二进制值作为控制字符。此外,文本媒体可能会拒绝某些二进制值为非文本。

Base64编码将二进制数据编码为只能在文本媒体中解释为文本的值,并且没有任何特殊字符和/或控制字符,因此数据也将在文本媒体中保留。

答案 4 :(得分:16)

媒体验证字符串编码更多,因此我们希望确保处理应用程序可以接受数据(例如,不包含表示EOL的二进制序列)< / p>

想象一下,您希望在编码为UTF-8的电子邮件中发送二进制数据 - 如果1和0的流创建序列,则该电子邮件可能无法正确显示UTF-8编码。

当我们想要对URL本身中的URL无效的字符进行编码时,URL中会发生相同类型的事情:

  

http://www.foo.com/hello我的朋友 - &gt; http://www.foo.com/hello%20my%20friend

这是因为我们想在系统上发送空间,认为空间很臭。

我们所做的只是确保已知的良好,可接受和无害的位序列与另一个字面的位序列之间存在一对一的映射,并且处理应用程序无法区分编码。

在您的示例中,man可能是第一种形式的有效ASCII;但通常您可能希望传输随机二进制值(即在电子邮件中发送图像):

  

MIME-Version:1.0
  内容描述:“a.gif的Base64编码”
  内容类型:image / gif; NAME = “A.GIF”
  内容传输编码:Base64
  内容 - 处理:附件; filename =“a.gif”

在这里,我们看到GIF图像在base64中编码为电子邮件的一部分。电子邮件客户端读取标头并对其进行解码。由于编码,我们可以确定GIF不包含任何可能被解释为协议的内容,并且我们避免插入SMTP或POP可能发现重要的数据。

答案 5 :(得分:12)

我发现方便的一个例子是尝试embed binary data in XML时。 SAX解析器误解了一些二进制数据,因为这些数据可能实际上是任何东西,包括XML特殊字符。 Base64对发送端的数据进行编码并在接收端对其进行解码,解决了这个问题。

答案 6 :(得分:11)

Base64而不是转义特殊字符

我会给你一个非常不同但又真实的例子:我编写javascript代码以便在浏览器中运行。 HTML标记具有ID值,但对ID中有效字符有限制。

但我希望我的ID无损地引用我的文件系统中的文件。现实中的文件可以包含感叹号,重音字符,波浪形,甚至表情符号等各种怪异奇妙的字符!我不能这样做:

<div id="/path/to/my_strangely_named_file!@().jpg">
    <img src="http://myserver.com/path/to/my_strangely_named_file!@().jpg">
    Here's a pic I took in Moscow.
</div>

假设我想运行这样的代码:

# ERROR
document.getElementById("/path/to/my_strangely_named_file!@().jpg");

我认为这段代码在执行时会失败。

使用Base64我可以参考一些复杂的东西而不用担心哪种语言允许哪些特殊字符需要转义:

document.getElementById("18GerPD8fY4iTbNpC9hHNXNHyrDMampPLA");

与使用MD5或其他散列函数不同,您可以反转编码以找出实际有用的数据。

我希望我早年知道Base64。我会避免用'encodeURIComponent'和str.replace(‘\n’,’\\n’)

撕掉我的头发

SSH传输文本:

如果你试图通过ssh传递复杂的数据(例如一个dotfile,这样你可以获得你的shell个性化),祝你好运没有Base 64.这就是你用base 64做的方法(我知道你可以使用SCP,但这将需要多个命令 - 这使得键绑定变得复杂化了:

答案 7 :(得分:10)

大多数计算机以8位二进制格式存储数据,但这不是必需的。一些机器和传输介质一次只能处理7位(或甚至更少)。这样的介质会以7位的倍数来解释流,因此如果您要发送8位数据,则​​不会在另一侧收到您期望的内容。 Base-64只是解决此问题的一种方法:将输入编码为6位格式,通过介质发送,然后在接收端将其解码为8位格式。

答案 8 :(得分:5)

除了其他(有点冗长)答案之外:即使忽略仅支持7位ASCII的旧系统,在文本模式下提供二进制数据的基本问题是:

  • 换行符通常以文本模式转换。
  • 必须注意不要将NUL字节视为文本字符串的结尾,这在使用C lineage的任何程序中都很容易。

答案 9 :(得分:5)

  

它是什么意思“媒体是   旨在处理文本数据“?

这些协议旨在处理文本(通常只有英语文本)而不是二进制数据(如.png和.jpg图像)。

  

他们可以处理二进制=&gt;他们能   处理任何事情。

但反过来却不是这样。设计用于表示文本的协议可能会错误地处理恰好包含以下内容的二进制数据:

  • 字节0x0A和0x0D,用于行结尾,因平台而异。
  • 其他控制字符,如0x00(NULL = C字符串终结符),0x03(END OF TEXT),0x04(传输结束)或0x1A(DOS文件结束),可能过早地发出数据结束信号。< / LI>
  • 字节高于0x7F(如果是为ASCII设计的协议)。
  • UTF-8无效的字节序列。

因此,您不能仅通过基于文本的协议发送二进制数据。你只限于代表非空间非控制ASCII字符的字节,其中有94个。选择Base 64的原因是它使用2的幂更快,64是最大的工作

  

但有一个问题。那个怎么样   系统仍然不同意共同点   编码技术就像这么常见   UTF-8?

至少在网上,他们大多数都有。 A majority of sites use UTF-8

西方的问题是,有很多旧软件可以解决1字节= 1个字符并且无法使用UTF-8。

东方的问题是他们对GB2312和Shift_JIS等编码的依恋。

事实上,微软似乎仍然没有选择错误的UTF编码。如果要使用Windows API或Microsoft C运行时库,则限制为UTF-16或区域设置的“ANSI”编码。这使得使用UTF-8变得很痛苦,因为你必须一直转换。

答案 10 :(得分:5)

为什么/我们如何使用Base64编码?

Base64是二进制文本编码方案之一,效率为75%。它的使用使得典型的二进制数据(例如图像)可以通过传统安全地发送,而不是8位清洁&#34;通道。 在早期的电子邮件网络中(直到20世纪90年代初),大多数电子邮件消息都是7位US-ASCII字符集中的纯文本。如此多的早期通信协议标准被设计为在#7; 7位&#34;通讯链接&#34;不是8位清洁&#34;。 方案效率是输入中的位数与编码输出中的位数之间的比率。 十六进制(Base16)也是二进制到文本编码方案之一,效率为50%。

Base64编码步骤(简化):

  1. 二进制数据以24位(3字节)的连续块排列。
  2. 每个24位块被分组为4个部分,每个部分为6位。
  3. 每个6比特组被转换成它们对应的Base64字符值,即Base64编码将三个八比特组转换成四个编码字符。输出字节与输入字节的比率为4:3(开销为33%)。
  4. 有趣的是,相同的字符将根据它们在三个八位字节组中的位置进行不同的编码,这三个字节组被编码以产生四个字符。
  5. 接收方必须撤消此过程才能恢复原始消息。

答案 11 :(得分:3)

  

“旨在处理文本数据的媒体”是什么意思?

在ASCII统治世界处理非ASCII值的那一天是令人头疼的事。人们跳过各种各样的箍,通过电线传输这些箍而不会丢失信息。

答案 12 :(得分:3)

以下是我在阅读其他人发布的内容后的理解摘要:

重要!

Base64 编码并不意味着提供安全

Base64 编码不是为了压缩数据

我们为什么要使用 Base64

Base64 是数据的文本表示,仅由 64 个字符组成,包括字母数字字符(小写和大写)、+、/ 和 =。 这 64 个字符被认为是“安全的”,也就是说,与 <、> \n 等字符不同,它们不会被传统计算机和程序误解。

更新

我编写了一个用于 base64 编码和解码的 API。

对于 base64 编码,请使用:https://hrp-qr-api.herokuapp.com/base64encode

对于 base64 解码,使用:https://hrp-qr-api.herokuapp.com/base64decode

该 API 还执行了一些实现 EFRIS 所需的其他操作,例如生成 QR 图像、将 png 转换为位图、gzip 解压缩等。

相关问题