LUD-04: `auth` 基础规范

  • fiatjaf
  • 发布于 2022-08-12 17:54
  • 阅读 16

LUD-04 规范定义了使用比特币钱包进行身份验证的方法,通过LinkingKey实现用户登录和服务授权,在不泄露用户身份的前提下完成。服务端生成包含随机数据的LNURL-auth,钱包使用LinkingPrivKey对数据签名,服务端验证签名后即可验证用户身份。

LUD-04: auth 基础规范

作者: akumaigorodski


使用比特币钱包进行授权

一个特殊的 linkingKey 可以用来让用户登录服务或授权敏感操作。这最好在不泄露用户身份的情况下完成,所以不能使用普通的 LN 节点密钥。服务可以不要求用户提供凭据,而是显示一个包含特定 LNURL 的“登录”二维码。

服务端生成 auth URL 并验证签名:

当创建一个 LNURL-auth 处理程序时,LN SERVICE 必须在其中包含一个 k1 查询参数,该参数由随机生成的 32 字节的数据组成,以及可选的 action 枚举,例如 https://site.com?tag=login&k1=hex(32 bytes of random data)&action=login

稍后,一旦 LN SERVICE 在指定的 LNURL-auth 处理程序处收到调用,它必须获取 k1、压缩的(33 字节)secp256k1 公钥 key(编码为十六进制)和一个 DER 十六进制编码的 ECDSA sig,并使用 secp256k1 验证签名。一旦签名成功验证,用户提供的 key 就可以用作标识符,并可以存储在会话、数据库或 LN SERVICE 认为合适的任何位置。

LN SERVICE 必须确保不接受意外的 k1:强烈建议 LN SERVICE 拥有一个未使用的 k1 缓存,仅对该缓存中存在的 k1 进行验证,并在成功的身份验证尝试中删除已使用的 k1

服务端子域名的选择:

LN SERVICE 应仔细选择哪个子域名(如果有)将用作 LNURL-auth 端点,并在将来坚持使用所选的子域名。例如,如果最初选择了 auth.site.com,则将其更改为 login.site.com 将导致每个用户都有一个不同的帐户,因为钱包使用完整的域名作为密钥派生的材料。

考虑到 LN SERVICE 应该为选择的子域名提供有意义的名称,因为 LN WALLET 可能会在登录尝试时向用户显示完整的域名。例如,auth.site.comksf03.site.com 不容易引起混淆。

钱包与服务的交互流程:

  1. LN WALLET 扫描二维码并解码 URL,该 URL 预计具有以下查询参数:
    • tag 的值设置为 login,这意味着尚未执行 GET 请求。
    • k1(十六进制编码的 32 字节挑战),将由用户的 linkingPrivKey 签名。
    • 可选的 action 枚举,可以是以下四个字符串之一:register | login | link | auth
  2. LN WALLET 显示一个“登录”对话框,其中必须包含从 LNURL 查询字符串中提取的域名和 action 枚举(如果存在 action 查询参数,则将其翻译成人类可读的文本)。
  3. 一旦用户接受,LN WALLET 使用 linkingPrivKeysecp256k1 上签名 k1,并对签名进行 DER 编码。然后,LN WALLET 使用 <LNURL_hostname_and_path>?<LNURL_existing_query_parameters>&sig=<hex(sign(hexToBytes(k1), linkingPrivKey))>&key=<hex(linkingKey)>LN SERVICE 发出 GET 请求
  4. 客户端签名验证后,LN SERVICE 会以如下 JSON 格式响应:
    {"status": "OK"}

    或者

    {"status": "ERROR", "reason": "错误详情..."}

action 枚举的含义:

  • register:服务将创建一个新帐户,并将其链接到用户的 linkingKey
  • login:服务将使用户登录到与用户的 linkingKey 链接的现有帐户。
  • link:服务会将用户提供的 linkingKey 链接到用户的现有帐户(如果该帐户最初不是使用 lnurl-auth 创建的)。
  • auth:将授予一些不需要登录(甚至可能不需要事先注册)的无状态操作。

linkingKey 推导

LNURL-auth 的工作原理是从用户种子派生特定于域的 linkingKey。这种方法有两个目标:第一个是简单性(用户只需要保留助记词即可保存资金和身份),第二个是可移植性(用户应该能够通过输入相同的助记词来切换钱包并获得相同的身份)。

但是,实际上无法达到第二个目标,因为存在无法在所有现有钱包之间传输的不同种子格式。因此,一种实用的方法是推荐针对不同钱包类型派生 linkingKey 的方法。

签名检查示例

在 Python 中

from binascii import unhexlify
from secp256k1 import PublicKey

k1 = unhexlify('e2af6254a8df433264fa23f67eb8188635d15ce883e8fc020989d5f82ae6f11e')
key = unhexlify('02c3b844b8104f0c1b15c507774c9ba7fc609f58f343b9b149122e944dd20c9362')
sig = unhexlify('304402203767faf494f110b139293d9bab3c50e07b3bf33c463d4aa767256cd09132dc5102205821f8efacdb5c595b92ada255876d9201e126e2f31a140d44561cc1f7e9e43d')

pubkey = PublicKey(key, raw=True)
sig_raw = pubkey.ecdsa_deserialize(sig)
r = pubkey.ecdsa_verify(k1, sig_raw, raw=True)

assert r == True
  • 原文链接: github.com/fiatjaf/lnurl...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
fiatjaf
fiatjaf
江湖只有他的大名,没有他的介绍。