Solidityにおけるリエントランシー攻撃とは?
執筆者 Alchemy
リエントランシー攻撃とは、Solidityにおいて、資金が尽きるまでスマートコントラクトから繰り返し資金を引き出し、権限のないコントラクトに送金し続ける攻撃である。この攻撃は、悪意のある行為者が悪用可能なスマートコントラクトを見つけた際、ブロックチェーン上の実行サイクル中に発生する。リエントランシー攻撃により、DAOやブロックチェーンプロトコルから数百万ドル相当の資金が流出している。
以下では、リエントランシー攻撃の仕組み、2種類のリエントランシー攻撃、そしてSolidity開発者がEthereumおよびSolanaブロックチェーン上でスマートコントラクトを脆弱性から保護するために取れる予防策について解説する。
リエントランシー攻撃とは
リエントランシー攻撃は、スマートコントラクトの関数が、しばしば身元不明あるいは敵対的な可能性のある行為者によって書かれたコントラクトへの外部呼び出しを行う際、トランザクションの制御フローを一時的に手放すことで発生する。これにより、呼び出された側のコントラクトが主要なスマートコントラクト関数を再帰的に呼び出し、資金を引き出すことが可能になる。
Ethereumブロックチェーン上のスマートコントラクトの実行サイクルは、残高を確認し、資金を送金し、その後残高を更新する。スマートコントラクトがエスクロー状態にある間、悪意のある行為者は別の呼び出しを行い資金を引き出すことができる。このサイクルは、資金が実質的に枯渇するまで繰り返される。
リエントランシー攻撃はどのように機能するか
**リエントランシー攻撃は、脆弱なコントラクトと悪意のあるコントラクトという2つのスマートコントラクト間で資金を移動させる再帰的なプロセスを作り出す。**リエントランシー攻撃の手順は以下の通りである:
- 悪意のある行為者が、脆弱なコントラクト「X」に対して、悪意のあるコントラクト「Y」へ資金を送金するよう呼び出しを行う。
- コントラクトXは、攻撃者が必要な資金を保有しているかを判定し、コントラクトYへの資金送金を実行する。
- コントラクトYが資金を受け取ると、残高が更新される前にコントラクトXへ再度呼び出しを行う_コールバック_関数を実行する。
- この再帰的なプロセスは、すべての資金が枯渇し移動するまで続く。
下図はこの攻撃のシナリオを示している:

リエントランシー攻撃の種類
リエントランシー攻撃には、単一関数型とクロスファンクション型の2種類がある。
1. 単一リエントランシー攻撃
単一リエントランシー攻撃は、脆弱な関数が攻撃者が再帰的に呼び出そうとしている関数そのものである場合に発生する。単一リエントランシー攻撃は、クロスファンクション型のリエントランシー攻撃よりも単純で、防止しやすい。
2. クロスファンクション攻撃
クロスファンクションリエントランシー攻撃は、脆弱な関数が、攻撃者にとって都合の良い効果を持つ別の関数と状態を共有している場合にのみ成立する。クロスファンクション攻撃は検知が難しく、防止も困難である。
3. クロスコントラクト攻撃
クロスコントラクトリエントランシー攻撃は、あるコントラクトの状態が完全に更新される前に、別のコントラクトから呼び出される場合に発生する。クロスコントラクトリエントランシー攻撃は、複数のコントラクトが同一の変数を手動で共有し、一部が安全でない方法でその共有変数を更新している場合に発生しやすい。
Solidityのリエントランシー攻撃の実例
以下の代表的なリエントランシー攻撃事例は、悪意のある行為者がブロックチェーンプロトコルの脆弱性をどのように悪用してきたかを示している:DAOハック、Lendf.me、Cream Financeである。
1. DAOハック(2016年)
EthereumのDAOは、約6,000万ドル相当のEtherをハッキングされた。EthereumのDAOは、ネットワークメンバーが投資判断に直接投票できる投資ファンドとして設計されていた。
DAOは約1億5,000万ドルを調達したが、専門家やコミュニティ参加者は、資金を保管するスマートコントラクトのセキュリティについて懸念を表明していた。資金は、ソースコード内の再帰呼び出しのバグによりリエントランシー攻撃に脆弱なスマートコントラクトにロックされていた。開発チームが問題を修正する前に、ハッカーが攻撃を実行しコントラクトから資金を引き出した。
2. Lendf.meプロトコル(2020年)
2020年4月、悪意のある行為者がリエントランシー攻撃を用いて、Ethereumネットワーク上の貸付業務を行う分散型金融プロトコルであるLendf.meプロトコルから2,500万ドルを盗み出した。
プロトコルの開発者は、ERC-777トークンが送金・受取時にユーザーに通知するコールバック関数を持つという点を見落としていた。ハッカーは、悪意のあるスマートコントラクトを受取人として設定することでこの脆弱性を悪用し、Lendf.meプロトコルの資金の99.5%を引き出した。
3. Cream Financeハック(2021年)
2021年10月、悪意のある行為者は、プロトコルの「フラッシュローン」機能に対するリエントランシー攻撃を用いて、1億3,000万ドル以上相当のERC-20トークンおよびCream流動性プロトコル(LP)トークンを盗み出した。この攻撃の根本原因は、CREAM Financeプロトコルへの誤ったAMPの統合であった。
リエントランシー攻撃を防ぐ方法
**リエントランシー攻撃を防止し、潜在的な被害を軽減するには、厳格なブロックチェーンセキュリティフレームワークの構築が不可欠である。**以下のリエントランシー対策のベストプラクティスは、開発者およびweb3コミュニティ全体が資金を保護する助けとなる:チェック・エフェクト・インタラクション(CEI)、リエントランシーガード、プルペイメント、ガス制限である。
チェック・エフェクト・インタラクション(CEI)
CEIプロセスは、リエントランシーを防ぐための基本的な手法である。チェックとは条件の真偽を指し、エフェクトとは相互作用の結果として生じる状態変更を指し、インタラクションとは関数間またはコントラクト間のトランザクションを指す。
インタラクションの前にエフェクト(実行効果)を配置することに伴う潜在的なセキュリティリスクや抜け穴は、開発者にとって重要な考慮事項である。
リエントランシーガード(ミューテックス)
リエントランシーガード(ミューテックス)は、関数または関数修飾子として作成できる。リエントランシーに脆弱な関数呼び出しの周囲にブール型のロックが配置される。これは、「ロック」の初期状態がfalseであるが、脆弱な関数の実行が始まる直前にtrueに設定され、実行終了後速やかにfalseに戻されることを意味する。
プルペイメント
より安全なエンドツーエンドのトランザクションを実現する方法として、プルペイメント方式がある。プルペイメントのプロセスでは、資金の送金に仲介エスクローを使用することが義務付けられ、潜在的に敵対的な相手との直接的な接触を回避する。
仲介エスクローを介して資金を送ることで、スマートコントラクトの資金はリエントランシー攻撃から保護される。ただし、そのエスクローが複数のアカウントの資金を管理している場合、リエントランシーの対象となる可能性がある。CEIパターンとリエントランシーガードは、適切な場合には実装すべきである。
ガス制限
ガス制限は、攻撃者を防ぐ最適な手法ではない。というのも、ガスコストはEthereumのオペコードに依存しており、これは変更される可能性があるためである。一方で、スマートコントラクトのコードは不変である。
send、transfer、_call_関数の違いを理解することは重要である。_send_と_transfer_は事実上同じであるが、_transfer_はトランザクションが失敗した場合にロールバックするのに対し、_send_はしない。
_send_や_transfer_とは異なり、_call_関数にはガス制限がなく、マルチコントラクトのトランザクションを実行するためにガスを転送する。残念ながら、これはリエントランシー攻撃も可能にしてしまうことを意味する。
Alchemy Universityでリエントランシー攻撃についてさらに学ぶ
Ethereum上のスマートコントラクトの実行サイクルは、完全に安全なプロセスではない。悪意のある行為者は、リエントランシー攻撃を実装することでブロックチェーンを悪用し、脆弱なスマートコントラクトから資金を移動・引き出す。予防策を講じることで、Solidity開発者はより安全な実行サイクルを確保し、自身のブロックチェーンプロトコルを保護できる。
Solidityスマートコントラクト開発のベストプラクティスについて学ぶには、Alchemyの無料の7週間Ethereum Developer Bootcampに参加してほしい。もともと3,000ドルの認定コースであったAlchemy Universityのブートキャンプは、無料でSolidityを学ぶための最上の場である。
開発全般が初めての開発者にとっては、Ethereumブートキャンプを始める前の前提知識として、Alchemyの3週間JavaScriptクラッシュコースが最適である。
関連する概要

ブロックチェーンで魔法を生み出す
Alchemyは、最も強力なweb3開発者向けプロダクトとツールを、豊富なリソース、コミュニティ、そして卓越したサポートと組み合わせて提供します。


