EIP 4361 和 JWT 验证 以及 RSA 算法
EIP-4361
EIP-4361,全称"使用以太坊登录"(Sign-In with Ethereum,简称 SIWE),是一种让用户使用以太坊账户安全登录传统(链下)网站的技术标准。
简单来说,它的目标是用web3的"连接钱包+签名"来取代传统的"输入邮箱/用户名+密码"的登录方式。
它的核心价值主要体现在两个方面:
- 提升用户主权:你不再需要将身份交给Google或Facebook等中心化身份提供商,而是完全由自己通过私钥控制数字身份。
- 标准化与安全性:定义了一套通用的消息格式,钱包(如MetaMask)能够识别这是登录请求,从而提供更清晰的签名界面。同时通过"域名绑定"和"随机数(Nonce)"等机制,有效防止钓鱼和重放攻击。
一张典型的登录消息长什么样?
当你点击"登录"后,钱包弹出的签名请求本质上是一条结构化的文本。标准规定了它必须包含哪些信息,一个典型的例子如下:
text
example.com wants you to sign in with your Ethereum account:
0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
I accept the ExampleOrg Terms of Service: https://example.com/tos
URI: https://example.com/login
Version: 1
Chain ID: 1
Nonce: 32891756
Issued At: 2021-09-30T16:25:24Z
我们来解读一下其中的关键字段:
- 域名 (domain) :必须。发起请求的网站域名,用于防止钓鱼攻击。
- 地址 (address) :必须。你用来登录的以太坊地址,通常采用EIP-55的校验和格式。
- 声明 (statement):可选。一段人类可读的文本,通常用于展示服务条款等用户需要同意的信息。
- URI (uri) :必须。你正在访问的具体资源地址。
- 链ID (chain-id) :必须。以太坊的链ID(主网为1),用于绑定本次会话所在的网络,防止在其他链上被重放。
- 随机数 (nonce) :必须。一个至少8位的随机字符串,由网站生成,用于防止重复攻击。
- 签发时间 (issued-at) :必须。消息的生成时间,采用ISO 8601格式。
- 过期时间 (expiration-time):可选。消息的失效时间,为登录请求增加一个时效窗口。
工作流程:
通常的工作流程在你的后端代码中大致如下:
- 前端调用后端获取 nonce 的接口,后端生成随机 nonce 并构造完整的如上所示的 EIP-4361 消息,同时将 nonce 存入 Redis(设置 5 分钟过期),与地址绑定。
- 前端收到消息后,调用 MetaMask(或其他钱包)的 personal_sign 方法,用户确认后获得签名。
- 前端调用后端做验证【传入签名消息和完整的完整的EIP-4361消息】
java
POST /api/auth/login
Body: { "message": "完整的EIP-4361消息", "signature": "0x..." }
- 后端验证签名、验证消息内容(nonce、过期时间、domain 等),通过后使用 RSA 私钥签发 JWT 返回给前端。后续请求前端携带 JWT,后端用公钥验证。
RSA【非对称加密算法】
核心原理:基于一个简单的数学事实------将两个大素数相乘很容易,但想对它们的乘积进行因式分解(找出是哪两个素数乘出来的)极其困难。这个"乘积"就是RSA的"公钥"的基础。
工作流程:
- 生成密钥对:随机选择两个非常大的质数【大于 1 的自然数中,除了 1 和它本身以外不再有其他因数的数 】(比如几百位数字长),通过复杂运算生成一个公钥(可以公开)和一个私钥(必须保密)。
- 私钥 (n, d):这是一个必须由发送方严格保密的数字对。其中 n 是 p 和 q 的乘积(模数),d 是一个私有指数。
- 公钥 (n, e):这是一个可以完全公开的数字对。它与私钥共享同一个模数 n,但指数 e 是公开的【当然 n 也是公开的】。
- 签名:发送方用私钥对消息进行签名。
- 验证:接收方用对应的公钥验证签名。
特点与现状:
- 优点:原理相对直观,安全性经过了数十年的实践检验,非常可靠。
- 缺点:速度慢,尤其是签名和验证。为了保证安全,密钥长度通常需要2048位甚至4096位【就是指p和q 的乘积n的二进制位数】,导致计算量大,生成的签名和密钥也比较长。
- 主要应用:传统的SSL/TLS证书(HTTPS)、SSH登录、PGP邮件加密、软件代码签名等。你访问的绝大多数银行网站、淘宝、京东,在早期都依赖 RSA 。
ECC
ECC(Elliptic Curve Cryptography,椭圆曲线密码学)是基于椭圆曲线数学结构设计的公钥密码体系。
相比RSA,ECC能以更短的密钥长度提供同等的安全性,且计算效率更高。
ECC(椭圆曲线密码学)的核心公式非常简单:
y² = x³ + ax + b
这就是椭圆曲线的方程。a和b是常数,决定了曲线的形状。
它怎么用来加密?
ECC的安全基础是一个"单向"运算:
Q = k × P
- P:一个固定的起点(叫基点,公开)
- k:你的私钥(一个随机大整数,保密)
- Q:计算出的终点(公钥,公开)
关键点:
- 知道k和P,算出Q → 很容易(正向)
- 知道Q和P,算出k → 几乎不可能(逆向)
举个类比
就像调鸡尾酒:
- 你知道配方(k)和基酒(P)→ 能调出成品(Q)
- 给你成品(Q)和基酒(P)→ 猜不出配方(k)
这就是ECC的全部核心:一个简单公式 + 一个无法逆向的乘法运算。
安全性与现状
安全性:256 位的 ECC 密钥提供与 3072 位 RSA 相当的安全性,另外,ECC一次签名生成的数据量很小(64字节),而 RSA 签名生成的数据量很大(256-512字节)。
量子威胁:和RSA一样,ECC也会被Shor算法攻破,需要转向后量子密码学。
当前地位:
- 区块链:比特币、以太坊、Solana等几乎全部使用ECC(secp256k1)。
- TLS/HTTPS:现代网站普遍支持ECC证书(速度更快)。
- SSH:新密钥优先推荐ed25519(一种高性能ECC变体)。
- JWT:ES256(ECDSA with P-256)是常用签名算法。
ECDSA
ECC 是基础数学,ECDSA 是用 ECC 造出来的具体签名算法。
问题一:后端是如何验证这个签名就是这个用户签的?
这依赖于以太坊使用的椭圆曲线数字签名算法(ECDSA)。以太坊签名由三个核心组件构成:R 和 S(ECDSA 算法输出的两个大整数)以及 V(恢复 ID,用于在多个可能的公钥中确定正确的那一个)。
ECDSA 签名的一个独特特性是:从签名和原始消息中可以恢复出签名者的公钥,而无需提前知道公钥。具体过程如下:
- 将原始消息进行哈希计算(以太坊使用 Keccak-256)
- 结合签名中的 R、S、V 三个值,通过椭圆曲线数学运算反向推导出签名者用于签名的公钥
- 对恢复出的公钥计算 Keccak-256 哈希,取最后 20 个字节,即为签名者的以太坊地址
因此,后端服务器收到用户提交的原始消息和签名后,可以独立计算出签名者地址,然后与消息中声明的 address 字段进行比对。如果两者一致,就证明该签名确实由声明地址的私钥持有者签署。这正是 Web3 登录安全性的数学基础------私钥从未离开用户的钱包,但签名却足以证明用户对地址的控制权。
JWT
JWT(JSON Web Token)是一种开放标准(RFC 7519),定义了一种紧凑、自包含的方式,用于在各方之间安全地传输信息。JWT 由三部分组成,以 . 分隔:
大概长这样:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
text
Header.Payload.Signature
Header:声明令牌类型(JWT)和签名算法(如 RS256)
Payload:存放实际传输的数据(如用户地址、过期时间等)
Signature:对 Header 和 Payload 拼接后,使用指定算法和密钥生成的签名
验证 JWT 时,服务端使用公钥对签名部分进行验证,确保令牌未被篡改且确实由持有私钥的授权中心签发。如果签名验证通过,则说明令牌真实有效。

在 JWT + RSA(RS256)方案中,授权中心持有 RSA 私钥签发 JWT,各个微服务只需持有对应的公钥即可独立验证令牌有效性,无需访问授权中心。这种架构天然支持分布式、无状态认证。
常用算法记录和常用工具记录
- RS256 是 RSA Signature with SHA-256 的缩写,它是一种数字签名算法,非对称加密算法
- HS256(HMAC with SHA-256) 对称加密算法
- 使用 openssl 工具生成 RSA 等密钥对
- 以太坊使用的哈希算法是:Keccak-256,使用的曲线是:secp256k1
- ETH地址生成流程:公钥(64 字节) → Keccak-256 → 取最后 20 字节 → 加 "0x" → 地址
- 加密用公钥,解密用私钥":正确。这是用于保证机密性的标准做法。
- "加密用私钥,解密用公钥":在严格意义上不正确,但它的操作过程(用私钥处理数据,用公钥还原)在密码学中有一个专门的名字------数字签名【私钥签,公钥验)】。