明文签名被认为有害

发布: (2025年12月28日 GMT+8 02:03)
6 min read

Source: Hacker News

请提供您希望翻译的正文内容,我将把它翻译成简体中文并保持原有的格式、Markdown 语法以及技术术语不变。谢谢!

PGP 中的明文签名 – 陷阱与验证

自 1990 年代初的首个 PGP 版本起,PGP(以及所有基于它的实现)就支持一种称为 明文签名(cleartext signature)的功能。你今天仍然会遇到此类签名。下面是一个明文签名消息的示例:

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

Far out in the uncharted backwaters of the unfashionable  end  of
the  western  spiral  arm  of  the Galaxy lies a small unregarded
yellow sun.
-----BEGIN PGP SIGNATURE-----

iJEEARYKADkWIQSHd0YfKgdOvEgNNZQZzByeCFsQegUCaU5mGhsUgAAAAAAEAA5t
YW51MiwyLjUrMS4xMSwyLDIACgkQGcwcnghbEHq27gEAqE+Cw1FmIlDXyzc1+5K8
3e60/3TjpqpFmkmuot8ZROMBAIrQXMhfN3gr7jdsxLuV1L7+IzHSRyUMlelZSnAs
k+AL
=kCuN
-----END PGP SIGNATURE-----

为什么明文签名可能会产生误导

  • 已签名的文本是直接可读的,但 要正确验证它需要使用 PGP 工具。仅仅查看终端输出 不足够,原因如下:
    • 以短横线 (-) 开头或以字符串 From 开头的行会被转义。
    • 许多终端模拟器会解释转义码(例如颜色或光标移动序列),从而改变你看到的内容。
  • 确认实际签名内容的唯一可靠方法是让 PGP 实现处理整条消息,并输出 规范(canonical)的签名文本。

使用 GnuPG 验证明文签名消息

# 使用 gpg(打印状态并将已签名文本写入 signed.txt)
gpg --verify -o signed.txt message.asc

# 使用 gpgv(用于脚本;仅信任 trustedkeys.* 中的密钥)
gpgv -o signed.txt message.asc

典型输出:

gpg: Signature made Fri 26 Dec 2025 11:40:26 AM CET
gpg:                using EDDSA key 8777461F2A074EBC480D359419CC1C9E085B107A
gpg: Good signature from "wk@gnupg.org" [ultimate]
...

如果诊断信息显示来自你信任的密钥的良好签名,则可以安全使用 signed.txt 的内容。
当多个密钥验证同一条消息时,它们签署的文本是完全相同的。

注意: gpgv 在自动化脚本中更为可取,因为它只接受 trustedkeys.gpg(或 trustedkeys.kbx)中列出的密钥所做的签名。gpg--assert-signer 选项也可以作为替代方案。

推荐做法:使用分离签名(或 PGP/MIME)

明文签名易于阅读,但很难做到完全正确。关键在于 必须准确知道到底验证了什么。对于新消息,你应当:

  • 优先使用分离签名

    # 验证分离签名
    gpg --verify message.sig message.txt
    gpgv message.sig message.txt

    (此处 不要 使用 -o/--output 选项;那会创建一个空文件。)

  • 或者,在电子邮件中使用 PGP/MIME(这是签名或加密邮件的现代标准格式)。

历史背景

在 1990 年代初,互联网尚未普及;大多数通信仍在拨号 BBS 上进行。Phil Zimmermann 设计 PGP 的初衷是让用户即使在收件人尚未安装 PGP 的情况下,也能交换 ASCII 编码的消息。

电子邮件很快取代了 BBS,但 MIME 的普及花了一段时间。1996 年,Michael Elkins 为 Mutt 邮件客户端引入了 PGP/MIME(RFC 2015),逐步取代了明文签名和明文加密的邮件。如今,PGP/MIME 已成为签名/加密消息的事实标准,尽管仍有少数客户端保留了旧的明文格式。

为什么明文签名不安全

  • 装甲行篡改——-----BEGIN PGP … 头部可以通过使用更少的短横线或外观相似的 Unicode 字符来伪造,导致用户误以为签名文本比实际更早开始。

  • 注释行——用户往往不知道注释行(例如 Hash:)并不是签名文本的一部分。添加额外的注释行会注入未签名的内容。

  • 空行技巧——分隔装甲头部与签名文本的空行可以被终端控制或 Unicode 字符替换,从而影响实际签名范围。

  • TF‑8 字符,误导观看者。

  • 过长的行 – 可能导致显示或解析异常。

这些以及过去 30 年中展示的许多其他变体,促使 PGP/MIME 被广泛采用。

Bottom line

避免对新数据使用明文签名。请改用分离签名或 PGP/MIME,并且永远不要假设屏幕上看到的文本就是被签名的内容。

Back to Blog

相关文章

阅读更多 »

理解 ECDSA

本文基本上是一个从零开始理解 ECDSA(Elliptic Curve Digital Signature Algorithm)的练习。我只假设一些基础数学和一个意愿……