开始前,会这些就够了
- 会运行一小段 Python,认识字符串、列表和条件判断即可
遇到不熟悉的词,先看这 2 个解释
- 字符编码
- 字符编码是把文字与可存储的数据对应起来的规则。写入时按规则产生数据,读取时按相应规则还原文字;双方使用不同规则,就可能看到乱码或替代符号。
- 加密
- 加密用算法和密钥把原来的内容变成难以直接阅读的数据,让拥有相应解密条件的人能够恢复内容。它主要解决谁能读到信息的问题,密钥的保存同样重要。
搜索一个带空格和中文的词,网址里可能多出一串百分号;接口里的一小块数据,又可能变成一行大小写字母。看起来陌生,不代表变成了秘密。这些写法常常只是为了让数据顺利通过某种文本格式。
这篇只看两种可逆编码。我们用一段虚构文字当材料,不讨论旧文章里的哈希指纹,也不使用真实密码。判断是否保密的关键,是还原时需不需要秘密,而不是肉眼能不能一眼看懂。
百分号编码,先解决“标点到底属于谁”
在 URL 的查询部分,& 和 = 可以承担分隔作用。如果用户搜索的文字本来含有这些符号,直接拼上去就可能被当成结构。百分号编码把相应字节写成 % 加两位十六进制数,让文字与分隔符各司其职。
不是看到一个 URL 就把它从头编码到尾。主机、路径和参数有各自的位置和规则;实际构造查询参数通常交给 URL 库。空格在一些表单编码里会写成 +,真正的加号则另行编码,所以也不能把所有 + 一律替换为空格。
Base64 给二进制数据换一套文本写法
Base64 把字节分组,映射成一套有限的可打印字符,便于放进只适合处理文本的地方。它没有用秘密密钥,知道规则的人就能解回字节。标准 Base64 和 URL 安全变体的字符约定有所不同,双方仍需说好使用哪一种。
换成这套写法通常会更长,而非压缩。普通 Base64 每三个输入字节对应四个字符,不足一组时还可能有填充。因此“内容更长、更像乱码”既不能证明加密,也不能证明压缩失败:编码本来就服务于另一个目的。
同一句话,来回走两条路
示例包含真正的加号、空格、& 和中文“茶”。quote 的 safe 参数设为空,表示把这段文字作为独立值处理,而不是把它当作一个完整 URL。Base64 则先按 UTF-8 得到字节,再编码;还原后也按 UTF-8 读文字。
两次还原都不需要提供密码。最后两行再对照普通百分号解码和表单式解码处理 a+b 的差异。它们不是谁比较聪明,而是遵守不同约定;生产代码应使用与发送方一致的解码方法。
import base64
from urllib.parse import quote, unquote, unquote_plus
text = "A+B & 茶"
url_value = quote(text, safe="")
b64 = base64.b64encode(text.encode("utf-8")).decode("ascii")
print(url_value)
print(unquote(url_value) == text)
print(b64)
print(base64.b64decode(b64).decode("utf-8") == text)
print(unquote("a+b"))
print(unquote_plus("a+b"))怎样运行:保存为 encoding_demo.py,在一个自己的练习目录中运行 python encoding_demo.py。使用 Python 3.9 或更高版本,仅用标准库。
运行后对照结果
A%2BB%20%26%20%E8%8C%B6
True
QStCICYg6Iy2
True
a+b
a b不要把“可传输”当成“不可窥看”
给内部编号做 Base64,可能方便某个接口接收,但不会自动让编号难以猜测,更不会让服务端知道调用者有没有权限。服务端仍要按实际身份检查能否访问那条记录。把可逆的表示变化当作权限控制,会误解它能提供的作用。
同样,编码后的内容也没有因此变得可信。接收方还要按数据用途检查长度、类型和允许值。不要反复解码直到“看着正常”:一次解码后出现的百分号可能本来就是数据。每一层由谁编码、由谁解码,应该有明确约定。
记住这三点
- 百分号编码帮助区分 URL 数据和结构;Base64 帮助以文本表示字节。
- 两者都可按公开规则还原,没有提供保密性。
- 字符编码、URL 所在位置和 Base64 变体都需要双方约定。
别把例子用过头
- 不是所有 URL 位置都把 + 当空格。
- Base64 不是压缩,也不会赋予内容访问权限或可信性。
自己试一小步
为一个“搜索词”参数设计可还原的小实验。
- 准备只含虚构内容的输入,覆盖中文、空格、加号和百分号。
- 分别用 quote 与表单查询构造方式处理,记录每条路使用的解码器。
- 加入一个已经含有 %20 的普通字符串,检查是否发生了多解码一次。
做到这些,就算完成
- 每条路都能还原原始内容,而不只是外观相似。
- 明确哪些标点是参数结构、哪些是参数值。
- 解释为什么还原成功与保密无关,不用真实凭据做实验。
查原始资料
想确认一个细节,先看这份资料对应的部分,不必从头读完所有文档。
- Percent-encoding (新标签页)↗
支持百分号表示、保留字符与空格在不同上下文中的表示差异。
- RFC 4648:Base-N Encodings (新标签页)↗
支持 Base64 字母表、分组与填充;第 12 节说明这种编码不提供计算上的保密性。
- urllib.parse:URL quoting (新标签页)↗
支持 quote、unquote、
unquote_plus的调用约定与加号处理。
找一份资料继续练
先选一项,按下面的范围继续学;不必从头读完整门课程。
HTTPS 中文漫画:消息怎样安全地到达网站 (新标签页)↗
只读漫画第一集,为窃听、篡改和冒充各举一例,再对照本文判断公开的可逆编码能不能提供这些保护。
查看学习准备与访问说明 →