ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Agent 时代身份验证新思路:用 Username.md 构建可验证的 AI 信任链

Agent 时代身份验证新思路:用 Username.md 构建可验证的 AI 信任链 如果说大模型把“对话能力”普及到了每一个开发者那么接下来真正改变工作流的是 Agent 开始替我们做事。但面对 Agent 的爆发有一个基础设施一直被低估身份。当你教一个 Agent 去“联系 Alice”“校验 Bob 发的配置”“确认某个维护者是否值得信任”时它第一步要做的事情是什么是判断面前这段文本到底是谁写的。人类可以看头像、看历史、看说话风格Agent 不行它需要一种可以程序化验证的信任链路。传统互联网身份体系是围绕“登录”设计的密码、验证码、OAuth 跳转、会话 Cookie每一步都是为了证明“当前操作者是谁”。但 Agent 的工作方式不太一样它更接近“读者”和“执行者”的叠加态它要一边读你发布的身份信息一边确认这些信息没有被中途篡改一边决定要不要进一步操作。于是有人提出了一个很朴素的方案Username.md——一个经过签名的、Agent 可读的、由你自己拥有的身份页面。这个想法并不是要给整个 Web 重新发明一套身份协议而是用已经成熟的 Markdown PGP 签名 自有域名组合起来解决一个非常具体的问题Agent 拿到你的身份页时如何确信页面里的内容真的出自你手。这篇文章会拆解它的设计思路把它和主流的身份方案放在一起对比然后从密钥生成、页面编写、签名发布到验证脚本完整走一遍实战流程。1. 这篇文章真正要解决的问题AI Agent 的验证困境先看几个真实场景。第一个场景是多 Agent 协作。假设你的 Agent 需要从同事的站点上读取一份 API 接入说明而这份说明是同事的 Agent 自动生成的。双方都是机器没有浏览器、没有验证码、没有人工审核。你的 Agent 拿到内容后要先问一个问题这份说明真的来自同事本人吗会不会是中间环节被替换的在没有额外验证手段的情况下Agent 只能选择相信或不相信而“盲目相信”在生产环境里是灾难。第二个场景是开源身份。开源维护者通常会把自己的 GitHub 主页当作身份入口但 GitHub 主页本质上是一个平台托管的页面。平台可以限制账号、可以关停服务、可以改版。如果你的 Agent 依赖某个维护者的 GitHub 页面来获取公钥和联系方式平台侧的任何一个变化都会破坏这条信任链。对 Agent 来说它更希望看到一个不依赖平台、可以长期稳定访问的固定端点。第三个场景是自动接入。过去一个人要建立一份“个人资料”是给 HR 或合作方看的现在这份资料还要给 Agent 看。Agent 需要解析你的名字、你的公开邮箱、你的公钥指纹、你的社交链接。它甚至需要知道“该信任哪一份资料、哪个公钥”。如果这些信息散落在社交主页、博客、简历、登记表里Agent 每次都要靠网页抓取和语义理解来猜效率低还容易出错。这三个场景指向同一个结论Agent 时代对身份验证的需求和人类时代有本质区别。人类验证身份靠交互Agent 验证身份靠密码学。你需要证明的不是“我能在浏览器里登录”而是“这段内容由一个我信任的私钥持有者签名并且内容自发布后没有被修改过”。这就是 Username.md 这类方案要补上的空白。所以这篇文章真正要解决的问题一句话概括如何用最低成本为自己搭建一个 Agent 可以直接读取、又能用密码学方法验证的本人身份页。2. Username.md 是什么一个“签名 可读 自有”的身份页从项目名拆开看Username.md 包含三层设计Username 表示它代表一个用户身份标识.md 表示内容格式是 Markdown而项目标题里的三个定语才是它的技术核心。2.1 signed签名解决的是内容可信问题“signed”意味着身份页不是一封来自服务器的纯文本而是由你本地私钥签名过的数据。签名解决两个问题。第一是内容完整性。身份页发布后只要任何一个字节被改动签名验证就会失败。第二是来源确定性。只要私钥没有泄露能够验证通过的内容就可以确定为私钥持有者所发布。这里要和“加密”做一个区分。加密是为了防止别人看到内容签名是为了让别人确认内容来源可信两者使用私钥的方式不同。身份页通常是公开信息不需要加密但必须有签名。用生活化的比喻来说签名相当于“数字公证”文件摆在那里谁都能看但封条上的签章只有你才有。2.2 agent-readable让 AI 能以最低成本读懂身份信息Agent 读取网页和人类不同。人类可以理解复杂排版、图标、图片中的含义Agent 如果要稳定解析更希望看到结构化程度高、噪声少的文本。纯 Markdown 就是一个非常合适的选择。一方面Markdown 比 HTML 轻量得多没有 script、style、div 嵌套等无关内容另一方面Markdown 本身有标题、列表、链接的语义Agent 可以很容易识别出“这个段落是身份声明”“这一行是联系方式”“那个链接是社交主页”。如果身份页是动态渲染的 SPA 页面Agent 还需要执行 JavaScript 才能拿到真正内容这会让解析成本大幅上升。所以“agent-readable”不只是一个格式偏好更是一个工程决策。固定 URL 纯静态 Markdown 独立签名文件意味着 Agent 可以用三行命令完成抓取、验证、解析的全部流程。2.3 you own身份数据不随平台迁移而消失“you own”是这套设计里容易被低估的部分。它的含义是身份页处于你控制的域名之下签名私钥也由你保管。平台可以关停你的账号搜索引擎可以调整收录策略但只要你还有域名和私钥你的身份声明就依然存在。从更深一层看这其实是把“身份数据”和“平台账号”解耦。现在很多人的数字身份绑定在微博、GitHub、微信等平台上平台注销账号等于注销了身份。而 Username.md 式的设计让身份页本身成为一种可以迁移、可以备份、可以长期持有的资产。当然这里要澄清一个边界域名和私钥属于你不等于“这个身份对应的现实实体”自动被验证。域名和私钥只能证明内容来源稳定不能证明现实世界的你叫什么名字、在哪个公司工作。身份和实体之间的连接通常还需要其他可信凭证来背书。这个边界在后面章节会展开。3. 传统身份方案在 Agent 场景下的短板把 Username.md 和几种主流身份标识放在一起对比能更清楚地看出它的定位。方案身份归属机器可读性签名验证长期可用性适合 Agent 吗GitHub / 社交主页平台一般无受平台限制较弱个人博客 about 页自己差无强一般OAuth / OIDC身份提供商强协议自带强适合登录鉴权不适合内容信任VCard / JSON-LD自己强无强适合结构化数据无防篡改PGP Web of Trust自己弱强强需要额外基础设施Username.md自己较强强强比较契合细看几个代表方案。OAuth / OIDC 是很成熟的身份协议但它的设计目标是“授权”和“登录”流程中有重定向、会话、Token 交换。Agent 如果只是想读一个公开身份页用 OAuth 显然是杀鸡用牛刀。而且 OAuth 依赖身份提供商如果 Agent 要对接多个方就需要处理多个提供商的协议差异。JSON-LD 和 VCard 在机器可读性上很强结构非常规整但它们通常不包含签名机制。Agent 能解析出“这个节点代表邮箱”并不意味着“这个邮箱是我声明的那个邮箱”。缺少签名内容可信度就得不到保障。PGP 的 Web of Trust 设计目标是解决公钥信任链签名能力很强但整体体系复杂普通 Agent 很难直接消费。Username.md 没有重新发明一套公钥基础设施而是把 PGP 的签名能力直接嵌入到一个 URL 里让消费方只需要做一次gpg --verify。从材料看Username.md 的定位更像是“轻量级个人身份端点”它在机器可读性和密码学可验证性之间取了平衡同时保留了部署的简单性。它解决的核心矛盾是一些方案太复杂一些方案又太不可信而开发者需要一个刚刚好的中间点。4. 环境准备与前置条件搭建 Username.md 式的身份页不需要很重的环境用到的都是比较通用的工具和协议。下面是建议的准备工作。操作系统Linux 或 macOS 最方便Windows 用户建议使用 WSL 或 Git Bash避免 GPG 路径和命令差异带来的问题。GnuPG用于生成密钥、签名、验证。通常系统自带也可以用gpg --version确认版本以实际环境为准本文演示的是通用命令。域名或静态托管自建用户名身份页最好放在自己控制的域名下。没有域名时用 GitHub Pages、Cloudflare Pages、Vercel 等静态托管也能先用起来但自主性会弱一些。Markdown 编辑器任何文本编辑器都可以建议用 VS Code 或 Typora方便预览。Python 3用于编写自动化验证脚本如果不想写脚本也可以直接用 curl 加 gpg 命令手动验证。git用来管理身份页内容和签名历史方便回溯每次变更。环境准备阶段不需要安装任何重量级框架。整套方案的依赖非常轻这也是它适合个人开发者快速落地的原因。5. 核心流程拆解从密钥生成到签名发布整个流程可以拆成五步生成密钥、编写身份页、生成签名、发布内容、验证结果。每一步都有对应的命令和注意事项。5.1 生成 GPG 密钥对身份页的签名能力来自一个你自己保管的 GPG 密钥对。如果之前已经有 GPG 密钥可以直接复用如果没有需要先生成一个新的。gpg --full-generate-key交互式界面会要求选择密钥算法、密钥长度、有效期、用户 ID 等。对于身份页场景选择 RSA 4096 位是比较稳妥的默认值有效期可以根据自己的维护习惯设定比如三年或五年。用户 ID 建议使用真实姓名和常用邮箱因为这个信息会被 Agent 展示给其他调用方。生成完成后查看密钥列表和指纹gpg --list-secret-keys --keyid-format LONG gpg --fingerprint KEY_ID指纹是密钥的一个全局唯一标识也是你后续要在身份页里公开给 Agent 的值。注意私钥必须保存在本机并且设置密码保护它不应该被上传到服务器、仓库或任何第三方平台。5.2 编写身份页内容身份页是一个 Markdown 文件建议命名为username.md放在网站的固定路径下。虽然叫 username但里面的内容不只是一个用户名而是完整的身份声明。推荐包含这些字段显示名称、个人网站、公开邮箱、PGP 公钥指纹、社交账号、个人偏好等。一个需要注意的设计点是身份页的内容要尽量稳定。Agent 可能会缓存它也可能在多次请求之间做比对。如果你频繁改动内容一方面会让签名难以追溯另一方面也可能影响 Agent 对身份的信任判定。建议把身份页当作一个“版本化”的资产来维护而不是一个普通的博客页面。5.3 生成签名文件身份页写好之后对文件做一次分离签名gpg --detach-sign --armor username.md执行后会在同目录生成username.md.asc这个文件就是签名。所谓“分离签名”是指签名独立存放在另一个文件中原始 Markdown 文件保持纯净。为什么要用分离签名而不是把签名嵌入到 Markdown 里核心原因是 Agent 读取的 URL 应当是纯 Markdown这样 Agent 不需要解析 PGP 包裹格式就能直接读取正文。如果使用gpg --clearsign生成内联签名虽然签名和内容在一个文件里更方便人工下载但 Agent 必须先剥离文件头尾的签名块才能拿到正文增加了解析成本。所以对agent-readable的要求来说分离签名是更优选择。验证分离签名时gpg 会要求同时提供签名文件和被签名的数据文件gpg --verify username.md.asc username.md当输出包含Good signature时说明内容确实由对应私钥持有者签名且内容未被篡改。5.4 发布到自己的域名把username.md和username.md.asc一起发布到你的网站根目录或者某个固定路径比如https://yourdomain.com/username.md。如果使用 GitHub Pages操作很简单把两个文件提交到仓库开启 Pages 服务即可。如果使用自有服务器则把文件放到 Web 服务的静态目录下。以 nginx 为例只需要保证两个文件能被直接访问不经过任何动态处理。这里有一个容易踩坑的地方有些 Web 框架或 CDN 会对.md文件做额外处理比如转成 HTML、添加渲染模板。但对 Agent 来说我们需要的是原始 Markdown 文本而不是 HTML 渲染结果。因此发布时务必确认访问https://yourdomain.com/username.md返回的是原始文本而不是页面源码。可以使用curl -s https://yourdomain.com/username.md检查响应内容。5.5 在 Agent 或脚本中完成验证发布完成后消费方可以按下面三步来验证页面用固定 URL 下载身份页和签名文件。用公钥验证签名。签名通过后解析 Markdown 内容并用于后续业务。如果消费方是你的自定义 Agent可以把公钥指纹预先配置在 Agent 的信任名单中。首次信任可以由人工确认一次后续验证都基于这个已信任的指纹。这个流程和首次使用 SSH 时的 “known_hosts” 机制非常相似。6. 完整示例与代码实现下面给出一个可以直接复制的完整示例。假设你的域名是https://alice.example身份页文件名为username.md。6.1 身份页 Markdown 示例文件路径username.md# username: alice - display_name: Alice Zhang - website: https://alice.example - email: aliceexample.com - pgp_fingerprint: ABCD EF12 3456 7890 ABCD EF12 3456 7890 ABCD EF12 ## identity 本站点用于声明 Alice Zhang 在互联网上的身份信息以及对应的 PGP 公钥指纹。 所有内容通过 PGP 签名验证签名即可确认页面内容未被篡改。 ## contact - email: aliceexample.com - github: https://github.com/alice - blog: https://alice.example/blog ## preferences - preferred_chat: matrix - timezone: Asia/Shanghai - language: zh-CN这个文件的优点在于人类直接打开可以看到完整身份信息Agent 按 Markdown 语法解析可以稳定提取display_name、email、pgp_fingerprint等字段。使用- key: value这种列表形式比纯叙事段落更容易被解析。6.2 签名与发布命令进入username.md所在目录执行分离签名cd ~/identity-page gpg --detach-sign --armor username.md生成username.md.asc后把两个文件提交到发布目录。如果是 git 管理的静态站点可以执行git add username.md username.md.asc git commit -m update identity page and signature git push origin main如果使用 nginx 部署把文件放到设置的静态目录中就可以了。为了控制 Agent 的缓存行为可以加一段简单的响应头配置location /username.md { add_header Cache-Control public, max-age3600, must-revalidate; } location /username.md.asc { add_header Cache-Control public, max-age3600, must-revalidate; }这里设置的是 1 小时缓存must-revalidate保证内容更新后Agent 可以通过重新验证签名拿到最新状态避免因为旧缓存而信任过期内容。6.3 Python 验证脚本当 Agent 消费身份页时可以把验证逻辑封装成一个 Python 脚本。下面脚本从指定 URL 下载身份页和签名然后调用本机 gpg 命令完成验证。#!/usr/bin/env python3 import os import sys import tempfile import subprocess import urllib.request BASE_URL https://alice.example CONTENT_PATH /username.md SIGNATURE_PATH /username.md.asc def download(url: str) - bytes: with urllib.request.urlopen(url, timeout10) as resp: return resp.read() def main() - None: with tempfile.TemporaryDirectory() as tmp: content_file os.path.join(tmp, username.md) sig_file os.path.join(tmp, username.md.asc) with open(content_file, wb) as f: f.write(download(BASE_URL CONTENT_PATH)) with open(sig_file, wb) as f: f.write(download(BASE_URL SIGNATURE_PATH)) result subprocess.run( [gpg, --verify, sig_file, content_file], capture_outputTrue, textTrue, ) print(result.stdout or result.stderr, end) if result.returncode 0: print([OK] signature verified: content has not been tampered with) else: print([FAIL] signature verification failed) sys.exit(1) if __name__ __main__: main()脚本逻辑很直接下载两个文件调用gpg --verify做验证再根据返回码输出结果。执行方式python3 verify_identity.py将这个脚本作为 Agent 工具链的一部分可以在 Agent 使用身份页内容之前先跑一次验证保证读到的是可信内容。7. 运行结果与效果验证执行上面的 Python 脚本如果一切正常输出会和下面类似gpg: Signature made Mon DD HH:MM:SS YYYY CST gpg: using RSA key ABCD EF12 3456 7890 ABCD EF12 3456 7890 ABCD EF12 gpg: Good signature from Alice Zhang aliceexample.com [OK] signature verified: content has not been tampered with验证成功的标准是命令行输出包含Good signature。脚本返回码为 0。页面里的pgp_fingerprint和本地验证密钥的指纹一致。如果验证失败第一步判断信号是gpg的具体报错输出Cant check signature: No public key说明本机没有导入对应的公钥需要先从页面或信任节点获取公钥。输出BAD signature说明内容被篡改过或者签名文件和内容文件不匹配。输出Good signature但提示日期不受信任说明签名时间距离当前时间过远或者密钥有效期已过。在接入 Agent 之前建议先手动验证一次确认 URL 路径、签名文件和公钥指纹这三个环节都是通的。手动验证跑通后再把验证逻辑接入 Agent 的调用链这样可以减少排错时的不确定因素。8. 常见问题与排查思路问题现象可能原因排查方式解决方案验证时报No public key本机没有导入身份页对应的公钥执行gpg --list-keys查看本地公钥列表导入发布者的公钥后再验证验证报BAD signature内容被修改或签名文件与内容不配对对比两端文件哈希确认 URL 对应关系重新生成签名并发布Good signature但指纹不一致页面声明的指纹与密钥实际指纹不一致执行gpg --fingerprint比对更新页面信息或更换密钥Agent 解析不到正文访问 URL 返回了 HTML 渲染页而不是原始 Markdowncurl -s URL直接查看响应文本关闭服务端的渲染转换或改用专门的静态文件路径签名时间过旧内容发布后没有再签名查看签名时间戳更新内容后重新签名页面访问 404文件路径或文件名不对用浏览器访问 URL检查静态目录修正发布路径确认文件名大小写密钥疑似泄露私钥文件可能被外部访问检查私钥备份情况和密钥生成记录立即吊销密钥生成新密钥并更新所有页面排错的总原则是先从最容易验证的环节开始。先确认 URL 能访问再确认公钥已导入最后观察gpg --verify的输出。这三个环节任何一个不通后面都谈不上信任。9. 最佳实践与工程建议把 Username.md 这类身份页真正用起来有几点工程层面的建议值得记住。第一固定路径比固定内容更重要。身份页 URL 一旦公开尽量不要频繁变更。Agent 会把 URL 当作身份标识的一部分记住如果你今天放在/username.md明天改成/about.md旧引用的验证链路就会全部失效。更稳妥的做法是确保旧 URL 能在相当长的时间内保持可访问即使页面内容更新路径也不变。第二私钥是身份的核心资产。私钥一旦泄露别人就能伪造你的所有身份页。建议私钥设置高强度密码并做离线备份。不要把私钥放进 git 仓库不要上传到服务器不要放在公开的 CI 配置中。签名操作只在本地完成服务器上只放公钥和已签名的文件。第三定期轮换密钥并保持旧密钥可验证一段时间。密钥到期后不要直接删除旧公钥。代理节点可能还保存在旧密钥的缓存突然失效会导致验证报错。更好的做法是新密钥发布后保留旧公钥一个过渡期同时在身份页里注明新旧密钥的替换关系。第四内容更新和签名更新要保持原子性。每次更新username.md后必须立刻重新生成签名文件并且成对发布。如果只更新内容不更新签名所有 Agent 都会验证失败。发布前可以用脚本自动检查“文件变更时间是否晚于签名时间”或者直接做成一个发布脚本把“重新生成签名”固定在提交流程里。第五用 git 管理身份页的历史版本。身份页是长期资产每次修改都应有记录。建议每个版本都有对应的签名这样在纠纷发生时你可以拿出历史版本证明“某段时间内的身份声明是什么”。第六不要过度依赖单一信任节点。即使你的域名、私钥都在自己手里DNS 被劫持或域名过期仍然会影响身份页访问。建议在身份页上同时公布多个可验证信息比如公钥指纹、邮箱的 WKD 记录、社交账号上的公钥公告让 Agent 有多个交叉验证的入口。第七对 Agent 消费方来说首次信任建立是关键。第一次验证某个人的身份页时公钥指纹的来源需要人工确认。确认之后建议把指纹写入 Agent 的配置或数据库中后续的验证都以这个已确认的指纹为准而不是每次从页面读取指纹。10. 总结与后续学习方向Username.md 这个项目之所以值得关注是因为它没有引入任何复杂的协议只是把三个已经成熟的能力组合了起来Markdown 作为机器可读的格式GPG 签名作为密码学验证手段自有域名作为数据控制权边界。对一个 Agent 开发者来说这套组合意味着你可以用最低成本为你的 Agent 建立可验证的身份信任链路。从更长远的视角看Agent 时代会需要更多类似的基础设施。当前这套方案仍然有一些待完善的地方比如公钥的首次信任如何自动化、多密钥轮换的标准流程是什么、身份页是否可以声明可授权的 Agent 能力边界、是否需要一个轻量的键值发现协议来帮助 Agent 定位身份页路径。这些都是值得继续深入的方向。对你来说现在最值得做的实验不是继续收集更多 Agent 框架或提示词技巧而是先把自己的身份页搭起来。用域名、GPG 密钥和一个 Markdown 文件把“我是谁、我的公钥是什么、我的联系方式是什么”以可验证的方式发布出去。等 Agent 真正开始跨系统协作时你会在第一步就理解信任不是靠协议名称堆出来的而是靠签名的每一次成功验证建立起来的。
返回列表