授权与合规声明
本文全部操作对象均为自建隔离靶场(本机容器或隔离虚拟机),涉及安全测试的环节必须以取得合法授权为前提。未经授权的渗透测试违反《中华人民共和国网络安全法》与《刑法》相关条款,须承担相应法律责任。本文只讲环境配置、版本对照与靶场隔离,不含任何攻击步骤、利用载荷与绕过手法,请勿将文中环境指向任何非自有系统。
一、现象:三串看起来都像乱码的东西
1.1 抓包里那一条
抓 HTTP 升级请求时,很多人第一次注意到的是请求头里这一行:
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
这串值的出处是 RFC 6455 的握手示例(BE15),是公开文档里印着的示例值,不是任何真实凭据。第一次看到它的人通常有两个反应:“这肯定加密过了吧”,以及"那我把它解开是不是就拿到秘密了"。
两个反应都自然——这串东西确实像"被处理过"。问题在于:"被处理过"和"被保护了"是两件事。
1.2 三种"乱码",长得像,问的问题不一样
三串"乱码"并排放一起,差异马上出来。
| 你看到的东西 | 它更可能是 | 一个立刻能做的小检验 |
|---|---|---|
dGhlIHNhbXBsZSBub25jZQ== | Base64 编码 | 按公开字母表还原,全程不需要任何密钥 |
666F6F626172 | Base16(十六进制)编码 | 每两个字符对应一个字节,字符只用 0-9A-F |
| 一串定长的十六进制字符 | 摘要(哈希) | 想从它反推原文,没有一条确定的路 |
要害在于:前两行是"换个写法",第三行才是"换个东西"。
1.3 本文只回答一个问题
本文只回答一件事:这三类转换各自解决什么问题,以及为什么"看起来像乱码"不能当作"已经被保护了"的证据。
两条边界先划清楚:
- 百分号编码、UTF-8 字节、HTML 实体与 URL/JSON 转义,是"字符与字节怎么互转"的另一类问题,本文不展开。
- 本文不写任何"怎么把某串东西还原出来"的思路,也不涉及任何以猜出别人凭据为目的的做法。
另外,"下载之后怎么核对文件"属于校验和与签名那条轴,本文不重复,第五章末尾一句切分。
本章可以带走的一句:把"看起来像乱码"当成"已经被保护",是这一整类误解的起点;先分清楚它是编码、摘要还是加密,再谈保护。
二、三个问题各不相同:能不能还原、有没有密钥、是不是单向
2.1 第一问:能不能还原
编码和加密都能还原——但这话只说了一半。分岔在于还原时要不要一把钥匙。
Base64 的还原不需要任何秘密。RFC 4648 第三、四节定义的是一套公开的字母表和一套公开的切分规则(BE02、BE03),谁拿到那串字符都能照同样的表倒回去。它没有"输入密码才准解"这一层——设计目标里根本没有"阻止别人解"。
2.2 第二问:有没有密钥
编码这个位置上不存在密钥这个概念——不是"密钥很短",是整件事里没有它。加密有密钥,密钥是"能不能还原"的唯一闸门:闸门在,原文取不回来;闸门丢给别人,原文就等于公开。
所以"我把这段 Base64 解开了"和"我把这段密文解开了"分量完全不同:前者只说明你会查表,后者说明你拿到了不该拿的东西。
2.3 第三问:是不是单向
摘要的关键不在于"很难还原",而在于设计上就不提供还原这条路。OWASP 的《Password Storage Cheat Sheet》把它写成一句定义(BE16):
hashing is a one-way function
——哈希是一个单向函数。紧跟着的括号把"单向"解释得更直白:不可能把一个哈希"解密"回原始明文值。
注意措辞是"不可能",不是"很困难":这是设计上的性质,不是一把能靠算力磨开的锁。把摘要理解成"一种特别难解的加密",后面所有判断都会跟着偏。
2.4 一张对照表
三个问题合起来就是这张表。
| 转换 | 有没有密钥 | 能不能还原 | 典型用途 |
|---|---|---|---|
| Base16 / Base32 / Base64 编码 | 没有 | 能,任何人照公开字母表就能还原 | 把二进制塞进只收 ASCII 的场合,便于放进文本搬运 |
| 摘要(哈希) | 没有 | 不能,规则上就是单向 | 校验、指纹,以及口令校验时的比对对象 |
| 加密 | 有 | 能,但必须先有密钥 | 需要把原文取回来的场合 |
第一行和第三行都"能还原",差别全在第二列;第二行和第三行都"看起来乱",差别全在第三列。
本章可以带走的一句:判断一串东西是编码、摘要还是加密,问三个问题就够了——不要密钥能不能还原、还原时需不需要密钥、规则上允不允许还原。
三、Base64 到底做了什么
3.1 它要解决的问题:只收 ASCII 的场合
RFC 4648 第一节把理由写得很朴素(BE01):
Base encoding of data is used in many situations to store or transfer data in environments that, perhaps for legacy reasons, are restricted to US-ASCII [1] data.
——base 编码被用在很多场合,用来在只收 US-ASCII 的环境里存数据或传数据,而这些限制"也许出于历史原因"。
那个 “perhaps for legacy reasons” 是官方留的余地:受限环境不一定都是老系统;第一节还补了一句,没有历史包袱的新应用也能用它。
它从头到尾讲的是兼容性,一个字都没提"保密"。
3.2 六位一组:24 位进,4 个字符出
第四节给了两句关键定义(BE02、BE03):
A 65-character subset of US-ASCII is used, enabling 6 bits to be represented per printable character. (The extra 65th character, “=”, is used to signify a special processing function.)
The encoding process represents 24-bit groups of input bits as output strings of 4 encoded characters.
——用 US-ASCII 里一个65 字符子集,使每个可打印字符承载 6 位;多出来的第 65 个字符=表示一个特殊处理动作。编码则把输入的24 位一组输出成4 个编码字符。
机制于是全出来了:三个字节 24 位,正好切成四个 6 位小组,每组取值 0 到 63,拿去查那张 64 字符的表。表完全公开:
| 索引 | 字符 | 索引 | 字符 |
|---|---|---|---|
| 0 | A | 52 | 0 |
| 25 | Z | 61 | 9 |
| 26 | a | 62 | + |
| 51 | z | 63 | / |
(上表只摘首尾几个索引示意,完整表见 RFC 4648 第四节 Table 1。)
2026-10-15 本机实测
python3-c"import base64; print(base64.b64encode(b'foobar'))"实测环境 Python 3.13.12(BE37),输出b'Zm9vYmFy',与第十节测试向量BASE64("foobar") = "Zm9vYmFy"一致(BE38)。这就是它的全部机制:一个查表动作。
3.3 填充:=到底在补什么
=最容易被误读成"结束标记"。第三节说得很平实(BE05、BE06、BE07):
In some circumstances, the use of padding (“=”) in base-encoded data is not required or used. In the general case, when assumptions about the size of transported data cannot be made, padding is required to yield correct decoded data.
Implementations MUST include appropriate pad characters at the end of encoded data unless the specification referring to this document explicitly states otherwise.
The base64 and base32 alphabets use padding, as described below in sections 4 and 6, but the base16 alphabet does not need it; see section 8.
——填充不是永远必需:传输长度无法事先假定时,需要填充才能正确解码;实现必须在末尾加合适填充字符,除非规范另有说明;base64 与 base32 使用填充,base16 不需要。
补几个?第四节按"最后一组还剩几位"分三种情形(BE04):
(1) The final quantum of encoding input is an integral multiple of 24 bits; here, the final unit of encoded output will be an integral multiple of 4 characters with no “=” padding.
(2) The final quantum of encoding input is exactly 8 bits; here, the final unit of encoded output will be two characters followed by two “=” padding characters.
(3) The final quantum of encoding input is exactly 16 bits; here, the final unit of encoded output will be three characters followed by one “=” padding character.
——末尾正好 24 位:输出是 4 的整数倍,不加填充;剩 8 位:两个字符加两个=;剩 16 位:三个字符加一个=。
base32 同理,只是分组更小、填充更长(BE08):
(2) The final quantum of encoding input is exactly 8 bits; here, the final unit of encoded output will be two characters followed by six “=” padding characters.
(5) The final quantum of encoding input is exactly 32 bits; here, the final unit of encoded output will be seven characters followed by one “=” padding character.
——剩 8 位是两个字符加六个=;剩 32 位是七个字符加一个=。
base16 干脆不需要填充,第八节只有一句(BE09):
Unlike base 32 and base 64, no special padding is necessary since a full code word is always available.
——base16无需特殊填充,因为完整码字总是够用。
2026-10-15 本机实测
python3-c"import base64; print(base64.b64encode(b'f'), base64.b64encode(b'fo'), base64.b64encode(b'foo'), base64.b64encode(b'foob'))"实测输出b'Zg=='、b'Zm8='、b'Zm9v'、b'Zm9vYg==',与第十节四行测试向量逐条吻合。看它们的差别:填充个数只说明"最后一组还剩几个字节",此外什么都不说明——Zg==不比Zm9v更安全。
3.4 base64url:为 URL 和文件名换掉两个字符
字母表里有两个字符在 URL 和文件名里容易惹麻烦:+和/。第五节给出了一个变体(BE10、BE11):
This encoding may be referred to as “base64url”. This encoding should not be regarded as the same as the “base64” encoding and should not be referred to as only “base64”. Unless clarified otherwise, “base64” refers to the base 64 in the previous section.
This encoding is technically identical to the previous one, except for the 62:nd and 63:rd alphabet character, as indicated in Table 2.
——这个编码可以叫作 “base64url”,但不该被当成和 “base64” 同一种编码;除非另有澄清,“base64” 指的就是上一节那种。两者在技术上完全相同,只差第 62、63 个字母表字符。
也就是说,base64url 只是把+换成-、把/换成_:同样是换写法,不是加保护。
它和填充的关系也顺带交代:第五节说明=在 URI 里通常需要额外处理,而长度可推知时就能跳过填充(该话题属于另一篇)——这是场合差异,不是安全差异。
2026-10-15 本机实测
python3-c"import base64; print(base64.urlsafe_b64encode(bytes([251,255])))"实测输出b'-_8=':两个字节 0xFB、0xFF 在标准表里本该编到+与/,在 URL 安全表里换成了-与_。同一输入、两套字母表,只差那两个位置。
本章可以带走的一句:Base64 做的事情只有一件——把一串字节按公开的字母表换一种写法;6 位一组、=补齐,自始至终没有密钥参与。
四、为什么 Base64 会被当成加密
4.1 官方那句最要紧的话
第十二节 “Security Considerations” 里有一句,几乎是为这个误会写的(BE12):
Base encoding visually hides otherwise easily recognized information, such as passwords, but does not provide any computational confidentiality.
——base 编码在视觉上把本来一眼能认出来的信息(例如口令)藏了起来,但不提供任何"计算意义上的保密性"。
两个限定词一个都不能漏:“visually” 说的是眼睛看不出来,“computational confidentiality” 说的才是别人算不出来。Base64 只完成了前半句。
4.2 官方补充的"已知会造成安全事故"
同一节紧接着给出后果,写得很具体(BE13):
This has been known to cause security incidents when, e.g., a user reports details of a network protocol exchange (perhaps to illustrate some other problem) and accidentally reveals the password because she is unaware that the base encoding does not protect the password.
——这件事已知造成过安全事故:有人为了说明某个别的协议问题,把协议交互的细节贴了出来,因为不知道 base 编码并不保护口令,于是顺带把口令暴露了。
这段里没有攻击者,也没有技术门槛。成因是当事者误判了这串东西的保护等级:看到"乱码",补上"加密过的",就放心贴了出去。"看起来像乱码"之所以危险,正在于它不必骗过任何程序,只要骗过一个人。
4.3 还有一句关于"信息量"的判断
同一节最后一段否掉了"编码把信息变模糊了"这个侥幸(BE14):
Base encoding adds no entropy to the plaintext, but it does increase the amount of plaintext available and provide a signature for cryptanalysis in the form of a characteristic probability distribution.
——base 编码不给明文增加任何熵,反而让可用的明文变多了,并留下一个**"特征性的概率分布"作为分析的把柄**。
两层意思:编码不创造不确定性,进多少熵出多少熵;而且那套固定字母表一眼就能看出"这是 Base64",连"该往哪个方向看"都替别人省了。
4.4 三种错觉,各自错在哪
乱码错觉:"我看不懂,所以别人也看不懂。"官方那句 “visually hides” 说的正是这个——藏得住的只是眼睛,不是计算。
长度错觉:"编码后变长了,看起来更厚实。"Base64 把三个字节变成四个字符,长度确实多了三分之一,但它不增加熵——只增加搬运体积。
唯一性错觉:"这串东西只有我能生成。"恰恰相反,同一份输入谁编都是同样输出——加密有密钥,同一份明文用不同密钥得到不同密文,编码没有。
2026-10-15 本机实测
python3-c"import base64; s='dGhlIHNhbXBsZSBub25jZQ=='; print(base64.b64decode(s)); print(base64.b64encode(b'the sample nonce'))"实测输出两行:解出来是b'the sample nonce',再编回去又回到那串示例值。全程没有输入任何密钥,也没有权限或凭证环节——这就是"能还原但没有密钥"的具体样子。
本章可以带走的一句:Base64 只把东西"藏起来给人看",不把它"锁起来给人算";官方原话说得很清楚——它不提供任何计算意义上的保密性。
五、摘要与加密的分界
5.1 单向与双向
分界线由 OWASP 备忘单 “Hashing vs Encryption” 一节直接给出(BE16、BE17):
Because hashing is a one-way function (i.e., it is impossible to “decrypt” a hash and obtain the original plaintext value), it is the most appropriate approach for password validation. Even if an attacker obtains the hashed password, they cannot use it to log in as the victim.
Since encryption is a two-way function, attackers can retrieve the original plaintext from the encrypted data.
——因为哈希是单向函数(不可能把哈希"解密"回原始明文值),所以它是做口令校验最合适的做法:即便有人拿到了那个哈希,也没法拿它去冒充本人登录。而加密是双向函数,对方可以从加密数据里取回原始明文。
这两句摆正了关系:它们是方向不同的两种工具,不是"强弱两档"的同一个工具。加密能双向是用途所在(备忘单举的例子是住址这类要按明文显示的数据),摘要只能单向同样如此。
5.2 "快"在摘要这里是缺点
"MD5 为什么不能存密码"的答案就在这两句里(BE19、BE20):
Fast hashing algorithms such as SHA‑256 are not suitable for password storage because they allow attackers to perform large numbers of guesses quickly.
This means that they should be slow (unlike algorithms such as MD5 and SHA-1, which were designed to be fast), and you can change how slow they are by changing the work factor.
——像 SHA‑256 这样的快速哈希算法不适合存口令,因为它们让别人能很快地做大量尝试。备忘单讲专门算法时又补了一句:这类算法应当慢,不像 MD5 和 SHA-1 那样是为"快"而设计的,而且其慢可通过工作因子调整。
这里没有说 MD5 或 SHA-1 是"坏算法"。它们的定位是快速算出校验指纹,在这个位置上做得很好;一旦被放到"存放口令的比对对象"这个位置,"快"立刻变成缺点——它把别人每次尝试的成本压得极低。算法没变,位置变了,评价就反过来了。
5.3 摘要的用途不是"存起来再还原"
备忘单在 “Hashing vs Encryption” 开头就把结论写成了整段加粗(BE18):
Hashing and encryption can keep sensitive data safe, but in almost all circumstances, Passwords should be securely hashed using modern, adaptive hashing algorithms (e.g., Argon2id, bcrypt, or PBKDF2), rather than encrypted or stored in plaintext.
——哈希和加密都能保护敏感数据,但在几乎所有情形下,口令都应该用现代的、自适应的哈希算法(例如 Argon2id、bcrypt 或 PBKDF2)来安全地哈希,而不是加密存放或明文存放。
注意措辞顺序:不是"哈希比加密好",而是"这个位置上该用的工具是哈希"。文档保留了一个例外(BE35)——只有必须拿到原始明文口令的场合才考虑加密存放,且应尽可能改用别的架构来避免这种需要。
所以摘要的正确姿势是:存的是"比对对象",不是"待还原的原文"。校验时把新输入的算一遍,对得上就通过,不需要还原原来那个。
5.4 一句切分:文件完整性核验
顺带划一条界:"下载之后怎么核对文件有没有被动过"是校验和与签名那条轴上的事,本文不重复,只在这里一句切分。两者都用哈希,但问的问题不同:一个问"字节有没有被改过",一个问"人是不是原来那个人"。
配套资料:把全文的"三种转换怎么分、Base64 的六位分组与填充、摘要与加密的分界、口令存放的四类算法定位"收成一页速查卡,放在资料包里,扫码即可获取:
本章可以带走的一句:摘要与加密是两个方向的工具——加密双向、靠密钥,摘要单向、没有密钥;判断某个位置该用哪一个,先问"我要不要把原文取回来"。
六、那密码到底该怎么存
6.1 先划掉三种做法
明文存放,没有讨论余地(BE36):
Passwords should never be stored in plain text.
——口令永远不应以明文存储。
加密存放,只留一个极窄的例外:5.3 引过的原文说,只有必须拿到原始明文口令的边缘场合才考虑,且应优先换架构绕开这个需要。
用快速哈希,位置不对:5.2 已交代,为"快"而设计的算法不适合放在这个位置上。
三种划完,剩下的是同一类工具:专门为口令设计的慢哈希算法,再配上盐和工作因子。
6.2 加盐:每个口令配一个独有的随机串
盐的定义很直接(BE21):
A salt is a unique, randomly generated string that is added to each password as part of the hashing process.
——盐是一段唯一的、随机生成的字符串,在哈希过程中加进每一个口令。
为什么必须唯一(BE22):
As the salt is unique for every user, an attacker has to crack hashes one at a time using the respective salt rather than calculating a hash once and comparing it against every stored hash.
——因为盐对每个用户都唯一,别人只能逐个地用各自的盐去处理,而不能"算一次、再跟所有哈希逐一比对"。
这句话点出的正是加盐防的东西:"算一次、批量比对"这条路被堵掉了。备忘单还补了两条(BE23、BE24):加盐也防止预先算好大批哈希再查表;因为盐不同,同样口令也得到不同哈希,"两个用户是否同一口令"也就看不出来。
一处很实用的提醒(BE25):
However, most widely used implementations and libraries automatically generate and manage salts internally, so application developers typically do not need to handle salt generation manually when using these libraries correctly.
——大多数广泛使用的实现和库会在内部自动生成并管理盐,只要正确使用这些库,开发者通常不需要手工处理盐的生成。对写代码的人,意思很明确:要理解的是盐为什么必须唯一,那个随机串怎么造交给库。
6.3 工作因子:把"算一遍"的代价调上去
盐解决"不能批量算",工作因子解决"每一遍都别太便宜"(BE26):
The work factor is the number of iterations of the hashing algorithm that are performed for each password (usually, it’s actually 2^work iterations). The work factor is typically stored in the hash output. It makes calculating the hash more computationally expensive, which in turn reduces the speed and/or increases the cost for which an attacker can attempt to crack the password hash.
——工作因子是每个口令要跑多少轮哈希(实际通常是 2 的 work 次方轮),一般会被存进哈希输出;它让算一次哈希更贵,从而降低对方尝试速度、抬高对方成本。
注意方向:它不让"还原"变得不可能,只让每次尝试都变慢——一个纯粹的代价旋钮。但它不能拧到底(BE27):
When you choose a work factor, strike a balance between security and performance.
——要在安全与性能之间取平衡;原文补了一句:理想取值没有黄金法则,取决于服务器性能与用户规模,需在实际服务器上实验才能定。
取舍逻辑值得说透:调高之后对方变慢,但你自己校验一次登录也同步变慢,调太高还可能被大量登录请求拖垮 CPU——两端都要顾。
它还有一个好性质(BE28):
One key advantage of having a work factor is that it can be increased over time as hardware becomes more powerful and cheaper.
——它可以随硬件变强变便宜而逐步调高,今天定下的参数不会永久锁死,等硬件上去了把旋钮拧大一档即可(原文的做法是在用户下次登录时用新参数重新哈希)。
6.4 四类算法,各自的位置
备忘单点名了四种算法,并给每一种标了位置。这里只读"它在什么位置上用",具体参数取值本文不抄。
Argon2id:Argon2 是相关竞赛胜出者,三个版本里应选Argon2id,因为它对侧信道与基于 GPU 的攻击提供了均衡的应对(BE29)。
scrypt:定位很明确——Argon2id 应当是口令哈希的首选,只有它不可用时才用 scrypt(BE30)。
bcrypt:定位更窄——只应在 Argon2 和 scrypt 都不可用的遗留系统里用于口令存放(BE31)。
PBKDF2:位置由合规需求决定——因被相关标准允许且实现经过验证,有这些要求时它应当是首选(BE32)。
共同原则是一句(BE33):
When selecting a password hashing algorithm, developers should prefer modern algorithms that are designed to resist both GPU-based and memory-based attacks.
——应当优先选为同时抵抗基于 GPU 的攻击与基于内存的攻击而设计的现代算法。
四条并排看,它们不是"四个等级",而是四个位置:新系统首选 Argon2id,不可用时退到 scrypt,遗留系统里用 bcrypt,有合规要求时用 PBKDF2。位置不同,判断标准就不同。
6.5 一个反直觉的细节:算法不必隐藏
最后一句容易被忽略,却和主题高度呼应(BE34):
You do not need to hide which password hashing algorithm is used by an application.
——你不需要隐藏一个应用用的是哪种口令哈希算法。
这句话把主题收了回来:安全不来自"别人不知道我做了什么",而来自"知道了也没用"。别人知道你用哪种算法、知道你加了盐,依然要逐个逐轮地算下去——挡住他的不是秘密,是代价。Base64 恰好相反:“一眼看不出,但知道了就毫无障碍”。
本章可以带走的一句:口令存放靠的不是"藏",而是"慢"——用为这个位置设计的慢哈希算法,给每个口令配一段唯一的盐,再把工作因子调到安全与性能都受得住的位置。
七、收束
回到开头那一行Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==。
现在再看它,判断路径已经很短:末尾两个等号是第三章见过的填充,字母表就是 Base64 那一套,它来自公开规范里的示例,本身不是凭据。“能一眼看出是 Base64”,正是它不属于加密的最直接证据之一。
把全文压成一次判断,就是三个问题依次问下去:
第一问,有没有密钥?没有密钥参与的是编码或摘要,不是加密。这一问把 Base64、Base16、Base32 全部分到"换写法"那一类。
第二问,规则上允许不允许还原?允许还原的是编码;不允许还原、设计上单向的是摘要。这一问把摘要单独拎了出来。
第三问,要还原就得有密钥的,才是加密。它不是"更强的编码",而是另一件工具:能双向、靠密钥,密钥丢了原文就取不回来。
三个问题问完,标题那句话也就落地了——编码解决"传得过去",摘要解决"对得上",加密解决"拿不走"。把其中一件当成另一件,最常见的后果不是"多花了功夫",而是像 RFC 4648 第十二节描述的那样,把一串没被保护的东西当成被保护的东西发了出去。
至于口令这类最容易被误判的数据,方向在第六章说完了:不用"藏"的思路,用"慢"的思路——慢哈希算法、每个口令一段唯一的盐、一个取平衡的工作因子。
配套资料:全文的一张总表——“编码 / 摘要 / 加密三问判定 + 口令存放四类算法定位 + Base64 填充规则”,连同这份边界清单放在资料包里,扫码即可获取:
本章可以带走的一句:编码解决"传得过去",摘要解决"对得上",加密解决"拿不走"——先问清楚要解决哪一个,再决定用哪一类工具。
附表 A:本文引用事实与官方出处对照表
| # | 事实(一句) | 出处(文档名 + 章节号 + 链接) | 核验日期 | 本文位置 |
|---|---|---|---|---|
| BE01 | base 编码用于只收 US-ASCII 的环境里存传数据 | RFC 4648 §1(https://www.rfc-editor.org/rfc/rfc4648) | 2026-10-15 | 第 3 章 |
| BE02 | US-ASCII 的 65 字符子集,每字符承载 6 位;=表示特殊处理动作 | RFC 4648 §4 | 2026-10-15 | 第 2、3 章 |
| BE03 | 编码把输入的 24 位一组输出成 4 个字符 | RFC 4648 §4 | 2026-10-15 | 第 3 章 |
| BE04 | base64 末尾:整除 24 位不加填充;剩 8 位加两个=;剩 16 位加一个= | RFC 4648 §4 (1)(2)(3) | 2026-10-15 | 第 3 章 |
| BE05 | 填充并非永远必需;长度无法假定时需填充才能正确解码 | RFC 4648 §3.2 | 2026-10-15 | 第 3 章 |
| BE06 | 实现必须在末尾加合适填充字符,除非规范另有明确说明 | RFC 4648 §3.2 | 2026-10-15 | 第 3 章 |
| BE07 | base64 与 base32 用填充,base16 不需要 | RFC 4648 §3.2 | 2026-10-15 | 第 3 章 |
| BE08 | base32 末尾:剩 8 位加六个=;剩 32 位加一个= | RFC 4648 §6 (2)(5) | 2026-10-15 | 第 3 章 |
| BE09 | base16 无需特殊填充,完整码字总是可用 | RFC 4648 §8 | 2026-10-15 | 第 3 章 |
| BE10 | 该编码可称 “base64url”,不应视为与 “base64” 相同 | RFC 4648 §5 | 2026-10-15 | 第 3 章 |
| BE11 | base64url 与上一节技术上相同,只差第 62、63 个字符 | RFC 4648 §5 | 2026-10-15 | 第 3 章 |
| BE12 | base 编码视觉上隐藏口令这类信息,但不提供计算意义上的保密性 | RFC 4648 §12 | 2026-10-15 | 第 4 章 |
| BE13 | 已知会造成安全事故:有人贴协议交互细节时顺带暴露口令 | RFC 4648 §12 | 2026-10-15 | 第 4 章 |
| BE14 | base 编码不加熵,却增加可用明文并留下特征性概率分布 | RFC 4648 §12 | 2026-10-15 | 第 4 章 |
| BE15 | dGhlIHNhbXBsZSBub25jZQ==是规范握手示例里的Sec-WebSocket-Key值 | RFC 6455 §1.3 / §4.2.2 示例 | 2026-10-15 | 第 1、7 章 |
| BE16 | 哈希是单向函数,不可能把哈希"解密"回原始明文值 | OWASP Password Storage Cheat Sheet · Hashing vs Encryption(https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html) | 2026-10-15 | 第 2、5 章 |
| BE17 | 加密是双向函数,对方可取回原始明文 | OWASP 同上 · Hashing vs Encryption | 2026-10-15 | 第 5 章 |
| BE18 | 口令应用现代自适应哈希(如 Argon2id、bcrypt、PBKDF2)而非加密或明文存放 | OWASP 同上 · Hashing vs Encryption | 2026-10-15 | 第 5 章 |
| BE19 | 像 SHA‑256 这类快速哈希不适合存口令,因它让人能快速做大量尝试 | OWASP 同上 · Introduction | 2026-10-15 | 第 5 章 |
| BE20 | 这类算法应当慢(不像为"快"而设计的 MD5 与 SHA-1),可由工作因子调整 | OWASP 同上 · Password Hashing Algorithms | 2026-10-15 | 第 5 章 |
| BE21 | 盐是一段唯一的、随机生成的字符串,哈希时加进每个口令 | OWASP 同上 · Salting | 2026-10-15 | 第 6 章 |
| BE22 | 盐对每个用户唯一,故只能逐个处理,不能算一次再比所有哈希 | OWASP 同上 · Salting | 2026-10-15 | 第 6 章 |
| BE23 | 加盐也防止预先算好一批哈希再查表 | OWASP 同上 · Salting | 2026-10-15 | 第 6 章 |
| BE24 | 加盐使同样口令得到不同哈希,无法直接判断是否同口令 | OWASP 同上 · Salting | 2026-10-15 | 第 6 章 |
| BE25 | 多数实现与库自动生成并管理盐,正确使用时无需手工处理 | OWASP 同上 · Salting | 2026-10-15 | 第 6 章 |
| BE26 | 工作因子是每个口令跑的哈希轮数(通常 2^work 轮),一般存于哈希输出 | OWASP 同上 · Using Work Factors | 2026-10-15 | 第 6 章 |
| BE27 | 工作因子要在安全与性能间取平衡,无黄金法则,需在目标服务器上实验 | OWASP 同上 · Using Work Factors | 2026-10-15 | 第 6 章 |
| BE28 | 工作因子的好处是可随硬件变强变便宜而逐步调高 | OWASP 同上 · Upgrading the Work Factor | 2026-10-15 | 第 6 章 |
| BE29 | Argon2 是相关竞赛胜出者;应选 Argon2id,对侧信道与 GPU 攻击均衡 | OWASP 同上 · Argon2id | 2026-10-15 | 第 6 章 |
| BE30 | Argon2id 应是首选,scrypt 只在它不可用时使用 | OWASP 同上 · scrypt | 2026-10-15 | 第 6 章 |
| BE31 | bcrypt 只应在 Argon2 与 scrypt 都不可用的遗留系统里用 | OWASP 同上 · bcrypt | 2026-10-15 | 第 6 章 |
| BE32 | 有相关标准与验证实现要求时,PBKDF2 应是首选 | OWASP 同上 · PBKDF2 | 2026-10-15 | 第 6 章 |
| BE33 | 应优先选同时抵抗 GPU 攻击与内存攻击的现代算法 | OWASP 同上 · Password Hashing Algorithms | 2026-10-15 | 第 6 章 |
| BE34 | 不需要隐藏应用用的是哪种口令哈希算法 | OWASP 同上 · Password Hashing Algorithms | 2026-10-15 | 第 6 章 |
| BE35 | 只有必须取得原始明文口令的边缘场合才加密存放 | OWASP 同上 · Hashing vs Encryption | 2026-10-15 | 第 5、6 章 |
| BE36 | 口令永远不应以明文存储 | OWASP 同上 · Introduction | 2026-10-15 | 第 6 章 |
| BE37 | 本机实测(Python 3.13.12):b64encode(b'foobar')得Zm9vYmFy;填充形态;urlsafe_b64encode对 0xFB、0xFF 得-_8= | 本机实测(python3 -c只读示例) | 2026-10-15 本机实测 | 第 3 章 |
| BE38 | 上述实测与 RFC 4648 §10 的四行测试向量逐条一致 | RFC 4648 §10 Test Vectors | 2026-10-15 | 第 3 章 |
附表 B:术语速查表
| 术语 | 一句话解释 | 易混点 |
|---|---|---|
| 编码 | 按公开规则换一种写法,不要密钥,任何人可还原 | 解决"传得过去",不解决"别人看不懂" |
| Base16(十六进制) | 每字节切成两个 4 位小组、查 16 字符表 | 不需要填充,一个码字总是够用 |
| Base32 | 每 5 位一组、查 32 字符表,填充比 base64 长 | 与 base64 一样只是换写法 |
| Base64 | 每 6 位一组、查 64 字符表,24 位进、4 字符出 | 第 65 个字符=只是填充 |
填充(=) | 补足最后一组不足的位用的字符 | 只说明"最后剩几个字节" |
| base64url | 把 base64 的第 62、63 个字符换成-与_ | 官方强调它不等于 “base64” |
| 摘要(哈希) | 单向函数,不提供还原成原文的路径 | 不是"特别难解的加密",方向不同 |
| 计算意义上的保密性 | 官方术语:让别人算不出来 | Base64 只做到"视觉上藏起来" |
| 盐(salt) | 每个口令配一段唯一的随机串,一起参与哈希 | 必须唯一;库会自动生成与管理 |
| 工作因子 | 每个口令跑多少轮哈希,一般存于哈希输出中 | 可随硬件调整,不是越大越好 |
| Argon2id | 备忘单列为新系统首选的口令哈希算法 | 只有它不可用时才退到 scrypt |
| scrypt | 口令哈希的次选算法 | 位置是"Argon2id 不可用时" |
| bcrypt | 只在遗留系统里用于口令存放的算法 | 位置比前两者窄 |
| PBKDF2 | 在有合规要求时首选的算法 | 位置由合规需求决定,不是第三档 |
写在最后:这篇用到的资料
写这篇文章时,我把"抓包里看到一串乱码"这件事重新拆了一遍,才发现要问的不是"这串是什么",而是"它属于编码、摘要还是加密"——问题换对了,后面的判断路径就短得多了。顺手也整理了几份配套的东西:
- 靶场环境对照表:DVWA、upload-labs 在 Windows / macOS / Linux 三平台的可行性与推荐路径
- Web 安全学习路线图:从基础打牢到安全管理,四个阶段各学什么
- 常用靶场清单:每个靶场练什么、适合哪个阶段
资料是我自己整理的,放在下面这个码上,扫码即可获取:
添加时备注「靶场」,优先通过。
拿到之后建议先看环境对照表那一份,它按"哪一层出问题、用哪一把尺子"整理,跟本文"先问是哪一类转换、再决定怎么判断"是一条线。