V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
xlsepiphone
V2EX  ›  问与答

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

  •  
  •   xlsepiphone · 237 天前 · 652 次点击
    这是一个创建于 237 天前的主题,其中的信息可能已经有所发展或是发生改变。

    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 的查询参数传输也不会存在安全问题才对。

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

    第 1 条附言  ·  237 天前
    找到一个 stackoverflow 的回答,看来是 BT 协议的问题了。。。也就是为时已晚。。

    https://stackoverflow.com/questions/4072234/bittorrent-tracker-request-format-of-info-hash

    Q:When I want to send an initial request to a tracker all references I've seen says it needs to be url-encoded. If I transform the SHA-1 hash I have of the info key into a hex string, why would I need to url-encode the hash? It only contains allowed characters.

    A:The info_hash parameter is not a hex string. It's a pure binary string, so yes, you will have to URL-encode many of the bytes in it. (This tends to make it longer in the end than just using a hex-encoded string, but that's the BitTorrent protocol for you, too late to do anything about it now!)
    7 条回复    2023-09-04 17:48:35 +08:00
    NoOneNoBody
        1
    NoOneNoBody  
       237 天前
    不写着 RFC1738 么?
    xlsepiphone
        2
    xlsepiphone  
    OP
       237 天前
    @NoOneNoBody #1 我看了,我就是没找到答案,0-9a-f 的字符里面没有包含任何特殊字符。
    xlsepiphone
        3
    xlsepiphone  
    OP
       237 天前
    @xlsepiphone #2 例如

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

    这个 url 貌似不存在安全问题。所以我才想知道,编码是因为约定俗成的历史原因,还是因为其他问题。
    victimsss
        4
    victimsss  
       237 天前
    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
        5
    StoneHuLu  
       237 天前
    问了下 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
        6
    xlsepiphone  
    OP
       237 天前
    @victimsss #4 我知道是 http/https 服务,因为客户端要像 tracker 请求 peer 列表,我的意思是,hex 字符串没有必要进行编码,因为它天然就是 url 安全的,所以我的问题是想知道为什么 BT 协议要这么规定。
    xlsepiphone
        7
    xlsepiphone  
    OP
       237 天前
    @StoneHuLu #5 在 bt 协议里面,torrent 文件的元信息中,info_hash 是一个 bencode 编码的字节字符串,有些字节是不可见的,也就是不能用 ascii 码显示,从某一个角度想,也许作者是想直接从 byte string (字节字符串)编码到%nn ,根本就没有考虑过把 20 字节的 info_hash 直接转换成 16 进制表示。

    这也只是我个人的猜测了。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3217 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 12:13 · PVG 20:13 · LAX 05:13 · JFK 08:13
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.