为什么“用户名:密码”的结果字符串文字在授权标头中使用 Base64 编码?它的背景是什么?
2 回答
要理解以下内容,你应该对“字符集”和“字符编码”的区别有一个清晰的认识。
另外,请记住Base64是一种编码,编码不是加密。用 Base64 编码的任何内容都有意易于解码。
Base64编码,最重要的是,确保 user:pass 字符都是ASCII字符集和 ASCII 编码的一部分。HTTP Basic auth 中的 user:pass 是 Authorization 标头字段值的一部分。HTTP 标头值是 ASCII(或扩展 ASCII)编码/解码的。因此,当您对 user:pass 进行 Base64 编码时,请确保它是 ASCII,因此是有效的标头字段值。
Base64 编码还为明文 user:pass添加了至少某种混淆。同样,这不是加密。但是,它确实会阻止普通人一目了然地阅读 user:pass。从安全角度来看,这似乎几乎毫无意义,我之所以将其包括在内,是因为以下背景信息。
一些背景
如果您查看RFC 2616(现已过时)和RFC 2617,您会发现它们分别将标头字段值和基本身份验证 user:pass 定义为 TEXT;即,ISO-8859-1 OCTECT(ISO-8859-1 是 8 位扩展 ASCII 编码)。这很奇怪,因为这使得作者似乎打算让兼容的 user:pass 使用与 HTTP 标头所需的字符集/编码相同的字符集/编码,在这种情况下,Base64 编码似乎毫无意义,除了琐碎的混淆。
也就是说,很难相信那些 RFC 的作者没有想到用户名/密码是非 ASCII(非 ISO-8859-1)字符集。假设他们有非 ASCII user:passes,他们可能会担心如何在所有 ASCII 标头集的中间包含/维护/传输非 ASCII 字节。Base64 编码 user:pass 当然很好地解决了这个问题。使用 Base64 还有一个更规范的原因——使数据传输更可靠。我的理解是 HTTP 是8-bit clean;即使标头以 ASCII 形式提供,我不认为 user:pass 的 Base64 编码是为了使其传输更可靠。
如果不问原作者,我不确定我们是否会确定。 这是 Julian Reschke 对该主题的有趣评论。他是RFC 5987, Character Set and Language Encoding for Hypertext Transfer Protocol (HTTP) Header Field Parameters的作者。他还在 HTTP RFC 方面做了大量工作,包括最新的 HTTP 1.1 RFC 大修。
当前处理 HTTP 标头编码的 HTTP 1.1 RFC RFC 7230现在建议标头使用 USASCII(又名 ASCII,7 位 ASCII)。 RFC 5987定义了一个标头参数编码规范——大概有些人正在使用它。 RFC 7235是关于 HTTP 身份验证的 RFC 2617 的最新更新。
这是userid-password元组在编码之前的生产规则:
userid-password = [ token ] ":" *TEXT
这里的token指定如下:
token = 1*<any CHAR except CTLs or tspecials>
这基本上是 32 到 126 范围内的任何 US-ASCII 字符,但没有一些特殊字符((
, )
, <
, >
, @
, ,
, ;
, :
, \
, "
, /
, [
, ]
, ?
, =
, {
, }
, 空格和水平制表符)。
并且TEXT指定如下:
TEXT = <any OCTET except CTLs,
but including LWS>
这基本上是除控制字符(代码点 0-31、127 )之外的任何八位字节(0-255) 序列,但包括线性空白序列,这是一个或多个空格或水平制表符,前面可能有一个 CRLF 序列:
LWS = [CRLF] 1*( SP | HT )
尽管这不会破坏标头字段值,但LWS具有与单个空格相同的语义:
所有线性空格,包括折叠,都具有与 SP 相同的语义。
为了保持这样的序列不变,字符串在作为字段值放置之前被编码。