Base64 究竟是什么
0X00 前言
为什么要写这么一篇文章?按理说大家工作了一段时间之后肯定有一个最基础的认知:md5 不是加密,base64 也不是。起码我最开始以为大家应该都知道,但是后面发现有些人对这两个东西的理解真的有很大的问题。所以才打算写这么一篇文章。
事情的起因是这样的:
甲:“你用 base64 加密一下”
我:“base64 没有加密效果”
甲:“你给 base64 前面加上 32 个随机字符,让他解不出来不就行了”
我:“啊???”
所以我接下来打算首先介绍一下 base64 究竟是怎么得到的(算法本身),再来说明白 base64 为什么不可以通过前面加 32 个随机字符来实现“加密”(随机长度也不行)。
0X01 常识性的知识
首先我们明确一个事情,就是「编码」「加密」「哈希」之间的区别:
| 名称 | 是否可逆 | 是否安全 | 典型 |
|---|---|---|---|
| 编码 | 是 | 否 | base64 |
| 加密 | 是 | 是 | AES |
| 哈希 | 否 | 不总是 | md5 |
- 编码,是将一段内容通过某种算法直接转换成另一段内容,只是形式发生了变化,在明确编码算法的情况下是可以轻松解码获得原始内容的
- 加密,是将一段内容通过某种算法和 密码 将明文加密成密文,内容本身发生了变化,在明确加密算法的情况下没有密码也是无法解密的
- 哈希,是将一段内容通过某种算法转换成固定长度的另一段内容,原始数据会丢失,理论上无论如何都不可能通过哈希后的数据反推出原文
0X02 base64 编码
在明确了什么是编码后,来自顶向下拆解一下这个 base64 编码吧。首先名字中的 64 指的就是编码后的每一位都有 64 种有效字符,也就是 a-z 的 26 个小写字母、A-Z 的 26 个大写字母、0-9 的 10 个数字和 +/ 两个特殊字符,加一起正好是 64。
显然 64 指的是 6bit 能容纳的最大长度了,所以 base64 的编码逻辑就是:把一个二进制的数据按 6bit 一组分成 N 组,得到 N 个 0-63 之间的数,然后根据下面这张表把每组的数字替换成字符。

如果我的原文是二进制的 01101000 01100101 01101100 01101100 01101111(这是 UTF-8 编码的 hello),那么可以拆分成 011010、000110、010101、101100、011011、000110、1111,进而对应的是26、6、21、44、27、6、15,再对照上面的表格得到的就是 aGVsbGP。这样一来,我们的 hello 字符串就顺利转成 base64 编码了。。。吗?
并没有,因为最后一位的 1111 其实并不是严格对照上述表格查到的,所以我们应该给其尾部补二进制零,将其补充成 111100 对应索引 60,查表得到字符 8,将 P 替换得到 aGVsbG8。这样一来,我们的 hello 字符串就顺利转成 base64 编码了。。。吗?
并没有,我们发现得到的编码后字符串长度是 7,并不能按 4byte 一组进行拆分,所以最后还需要补充一个 =,最后得到的 base64 编码是 aGVsbG8=。这样一来,我们的 hello 字符串就顺利转成 base64 编码了。。。吗?
是的!不过为什么不能按 4byte 一组进行拆分就得在后面补 = 呢?因为解码器在后续解码的时候是按照编码后的字符串 4 个一组,将其转成 24bit 再分成 3 个 8bit 恢复成原始数据,所以在最后需要用 = 将 base64 的结果串补到 4 的整数倍长度。
有些不严谨的 base64 解码器在后面没有
=的时候也可能解得开,不过这是解码器的问题,不是标准的问题,就不过多探讨了。
0X02 为什么不能靠前缀加密
如果你比较敏感,可能发现了 base64 的一个特征,它的编码过程是分段进行的,也就意味着如果一个 base64 编码的前半段出现了错乱,是不影响它后半段的正确解码的。再加上 base64 的特征十分明显,明显指数应该是和 md5 坐同一桌的,所以很多技术人员是可以一眼看出这段字符串是 base64 编码的。
那么即使你在一段 base64 编码的前面追加了一段随机的内容,例如:zxclkjgheiqlourytaGVsbG8=,那我们现在尝试“破解”一下
- 先用在线解码工具尝试解码,发现失败了
- 发现长度是 25,不是 4 的整数倍,那就在最前面追加 3 个
x让它变成xxxzxclkjgheiqlourytaGVsbG8= - 再次尝试解码,就已经看到最后的
hello了
所以说,在 base64 编码得到的串前面追加所谓的随机字符串,是没有什么加密效果可言的





