开发者工具 · Base64 编码器和解码器
如何使用 Base64 构建和解码 HTTP 基本身份验证标头
· 工作原理
base64 安全
授权:基本标头只是通过 Base64 运行的用户名:密码。这篇文章展示了如何构建该值,如何从请求日志中解码该值,以及为什么编码不隐藏任何内容。
尽管凭证正确,但 401 仍然存在——一个解码为微妙错误字符串的标头值
HTTP API 返回 401 Unauthorized 并需要 Authorization: Basic 标头。该值是方案字Basic、一个空格和一个Base64 字符串。即使可见的用户名和密码看起来正确,丢失的前缀、编码的前缀或未被注意到的换行符也会更改服务器接收的内容。
解码该字符串并读取用户名:密码(实际上是两个之间的冒号)。字节用户名:密码经过 UTF-8 编码,然后进行 Base64 编码,生成标头值。如果凭据为 admin:s3cret,UTF-8 字节为 0x61 0x64 0x6D 0x69 0x6E 0x3A 0x73 0x33 0x63 0x72 0x65 0x74(ASCII 字母加冒号),Base64 编码生成 YWRtaW46czNjcmV0,标头为 Authorization: Basic YWRtaW46czNjcmV0。
RFC 7617 中的配方:'user:pass', UTF-8, Base64 — 确切的步骤和冒号的作用
这是 RFC 7617 中定义的完整 HTTP 基本身份验证方案。它简单、标准化,并且本身不提供安全性:任何读取标头的人都可以立即对其进行解码以读取密码。这就是为什么 HTTPS 对于基本身份验证是必需的。编码是传输要求,而不是安全功能。密码以 UTF-8 字节传输,与任何其他数据相同; Base64 只是 HTTP 协议中使用的表示法。
如果需要从网络日志中解码 Basic 标头,过程很简单:剥离 Basic,Base64 解码剩余部分,并且您有用户名:密码。冒号是用户名和密码之间的分隔符。 RFC 7617 指定凭据为用户 ID:密码,第一个冒号是分隔符。如果密码包含冒号,则第二个冒号只是密码中的另一个字符。冒号是结构性的,因为接收者需要一个明确的边界。解码后搜索第一个冒号;它前面的所有内容都标识用户,后面的所有内容都是密码。因此,缺少冒号表示凭据对格式错误,而不是 Base64 字母问题。
工作示例:编码 admin:s3cret 并解码日志中的标头 - 两个方向,包括尾随换行错误
如果用户名是 admin,密码是 pass:word,则凭据是 admin:pass:word,编码为 YWRtaW46cGFzczp3b3Jk。解码时,必须仅在第一个冒号上分割,给出用户名 admin 和密码 pass:word。对每个冒号进行拆分会错误地拆分密码。 RFC 7617 中的字符集参数表示凭据采用 UTF-8 编码。这意味着用户名或密码中的非 ASCII 字符在 Base64 编码之前会转换为 UTF-8 字节。
如果用户名是咖啡馆(重音 e),则 UTF-8 字节为 0x63 0x61 0x66 0xC3 0xA9(四个字节用于 ASCII 字母,两个字节用于重音字符),并且完整凭据咖啡馆:密码包含咖啡馆字节,然后是冒号字节 0x3A,然后是密码。 Base64 输出忠实地编码所有字节。解码器必须知道将解码后的字节解释为 UTF-8 文本,而不是拉丁语-1。
包含冒号、空格和非 ASCII 的密码 — 为什么第一个冒号会分开,以及 charset 参数的用途
一个有效的示例:从 admin:s3cret 开始。转换为 UTF-8 字节:a=0x61、d=0x64、m=0x6D、i=0x69、n=0x6E、:=0x3A、s=0x73、3=0x33、c=0x63、r=0x72、e=0x65、t=0x74。十进制:(97、100、109、105、110、58、115、51、99、114、 101、116)。 Base64 对这些 12 字节进行编码:分为四组,每组三个(产生四组,每组四个 Base64 字符)。
编码值为 YWRtaW46czNjcmV0。授权标头为 Authorization: Basic YWRtaW46czNjcmV0。密码一侧可以包含另一个冒号,而无需移动第一个边界。当双方就文本编码达成一致时,空格和非 ASCII 文本也会保留。 ToolAcre 可以验证它发出的 UTF-8 字节,但需要不同字符集的旧服务器仍然是 Base64 转换之外的互操作性问题。
为什么没有 TLS 就不安全 — 解码会向看到标头的任何人显示密码
要解码收到的标头,请剥离 Basic、Base64 解码 YWRtaW46czNjcmV0 以获取字节,解释为 UTF-8 文本以获取 admin:s3cret,在第一个冒号上拆分以提取用户名和密码。一个常见的错误是 echo 尾随换行符。如果运行 echo admin:s3cret | Unix shell 中的 base64,echo 默认添加换行符,因此使用换行符对 admin:s3cret 进行编码(13 字节而不是 12)。
Base64 输出不同:YWRtaW46czNjcmV0Cg==(填充和额外字符)。具有此值的授权标头将失败,因为密码包含换行符。修复方法是使用 echo -n 或通过 printf 或不附加换行符的工具进行管道传输。 Base64 编码器和解码器避免了这种情况:准确编码您粘贴的内容,没有隐藏的换行符。 TLS 改变的是传输威胁,而不是凭证格式。在受保护的连接内,标头与请求的其余部分一起加密;一旦软件记录或显示它,Base64 值就会再次向任何能够解码它的人公开可重用凭证。在每个观察点,编辑仍然很重要。
常见错误 — echo 中的换行符、缺少“Basic”前缀以及对值进行双重编码
另一个错误是缺少基本前缀。授权标头值单独使用 Base64 无效;它是方案名称(Basic 或 Bearer 或其他),后跟空格,然后是凭据。某些系统无法将 YWRtaW46czNjcmV0 识别为凭据,但可以成功识别基本 YWRtaW46czNjcmV0。如果调试 401,请检查服务器是否正确解析授权标头。
方案在 HTTP 标准中不区分大小写,但许多实现是区分大小写的;检查 API 文档。双重编码是另一种失败模式。如果 Base64 编码已经经过 Base64 编码的字符串,则输出是不同的字符串。编码 YWRtaW46czNjcmV0 产生 WVdkbWFXNDZjek5qY3JldA== (完全不同)。某些系统可能会意外地应用编码两次:一次是在凭证设置期间,另一次是在构造标头时。 shell 命令中的换行符特别容易被忽略,因为它可以被编码为凭证的一部分,而不是作为 Base64 周围的空格被拒绝。生成的标头干净地解码为带有额外字节的密码,产生看起来像服务器端身份验证失败的 401 。
这不包括什么 - 摘要和承载方案,以及浏览器凭据提示
解码器需要单层 Base64,因此双重编码会导致不匹配。这就是为什么以 Base64 形式(非明文)记录凭证值可能会令人困惑:如果有人应用解码一次,他们会看到用户名和密码;如果应用两次,他们会看到混淆。摘要式身份验证 (RFC 7616) 和承载身份验证(针对 OAuth 令牌)使用不同的方案,每种方案具有不同的凭证格式。
摘要要求服务器发送随机数,客户端计算哈希值,标头包含哈希值和用户名,而不是密码。 Bearer 通常是 JSON Web Token (JWT),它是 Base64url 编码的,但不带有用户名前缀。基本身份验证比两者都简单,但如果没有 TLS,则完全不安全,因为凭证在标头中是可读的。摘要和承载使用相同的授权标头字段,但为其值分配完全不同的含义。浏览器凭据提示在 Basic 之上添加用户界面和缓存行为。本文停止构建和检查基本凭证有效负载,而不是比较这些身份验证系统。
要点:基本身份验证是 Base64,而不是保护 — Base64 编码器和解码器如何让您在本地检查标头值,而无需将凭证发送到任何地方
如果 API 支持多种身份验证方案,请选择最安全的可用方案。 Base64 编码器和解码器可以帮助调试基本身份验证失败:粘贴凭据字符串(用户名、冒号和密码),工具立即生成 Base64 值。将结果与标头发送进行比较,可以看到不匹配。相反,粘贴网络日志中的标头值,去除基本前缀,解码以查看服务器看到的内容。
为了学习,粘贴 admin:s3cret 并观察输出,然后修改密码以查看 Base64 如何变化。了解标头的构建方式可以阐明为什么解码需要了解 RFC 格式以及为什么冒号是结构元素,而不是 Base64。本地检查应使用发明的凭据,而不是从生产环境复制的实时密码。对这对进行编码,将输出移回输入面板,然后对其进行解码。匹配的标点符号和精确的尾随字符在标头发送到任何地方之前证明了表示往返。