为何 BT 协议中要用%nn 对 16 进制字符串的 info_hash 或者 peer_id 进行编码?

251 天前
 xlsepiphone

Note that all binary data in the URL (particularly info_hash and peer_id) must be properly escaped. This means any byte not in the set 0-9, a-z, A-Z, '.', '-', '_' and '~', must be encoded using the "%nn" format, where nn is the hexadecimal value of the byte. (See RFC1738 for details.)

For a 20-byte hash of \x12\x34\x56\x78\x9a\xbc\xde\xf1\x23\x45\x67\x89\xab\xcd\xef\x12\x34\x56\x78\x9a, The right encoded form is %124Vx%9A%BC%DE%F1%23Eg%89%AB%CD%EF%124Vx%9A

-[摘自 BT 协议]

按照协议的逻辑,

对于 \x12\x34\x56\x78\x9a\xbc\xde\xf1\x23\x45\x67\x89\xab\xcd\xef\x12\x34\x56\x78\x9a 这个 info_hash,每个字节的 10 进制数字如果小于等于 127 的(ascii 范围内),都先转换成 ascii 字符,然后用 encodeURIComponent 进行了编码,大于 127 的可以直接用%加 16 进制字符串表示,比如%ff

例如开头的字节 0x12,换算成 10 进制,等于 18 ,查 ascii 码表,18 对应的是 DC2(device control 2),不是一个可见字符,用 encodeURIComponent 编码后返回%12 。

又比如 0x34 ,换算成 10 进制,等于 52 ,查 ascii 码表,对应的是字符"4"。

所以头两个字节经过转换后变成了 %124

我的问题是,16 进制的字符表达在 URL 作为参数中应该是完全安全的

16 进制也就是 0-9 以及 a-f,两个字符代表一个字节,例如上面的 16 进制字符串完全可以表示为:123456789abcdef123456789abcdef123456789a ,作为 URL 的查询参数传输也不会存在安全问题才对。

这是因为历史原因约定俗成导致的,还是因为其他原因呢?

660 次点击
所在节点    问与答
7 条回复
NoOneNoBody
251 天前
不写着 RFC1738 么?
xlsepiphone
251 天前
@NoOneNoBody #1 我看了,我就是没找到答案,0-9a-f 的字符里面没有包含任何特殊字符。
xlsepiphone
251 天前
@xlsepiphone #2 例如

https://torrent.ubuntu.com/announce?info_hash=75439d5de343999ab377c617c2c647902956e282

这个 url 貌似不存在安全问题。所以我才想知道,编码是因为约定俗成的历史原因,还是因为其他问题。
victimsss
251 天前
The tracker is an HTTP/HTTPS service which responds to HTTP GET requests. The requests include metrics from clients that help the tracker keep overall statistics about the torrent. The response includes a peer list that helps the client participate in the torrent. The base URL consists of the "announce URL" as defined in the metainfo (.torrent) file. The parameters are then added to this URL, using standard CGI methods (i.e. a '?' after the announce URL, followed by 'param=value' sequences separated by '&').

这不是写着吗, 这是 一个 http/https 服务, 你说的是 URI 的编码规划,至于为啥要用 encodeURI 和 decodeURI ,谷歌一下就知道了。
StoneHuLu
251 天前
问了下 gpt4 ,感觉就是根据 RFC1738 做的一种防范式操作,解决的就是“貌似不存在安全问题”的“貌似、可能”。

gtp4:
为什么 bt 协议中要用%nn 对 16 进制字符串的 info_hash 或者 peer_id 进行编码?

在 BT 协议中,info_hash 和 peer_id 都是二进制的数据,直接在 URL 中传递可能会造成各种问题。例如,有些二进制字符可能无法在 URL 中正确传递,或者可能与 URL 的其它部分混淆。另外,有些二进制字符可能对 HTTP 服务器或客户端构成安全风险。

通过将这些二进制数据编码为%nn 形式的 16 进制字符串,可以避免这些问题。这种编码方式称为 URL 编码或百分比编码,它可以将任意的数据编码为只包含 ASCII 字符的字符串,从而可以安全地在 URL 中传递。

在这种编码中,每个非 ASCII 字符都被替换为%后跟两个表示该字符 ASCII 代码的 16 进制数字。例如,空格字符的 ASCII 代码是 32 (或 20H ),在 URL 编码中它被替换为%20 。

据说是根据 RFC1738 ?

是的,该编码方式是根据 RFC1738 中定义的 URL 编码规则(也被称为百分比编码)来执行的。根据 RFC1738 ,非字母数字字符需要通过十六进制的形式进行编码,形式为%nn ,其中 nn 为该字符的 ASCII 码的十六进制形式。

BT 协议中的 info_hash 和 peer_id 通常包含非字母数字字符,直接在 URL 中使用可能会引起问题,所以需要进行编码。这样做的目的是为了确保这些信息能够在 HTTP 请求(如 GET 或 POST )中安全可靠地传递。

RFC1738 是 Internet 工程任务组( IETF )发布的一份官方文档,定义了 URL 的标准格式以及各个部分的具体含义和编码方式,BT 协议的设计者遵循这个标准以确保协议的兼容性和稳定性。
xlsepiphone
251 天前
@victimsss #4 我知道是 http/https 服务,因为客户端要像 tracker 请求 peer 列表,我的意思是,hex 字符串没有必要进行编码,因为它天然就是 url 安全的,所以我的问题是想知道为什么 BT 协议要这么规定。
xlsepiphone
251 天前
@StoneHuLu #5 在 bt 协议里面,torrent 文件的元信息中,info_hash 是一个 bencode 编码的字节字符串,有些字节是不可见的,也就是不能用 ascii 码显示,从某一个角度想,也许作者是想直接从 byte string (字节字符串)编码到%nn ,根本就没有考虑过把 20 字节的 info_hash 直接转换成 16 进制表示。

这也只是我个人的猜测了。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/970824

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX