Logo
新用户订阅 RPC,首月享 6.5 折优惠查看优惠
OnFinality Learn
基础设施与运维阅读约 11 分钟

热钱包与冷钱包:密钥管理、威胁模型与验证

一份实用指南:通过建模密钥暴露面、交易频率以及真正能降低损失风险的验证步骤,在热钱包与冷钱包之间做出选择。

TL;DR

热钱包和冷钱包不是设备,而是密钥管理的姿态:热钱包让签名材料可被联网进程访问,冷钱包则将其隔离,直到明确的签名步骤才使用。正确的选择取决于你交易的频率、每个密钥背后的价值,以及你实际能检测和恢复的故障模式。本文提供思维模型、地址与余额检查的可运行验证步骤、测试签名流程的诊断程序,以及一张可用你自己的测量结果填写的表格。本文刻意不推荐特定硬件品牌或端点;关于具体的 RPC 端点选择,请使用 RPC Assistant。

直接答案与范围

热钱包是指任何私钥或签名能力可被联网进程访问、且无需单独审批步骤的钱包。冷钱包是指签名材料保持离线、仅在明确(通常是物理)批准后才使用的钱包。区别在于暴露面和签名流程,而不在于设备是手机、浏览器扩展、硬件还是纸质备份。

本文涵盖在选择或审计钱包设置时至关重要的操作差异:密钥暴露、交易频率、恢复和验证。它不排名供应商,也不声称经过测量的安全结果。你在结果表中看到的任何性能或可靠性数字,都是你在自己环境中运行测量所得的占位符。

假设与前提条件

以下流程假设你在测试网上有一个有资金的测试钱包,或有一个小额主网账户,一个你控制或信任的 JSON-RPC 端点,以及基本的命令行工具。你绝不应将生产私钥粘贴到 shell 历史、聊天窗口或浏览器控制台中。每次测试都使用环境变量和一次性密钥。

你还需要一种查询链上状态的方法。如果你仍在决定使用哪个端点,关于选择可靠端点的 RPC Assistant 指南和 OnFinality RPC 服务概览是合理的起点。关于网络特定参数,请参阅支持的网络列表。

  • 一个价值可忽略的测试密钥,存储在环境变量中,例如 PRIVATE_KEY。
  • 用于你正在测试的网络的 RPC_URL;不要在你分享的脚本中硬编码公共端点。
  • 如果你想运行签名示例,需要 Node.js 18+ 或 Python 3.10+。
  • 如果你正在测试冷钱包流程,需要硬件钱包或气隙签名器。

思维模型:暴露面与签名频率

每个钱包都有两个独立属性:密钥可被软件访问的时长,以及你需要签名的频率。热钱包最小化摩擦,但最大化了恶意软件、恶意浏览器扩展或被入侵的依赖项接触密钥的窗口。冷钱包最小化该窗口,但为每笔交易增加了步骤,这产生了自身的故障模式:人们将资金转移到热钱包并留在那里。

一个有用的推理方式是将密钥与地址分开。地址是公开的,可以安全分享;密钥是唯一授权花费的东西。因此,热与冷的问题在于密钥存放在哪里,以及在使用前必须发生什么。一个一直插在笔记本电脑上、无需确认即可签名的硬件钱包,比其营销宣传更接近热钱包。一个带有强密码短语且签名应用无互联网权限的手机钱包,比其外形更接近冷钱包。

  • 热:密钥可被在线进程访问;签名快速且通常自动。
  • 冷:密钥离线保存;签名需要明确批准或单独设备。
  • 温:混合模式,密钥静态加密,但在联网机器上解密以进行签名。
  • 标签的重要性不如回答这个问题:什么可以在没有人在场的情况下签名?

使用 curl 验证地址和余额

在你信任任何钱包 UI 之前,验证它显示的地址与你认为控制的密钥匹配。最简单的检查是直接查询链。以下 curl 调用使用大多数 EVM 网络支持的 JSON-RPC 方法。将 RPC_URL 和 ADDRESS 替换为你的值。

第一个调用返回以 wei 为单位的余额。第二个返回交易计数,这对于在交易失败后发现 nonce 缺口很有用。如果钱包 UI 和 RPC 不一致,停止并调查,然后再签名任何东西。

curl -s -X POST "$RPC_URL" \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"eth_getBalance","params":["'"$ADDRESS"'","latest"]}'

curl -s -X POST "$RPC_URL" \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":2,"method":"eth_getTransactionCount","params":["'"$ADDRESS"'","latest"]}'

在 JavaScript 中从密钥派生地址

一个常见的冷钱包错误是备份了错误的东西。你需要种子短语或私钥,而不是地址。下面的脚本从私钥派生地址,以便你可以确认备份确实控制你期望的地址。仅在离线机器上或使用一次性密钥运行它。

该脚本使用广泛可用的 ethers。它打印地址,从不记录密钥。将输出与钱包显示的地址进行比较。如果它们不同,你的备份不是用于该地址的。

// npm install ethers
import { Wallet } from 'ethers';

const pk = process.env.PRIVATE_KEY;
if (!pk) throw new Error('Set PRIVATE_KEY to a throwaway key');

const wallet = new Wallet(pk);
console.log('address:', wallet.address);
// Do not print the private key.

端到端测试签名流程

对于热与冷决策最有用的诊断,是对你将在生产中使用的确切签名路径进行试运行。对于热钱包,这意味着确认哪个进程可以访问密钥,以及如果该进程被入侵会发生什么。对于冷钱包,这意味着确认离线签名器产生有效签名,并且在线机器可以在从未看到密钥的情况下广播它。

一个实用的程序是签名一笔零值或最小值的交易,广播它,并验证包含。下面的 Python 示例使用 web3.py 构建并发送交易。它假设测试网和有资金的测试密钥。如果你使用硬件钱包,将本地账户替换为设备的签名接口,并保持密钥不在主机上。

from web3 import Web3
import os

w3 = Web3(Web3.HTTPProvider(os.environ['RPC_URL']))
acct = w3.eth.account.from_key(os.environ['PRIVATE_KEY'])

nonce = w3.eth.get_transaction_count(acct.address)
tx = {
    'to': acct.address,
    'value': 0,
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'nonce': nonce,
    'chainId': w3.eth.chain_id,
}
signed = acct.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print('sent:', tx_hash.hex())
receipt = w3.eth.wait_for_transaction_receipt(tx_hash, timeout=120)
print('status:', receipt.status, 'block:', receipt.blockNumber)

预期的验证结果

成功的试运行会产生交易哈希、状态为 1 的收据和区块号。发送者的 nonce 增加一。如果你查询前后余额,差值应等于价值加 gas。对于零值自转账,余额仅减少 gas,这是一种干净的方式,确认签名和广播工作正常,而无需移动有意义的资金。

对于冷钱包流程,预期结果是在线机器永远无法访问密钥。你可以通过检查广播进程的环境中不存在密钥来验证这一点。如果你的签名器要求将密钥加载到在线机器中,那么无论设备标签如何,你都有一个温或热设置。

  • 收据状态 1 和区块号确认包含。
  • 每笔成功交易 nonce 恰好增加一。
  • 对于简单转账,余额差值等于价值加 gas。
  • 广播进程的环境不应包含私钥。

用于你自己测量的结果表

使用下表记录你在环境中观察到的内容。不要用别人设置中的数字填写;重点是在相同条件下比较你的热和冷路径。测量签名延迟、广播延迟和所需的手动步骤数。该表是模板,不是基准。

  • | 指标 | 热钱包路径 | 冷钱包路径 | 备注 |
  • | --- | --- | --- | --- |
  • | 从意图到签名交易的时间 | (测量) | (测量) | 包括批准步骤 |
  • | 从签名到包含的时间 | (测量) | (测量) | 取决于 RPC 和网络 |
  • | 手动批准步骤 | (计数) | (计数) | 物理确认计入 |
  • | 密钥可被在线进程访问 | 是/否 | 是/否 | 通过进程检查验证 |
  • | 恢复已测试 | 是/否 | 是/否 | 在干净机器上从备份恢复 |

常见故障排查

大多数钱包故障不是密码学的;它们是操作性的。一笔从未确认的交易通常是 nonce 缺口、gas 设置过低或 RPC 端点落后于链头。一个显示与预期不同地址的冷钱包通常意味着错误的派生路径或不同账户的备份。一个突然显示不熟悉交易的热钱包通常意味着密钥已暴露。

当你看到不匹配时,停止签名并对照独立来源验证。直接查询链,检查地址派生,并确认链 ID。如果你使用共享或公共端点,过时的响应可能看起来像钱包错误。专用节点访问减少了这类歧义,OnFinality 专用节点概览解释了何时这很重要。

  • Nonce 缺口:查询 eth_getTransactionCount 并与钱包的待处理计数比较。
  • 链头过时:比较两个端点的 blockNumber。
  • 错误地址:从备份重新派生并比较。
  • 意外的出站交易:将密钥视为已泄露并转移剩余资金。

局限性与权衡

冷存储并不自动更安全。它将风险从远程攻击者转移到物理丢失、用户错误和签名设备的供应链入侵。没有备份的丢失种子短语是不可恢复的。从不信任的经销商处购买的硬件钱包可能带有预初始化的种子。热钱包也不自动不安全;一个余额小且密码短语强的热钱包可以是一个可接受的支出账户。

实际的权衡通常是拆分:在热钱包中保留少量运营余额,将大部分价值放在冷签名路径后面。这种拆分减少了热钱包被入侵的爆炸半径,而无需为每笔小额支付强制冷签名步骤。确切拆分取决于你的交易频率和对恢复努力的容忍度,而不是通用规则。

后续步骤

首先用一段话写下你的威胁模型:谁或什么可以接触你的密钥,如果他们这样做了你会失去什么。然后在测试网上运行上述验证步骤。一旦确认工作流程,在移动有意义的价值之前,在干净机器上测试恢复。

如果你需要用于验证步骤的可靠端点,请查看 RPC 端点指南并在 RPC 定价页面比较计划。对于运行签名基础设施的团队,专用节点选项和 API 服务概览是自然的下一步阅读。对于具体的端点或提供商推荐,请询问 RPC Assistant,而不是从列表中猜测。

  • 记录签名路径以及谁可以批准。
  • 在干净设备上测试从备份恢复。
  • 分离运营和储备余额。
  • 在任何钱包软件更新后重新验证地址。

永远不用担心基础设施

OnFinality 消除了 DevOps 的繁重工作,让您能够更聪明、更快地构建。

开始