使用加密密钥在 Hardhat 和 Foundry 中保护你的私钥

本文介绍了在智能合约开发中使用加密密钥的重要性,并提供了在 Hardhat 和 Foundry 框架中实现加密密钥的详细步骤。文章强调了明文存储密钥的风险,并提供了使用 AES 等加密技术保护密钥的方法,同时推荐了密钥管理和安全开发的最佳实践。

概述

想象一下,由于一个泄露的私钥而损失了价值数百万美元的加密资产。对于一些DeFi项目来说,这个噩梦已经成为了现实——最值得注意的是 $6.25亿美元的Ronin Bridge攻击,攻击者利用泄露的验证器密钥来耗尽资金——突显了开发者最危险的盲点:凭证管理。

虽然.env文件是管理本地密钥的常用解决方案,但它们仍然存在固有的风险,因为它们以纯文本形式存储凭证,这些凭证可能会被意外地提交到版本控制中,或者通过错误配置暴露出来。为了更强的安全性,加密密钥存储是首选的替代方案,像Hardhat和Foundry这样的主要框架现在都提供了内置支持。

本指南将引导你如何在开发工作流程中实施加密密钥。你将了解这些加密系统是如何工作的,以及如何将它们与Hardhat和Foundry框架集成。无论你部署到测试网还是主网,你都会发现保护你的私钥在整个开发生命周期中的最佳实践。

你将做什么

  • 了解以纯文本处理密钥的风险
  • 了解加密在幕后是如何工作的
  • 在Hardhat和Foundry中设置加密密钥
  • 在你的部署中使用加密密钥

你将需要什么

  • Node.js (v22 或更高版本)
  • 一个 Web3 钱包(例如 MetaMask,Rabby),其中包含一些测试网 ETH(如果需要,可以使用 QuickNode Multi-Chain Faucet
  • 一个免费的 QuickNode 账户 —— 推荐用于获取本指南中使用的可靠的 Sepolia RPC 端点

为什么加密密钥很重要

在智能合约开发和部署期间,通常需要私钥和RPC URL等敏感凭据。这些实际上是你整个应用程序的密钥——如果暴露,攻击者可以耗尽你的钱包,接管基础设施,或冒充你的dApp。

虽然在早期开发或黑客马拉松期间很容易低估风险,但现实世界的事件表明,一个小小的错误——比如在公共GitHub仓库中留下一个密钥——可能会是灾难性的。

常见风险

  • 错误提交的.env文件
  • Shell命令历史记录泄露
  • 恶意软件扫描本地文件以查找密钥模式
  • 通过截图或直播暴露的密钥

真实案例

根据Chainalysis 2024年的报告私钥泄露占去年所有被盗加密货币的43.8%。其中最大的一起是3.05亿美元的DMM比特币黑客攻击,很可能是由于不正确的密钥存储或运营安全造成的。

  • Ronin Bridge攻击(6.25亿美元): 攻击者使用泄露的验证器密钥耗尽了迄今为止最大的DeFi桥之一的资金。 (来源)

  • $4万GitHub泄露(2024): 一名开发人员不小心将他们的私钥留在了一个私有的GitHub仓库中,他们将其短暂地公开,以提交一份授权申请。瞬间,他们的钱包被盗走了4万美元。 (来源)

  • Solana solana-web3.js 后门 (2024): 一个被广泛使用的JavaScript库的恶意更新引入了一个后门,可以直接从磁盘窃取私钥。在漏洞被发现之前,成千上万的项目受到了影响。 (来源)

Chainanalysis Report来源: Chainalysis 2024报告

这些不是个别情况——它们代表了一种趋势。密钥管理仍然是Web3中最大的攻击媒介之一。

加密如何工作

当你加密一个密钥时,你正在使用密钥或密码短语将其转换为密文。只有具有正确解密密钥的用户或系统才能检索原始值。

在像Hardhat和Foundry这样的框架中:

  • 密钥使用AES(高级加密标准)或类似的对称加密方案进行加密
  • 密码(或主密钥)用于在本地加密和解密值
  • 加密的密钥存储在特殊的文件中(secrets.json,钱包密钥库等)
  • 解密仅在运行时发生,防止在内存或CLI历史记录中长期暴露

Encryption Diagram

即使你的机器被入侵或者仓库错误地公开了,加密密钥也会增加一个关键的屏障。如果没有解密密码,攻击者就不能简单地读取原始密钥。仅凭这一点就可以防止资金被盗,尤其是来自自动化机器人的盗窃。

项目设置

在深入了解特定于框架的加密密钥的指令之前,让我们先准备好你的环境。此设置将允许你使用Hardhat或Foundry顺利地遵循本指南。

1. 获取一个QuickNode端点

要与任何区块链进行交互,你需要一个RPC端点。你可以使用QuickNode立即创建一个。在本指南中,我们将使用Etherem Sepolia作为测试网。如果你愿意使用不同的网络,请随时这样做。

  1. 前往QuickNode并注册一个账户
  2. 选择 Ethereum Sepolia 作为你的网络
  3. 复制你的端点URL——稍后我们将使用它来连接你的脚本

2. 使用测试ETH资助你的钱包

你还需要Sepolia测试ETH来部署合约并支付交易费用。你可以从QuickNode Sepolia Faucet请求测试ETH (注意: 你必须在Ethereum Mainnet上至少有0.001 ETH才能使用 faucet,以避免垃圾邮件和滥用)

一旦你有了资金充足的测试网钱包和一个可用的端点,你就可以测试加密密钥了。

更喜欢Foundry?

如果你正在使用Foundry,你可以直接跳到 如何在Foundry中使用加密钱包 部分。

如何在Hardhat中使用加密密钥

Hardhat 3 (目前处于alpha阶段) 通过内置的 secrets manager引入了加密密钥。此功能支持安全地存储任何基于字符串的密钥——包括私钥、RPC URL以及你可能需要的任何其他密钥。

warning

Hardhat 3 目前处于alpha阶段。在正式发布为稳定版本之前,请谨慎使用。

步骤 1: 设置一个新的Hardhat项目

运行以下命令来创建一个新的Hardhat项目。

请注意,@next 被添加到 npx 命令中,以确保你使用的是带有 next 标签的Hardhat版本,截至本文撰写时,该版本是 Hardhat 3.0.0-next.4

mkdir secure-hardhat && cd secure-hardhat
npm init -y
npx hardhat@next --init

接受提示的默认答案。然后,验证Hardhat 3是否已安装:

npx hardhat --version

步骤 2: 设置加密密钥

要存储你的RPC URL,运行以下命令:

npx hardhat keystore set SEPOLIA_RPC_URL

如果这是你第一次使用密钥库,系统会提示你输入密码。此密码将用作主密钥来加密你的密钥。这意味着如果你丢失了密码,你将无法访问你的密钥。

然后,系统会提示你输入一个值,该值将使用你提供的主密钥进行加密。

通过运行以下命令,对你的私钥重复此过程:

npx hardhat keystore set SEPOLIA_PRIVATE_KEY

步骤 3: 验证加密密钥

要验证你的密钥是否已加密,运行以下命令:

npx hardhat keystore list

你应该在加密密钥的列表中看到你的RPC URL和私钥。

如果需要再次获取密钥值,可以运行以下命令。这将提示你输入主密钥并解密该值:

npx hardhat keystore get SEPOLIA_RPC_URL

设置好密钥后,你可以在配置文件中引用它们,以便在项目中安全地使用它们。

步骤 4: 在配置中引用密钥

当你初始化一个新的Hardhat项目时,它会附带一个预配置的hardhat.config.js文件,以及一个示例合约,部署脚本和一个Hardhat Ignition部署文件 - 推荐的智能合约部署方式。

在本指南中,我们将坚持使用基本的脚本部署,但了解如何使用配置文件来引用你的密钥是有帮助的。

打开 hardhat.config.js 并检查 networks 对象以引用你加密的密钥。如果你使用的是不同的密钥名称,请相应地更新 networks 对象。

import { configVariable } from "hardhat/config";

module.exports = {
  networks: {
    sepolia: {
      url: configVariable("SEPOLIA_RPC_URL"),
      accounts: [configVariable("SEPOLIA_PRIVATE_KEY")],
    },
  },
};

就是这样!现在你可以在你的部署脚本中使用你加密的密钥,而永远不会以纯文本形式暴露它们。

步骤 5: 在部署脚本中使用加密密钥

运行以下命令来部署你的合约,使用 ignition/modules 下的 Counter.ts 模块, 该模块基本上部署了 Counter.sol 合约,然后使用值5调用 incBy 函数。

npx hardhat ignition deploy --network sepolia ignition/modules/Counter.ts

当你运行命令时,Hardhat会提示你输入之前设置的密码,因为sepolia网络被配置为使用密钥库。只有当当前脚本或任务正在使用加密密钥时,才需要输入此密码。否则,你不会被提示输入密码。

输入密码后,Hardhat将部署你的合约并使用值5调用 incBy 函数。

祝贺你!你已成功在Hardhat中设置了加密密钥,并在你的部署脚本中使用了它们。

如何在Foundry中使用加密密钥

Foundry 支持通过 cast wallet CLI 进行加密钱包导入。虽然它目前不支持加密像RPC URL这样的其他变量,但你仍然可以使用加密密钥和环境变量的组合来保护你的工作流程。

如果你是Foundry的新手,我们建议从 Foundry简介 指南开始,以熟悉基础知识。

步骤 1: 安装并初始化Foundry

如果尚未安装Foundry,请通过运行以下命令进行安装:

curl -L https://foundry.paradigm.xyz | bash

然后,通过运行以下命令来初始化Foundry:

foundryup
forge init secure-foundry
cd secure-foundry

此命令将创建一个名为 secure-foundry 的新目录,并在其中从默认模板初始化一个新的Foundry项目。

├── README.md
├── foundry.toml
├── lib
│ └── forge-std
├── script
│ └── Counter.s.sol
├── src
│ └── Counter.sol
└── test
    └── Counter.t.sol

现在,我们将导入一个钱包以在我们的Foundry项目中使用。

步骤 2: 导入你的钱包

要导入钱包,我们将使用 cast wallet CLI。将 your-wallet-name 替换为你的钱包名称,并运行以下命令:

cast wallet import your-wallet-name --interactive

系统将提示你输入你的私钥并使用密码对其进行加密。密钥安全地存储在你本地的密钥库中,其默认路径为 ~/.foundry/keystore

使用--interactive标志的原因是为了避免将私钥存储在终端历史记录中。

当你的钱包被导入后,就可以使用了。

步骤 3: 创建和引用环境变量文件

现在你的钱包已被加密,你需要安全地引用你的RPC端点。由于Foundry目前不支持加密任意值(如RPC URL),最实际的方法是使用.env文件来管理这些密钥。虽然没有加密,但.env文件仍然被广泛使用,并且比直接在源代码中存储密钥更安全。

tip

如果你正在寻找更大应用程序或团队中的额外保护,你还可以探索诸如 Dotenv Vault 之类的工具,用于加密的 .env 文件共享,或诸如 AWS Secrets Manager 之类的云管理解决方案,用于生产部署。

在你的项目的根目录中创建一个 .env 文件,并添加你的QuickNode端点:

SEPOLIA_RPC_URL=https://your-quicknode-endpoint

并在运行你的脚本之前加载它:

source .env

步骤 4: 运行你的脚本

我们在前面的步骤中安全地导入了钱包,并将RPC端点添加到了我们的配置中。现在,我们可以运行我们的脚本并部署我们的合约。

Foundry的模板项目附带一个示例脚本,该脚本部署了一个 Counter 合约。更新脚本以使用你的钱包和RPC端点:

forge script script/Counter.s.sol:CounterScript --rpc-url $SEPOLIA_RPC_URL --account your-wallet-name --broadcast

终端将提示你输入用于加密私钥的密码。

输入密码后,Foundry将运行你的脚本并部署你的合约。

[⠊] Compiling...
No files changed, compilation skipped
Enter keystore password:
Script ran successfully.

### Setting up 1 EVM.

==========================
...

祝贺你!你已成功在Foundry中设置了加密密钥,并在你的部署脚本中使用了它们。

管理密钥的最佳实践

加密密钥是基础步骤,但维护安全开发工作流程需要额外的注意。以下是帮助保护凭据并最大程度地减少暴露风险的关键实践:

步骤 1: 使用 .gitignore 防止意外提交

如果你使用 .env 文件,请确保将它们从版本控制中排除,并将其保存在本地环境中。这些文件中的密钥未加密,应谨慎对待。

## Common entries
.env
secrets.json
foundry.keystore

步骤 2: 避免将密钥直接输入到终端中

使用交互式CLI提示或环境变量输入密钥。避免将密钥作为内联参数传递,以防止它们存储在shell历史记录中。

步骤 3:在出错后清除Shell历史记录 如果密钥意外地输入或粘贴到终端中,请立即清除你的历史记录:

history -c && history -w  # 对于 Bash 和 Zsh

步骤 4: 为每个项目使用专用密钥

为不同的项目或环境生成单独的私钥和RPC端点URL。这限制了任何妥协的有效性。

tip

有关RPC端点安全性的更多详细信息,请查看 本指南

步骤 5: 在部署之前测试密钥工作流程

始终验证你的项目是否在本地或暂存环境中正确解密密钥。

步骤 6: 保护你的本地机器

保持你的操作系统和工具更新。避免安装未验证的软件,并定期扫描可能针对钱包或密钥文件的恶意软件。

步骤 7: 探索加密密钥管理工具

步骤 8: 在生产中使用云密钥管理器

对于生产基础设施,请考虑使用基于云的密钥管理工具,例如:

结论

私钥管理仍然是构建安全dApp和智能合约的最关键方面之一。随着Hardhat和Foundry现在都提供加密密钥支持,开发人员拥有保护敏感数据的工具,而不会损害速度或便利性。

无论你使用的是Hardhat的内置密钥管理器还是Foundry的加密钱包密钥库,尽早采用这些实践都有助于防止常见错误并保护你的部署。

如果你遇到问题或有疑问,请在我们的 Discord 中提出。通过在 Twitter (@QuickNode) 或我们的 Telegram announcement channel 上关注我们来了解最新信息。

我们 ❤️ 反馈!

如果你对新主题有任何反馈或要求,请 告诉我们。我们很乐意听到你的声音。

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

0 条评论

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