背景

重放攻击 是指某个在一个网络上有效的已签名交易,未经用户同意就在另一个网络上被重复执行。对于基于以太坊的网络来说,这个问题尤为突出,因为:
  1. 地址格式:以太坊使用十六进制地址(例如 0x123...),这些地址在所有 EVM 链上都是相同的
  2. 交易格式:各网络使用相同的交易结构和签名方案
  3. 网络分叉:当链发生分叉时,同一地址会同时存在于两条链上,并且余额可能不同
EIP-155 通过将链 ID 纳入交易签名过程来解决这个问题,使签名与特定网络绑定。

Cosmos EVM 如何处理重放保护

双重保护机制

Cosmos EVM 在两个层面实现重放保护:

Cosmos 交易

固有保护:使用带有链专属前缀的 Bech32 地址(例如 cosmos1...、osmo1...)。来自一条链的地址在其他链上无效,因此可自动提供重放保护。

EVM 交易

EIP-155 保护:要求交易签名中包含链 ID。EVM 模块默认强制执行这一点,拒绝没有正确链 ID 的交易。

链 ID 配置

如链 ID页面所述,Cosmos EVM 使用:
  • EVM 链 ID(整数):用于以太坊交易中的 EIP-155 重放保护
  • Cosmos 链 ID(字符串):用于带有 Bech32 地址的 Cosmos SDK 交易
EVM 链 ID 必须在所有兼容 EVM 的链中保持唯一,才能确保重放保护有效。在选择链 ID 之前,请先检查 chainlist.org。

配置重放保护

默认情况下,所有 Cosmos EVM 节点都启用重放保护。系统会强制要求交易采用 EIP-155 签名,并拒绝任何未受保护的交易。

允许未受保护的交易(不推荐)

强烈不建议禁用重放保护,因为这会使用户暴露在重放攻击风险之下。只有在特定测试场景或迁移用途下才应考虑这样做。
如果确有必要,可以通过以下两步流程允许未受保护的交易:

第一步:全局模块参数

必须通过治理提案或创世配置修改 EVM 模块参数:
// In x/vm/types/params.go
DefaultAllowUnprotectedTxs = false  // Default value

// To enable in genesis.json
{
  "vm": {
    "params": {
      "allow_unprotected_txs": true  // Must be set to true
    }
  }
}

第二步:节点配置

即使已经在全局启用,每个节点运营者仍必须通过修改各自的节点配置来单独选择启用:
# In $HOME/.evmd/config/config.toml
[json-rpc]
# AllowUnprotectedTxs restricts unprotected (non EIP-155 signed) transactions
# to be submitted via the node's RPC when the global parameter is disabled.
allow-unprotected-txs = true  # false by default
只有同时满足以下两个条件,未受保护的交易才会被接受:
  1. 全局参数 allow_unprotected_txs = true
  2. 节点配置 allow-unprotected-txs = true

交易类型与保护

受保护的交易(EIP-155)

所有现代以太坊交易类型都包含链 ID:
// EIP-1559 Dynamic Fee Transaction
const tx = {
  type: 2,
  chainId: 9000,  // EVM Chain ID included
  nonce: 0,
  maxFeePerGas: ...,
  maxPriorityFeePerGas: ...,
  // ... other fields
}

传统未受保护交易

不包含链 ID 的 EIP-155 之前的交易:
// Legacy transaction without chain ID (rejected by default)
const tx = {
  nonce: 0,
  gasPrice: ...,
  gasLimit: ...,
  to: ...,
  value: ...,
  data: ...,
  // No chainId field
}

安全影响

启用重放保护时(默认)

可防范:
  • 跨链重放攻击
  • 交易误在错误网络上执行
  • 与分叉相关的重放漏洞

禁用重放保护时

面临的风险:
  • 交易可在任意 EVM 链上被重放
  • 因重放攻击导致资金损失
  • 在多条链上发生非预期的合约交互

最佳实践

  1. 始终使用 EIP-155:确保你的钱包和工具在签名交易时包含链 ID
  2. 验证链 ID:在签名前再次确认交易中的链 ID
  3. 保持保护启用:绝不要在生产环境中禁用重放保护
  4. 监控交易:在迁移期间跟踪交易是否在不同链上被执行

验证

要验证重放保护状态:
# Check global parameter
evmd q vm params | grep allow_unprotected_txs

# Check node configuration
grep allow-unprotected-txs $HOME/.evmd/config/config.toml

相关资源


Background

Replay attacks occur when a signed transaction valid on one network can be replayed on another network without the user’s consent. This is particularly problematic for Ethereum-based networks because:
  1. Address Format: Ethereum uses hexadecimal addresses (e.g., 0x123...) that are identical across all EVM chains
  2. Transaction Format: The same transaction structure and signing scheme across networks
  3. Network Forks: When chains fork, the same addresses exist on both chains with potentially different balances
EIP-155 solves this by incorporating the chain ID into the transaction signing process, making signatures network-specific.

How Cosmos EVM Handles Replay Protection

Dual Protection System

Cosmos EVM implements replay protection at two levels:

Cosmos Transactions

Inherent Protection: Uses Bech32 addresses with chain-specific prefixes (e.g., cosmos1..., osmo1...). Addresses from one chain are invalid on others, providing automatic replay protection.

EVM Transactions

EIP-155 Protection: Requires chain ID in transaction signatures. The EVM module enforces this by default, rejecting transactions without proper chain ID.

Chain ID Configuration

As documented in the Chain ID page, Cosmos EVM uses:
  • EVM Chain ID (integer): Used for EIP-155 replay protection in Ethereum transactions
  • Cosmos Chain ID (string): Used for Cosmos SDK transactions with Bech32 addresses
The EVM Chain ID must be unique across all EVM-compatible chains to ensure replay protection. Check chainlist.org before selecting your chain ID.

Configuring Replay Protection

By default, replay protection is enabled on all Cosmos EVM nodes. The system enforces EIP-155 signed transactions, rejecting any unprotected transactions.
Disabling replay protection is strongly discouraged as it exposes users to replay attacks. Only consider this for specific testing scenarios or migration purposes.
If absolutely necessary, unprotected transactions can be allowed through a two-step process:

Step 1: Global Module Parameter

The EVM module parameter must be changed via governance proposal or genesis configuration:
// In x/vm/types/params.go
DefaultAllowUnprotectedTxs = false  // Default value

// To enable in genesis.json
{
  "vm": {
    "params": {
      "allow_unprotected_txs": true  // Must be set to true
    }
  }
}

Step 2: Node Configuration

Even when globally enabled, each node operator must individually opt-in by modifying their node configuration:
# In $HOME/.evmd/config/config.toml
[json-rpc]
# AllowUnprotectedTxs restricts unprotected (non EIP-155 signed) transactions
# to be submitted via the node's RPC when the global parameter is disabled.
allow-unprotected-txs = true  # false by default
Both conditions must be met for unprotected transactions to be accepted:
  1. Global parameter allow_unprotected_txs = true
  2. Node configuration allow-unprotected-txs = true

Transaction Types and Protection

Protected Transactions (EIP-155)

All modern Ethereum transaction types include chain ID:
// EIP-1559 Dynamic Fee Transaction
const tx = {
  type: 2,
  chainId: 9000,  // EVM Chain ID included
  nonce: 0,
  maxFeePerGas: ...,
  maxPriorityFeePerGas: ...,
  // ... other fields
}

Legacy Unprotected Transactions

Pre-EIP-155 transactions without chain ID:
// Legacy transaction without chain ID (rejected by default)
const tx = {
  nonce: 0,
  gasPrice: ...,
  gasLimit: ...,
  to: ...,
  value: ...,
  data: ...,
  // No chainId field
}

Security Implications

With Replay Protection Enabled (Default)

Protected from:
  • Cross-chain replay attacks
  • Accidental transaction execution on wrong networks
  • Fork-related replay vulnerabilities

With Replay Protection Disabled

Vulnerable to:
  • Transactions being replayed on any EVM chain
  • Loss of funds through replay attacks
  • Unintended contract interactions on multiple chains

Best Practices

  1. Always use EIP-155: Ensure your wallet and tools sign transactions with chain ID
  2. Verify chain ID: Double-check the chain ID in your transaction before signing
  3. Keep protection enabled: Never disable replay protection in production
  4. Monitor transactions: Track transaction execution across chains during migrations

Verification

To verify replay protection status:
# Check global parameter
evmd q vm params | grep allow_unprotected_txs

# Check node configuration
grep allow-unprotected-txs $HOME/.evmd/config/config.toml