Skip to content

Base64编码详解与URL安全的Base64编码

Base64的基本编码方式

base64编码是一种常见的编码方式,主要用于对8bit的字节进行编码。具体的编码方式是:

  1. 把三个字节作为一组,转化为二进制的形式,一共3*8=24个二进制位。
    例如: abc 三个字符用ASCII编码,转换为二进制:
    01100001 01100010 01100011
  2. 把24个二进制数字每6个一组,分为4组:
    01100001 01100010 01100011 被分为
    011000 010110 001001 100011
  3. 按照表格,把每组二进制串转为对应字符:  ​​ 表格来源于百度百科

011000 010110 001001 100011 先转为十进制数字:

24 22 9 35 对照表格,转化为字符串:

YWJj

这个字符串就是最终的Base64编码,与网络上在线编码器生成的一致: ​​

字节数不能被三整除时的特殊处理

如果需要编码的字节不能被3整除怎么办?比如最后剩下一个单字节a,或者双字节ab。这时候我们需要特殊处理:

  1. 不足6个二进制位的补0
  2. 不足4组的,最后补字符串=

单字节a:
a => 01100001 => 011000 01 => 补0 =>
011000 010000 => 24 16 => YQ => 补=符号 => YQ==
双字节ab:
ab => 01100001 01100010 => 011000 010110 0010 => 补0 =>
011000 010110 001000 => 24 22 8 => YWI => 补=符号 => YWI=

安全的Base64编码概念

通过上面的对照表可以看到,除了大小写字母和数字之外,Base64编码后的字符串中可能包含"+/="之类的字符,而"/","="等是URL的保留字符或不安全字符,因此如果直接在URL中传输Base64编码,保留字符和不安全字符会被替换为%XX的形式,对后端来说解码不方便。如果不替换,就会造成URL注入漏洞。

因此,有一种URL安全的Base64编码,可以解决这个问题。 URL安全的Base64编码特点:

  1. 不能被3整除时,不补=符号。
  2. 生成Base64编码中,"+"和"/"被替换成其他非URL保留字符,使其可以直接放入URL中传输。
    比如"+"和"/"被替换成"-"和"_"。

安全的Base64编码也有好多种,有些编码不会去掉等号,有些编码替换的符号不同。

注意示项和示例

注意,是编码后的"+"和"/"被替换,而不是编码前的原始字符被替换,而这种情况并不常见。在没有遇到补齐和编码后出现"+"和"/"的场景下,安全和不安全的Base64编码输出是一致的。

这里看几个例子:

  1. 原字符串 abcdef
    原始Base编码: YWJjZGVm
    安全Base编码: YWJjZGVm
  2. 原字符串 +/=
    原始Base编码: Ky89
    安全Base编码: Ky89
  3. 原字符串 06?
    原始Base编码: MDY/
    安全Base编码: MDY_

可以看到,即使原字符串中包含+/等特殊字符,也与Base编码是否安全无关。只有在生成后的编码中包含+/等特殊字符时,才会出现安全的Base64编码与原始Base编码不同而情况。

Web前端中的使用

Web前端中有几种常见的Base64编码的函数和库,这几种库是安全的还是不安全的?我进行了测试:

js
import { Base64 } from "js-base64";
import { btoau, atobu } from "b2a";
const item = '06?';
// 方法1
const encode1 = Base64.encode(item);
const decode1 = Base64.decode(encode1);
// 方法2
const encode2 = btoau(item);
const decode2 = atobu(encode2);
// 方法3
const encode3 = window.btoa(item);
const decode3 = window.atob(encode3);

这是三种web前端常用的Base64编码方法。方法1使用了js-base64库,方法2使用了b2a库,方法3是window对象自带的编码方法。我用几个字符串进行了测试:

总结:三个Base64编码函数,方法1是原始的,方法2和3是安全的。但是三个方法都没有去掉最后的"="符号。实际开发中使用时,需要和后端的解码方法保持一致即可,如果不一致,可能会遇到特殊数据时后端无法正常解码。另外,目前网络上常用的在线Base64编解码,一般都是原始的Base64编码形式,并不是安全的。