スマートコントラクトに対する 既知の攻撃とその対策 1 blockchain.tokyo#21 @odan3240
View Slide
自己紹介 ● Twitter: @odan3240 ● エンジニア ○ フロントエンド ○ AWS ○ ブロックチェーン ● 会社: モバイルファクトリー ○ チーム: ブロックチェーンチーム ○ DApps を身近にする Uniqys Project をやっている 2
Uniqys Project ● ミッション ○ Uniqys Project ですべての人に DApps を身近にする ● Uniqys Kit ○ Ethereum のサイドチェーンな DApps を 開発するための開発キット ● Quragé ○ モバイルウォレット ● Quragé Link ○ Metamask のないブラウザでも DApps のプレイを可能にするサービス 3
背景 4
スマートコントラクト ● Ethereum の仮想マシンのコンテキストで決定論的に実行される不変なコンピュータプログラム ● コンテキスト ○ ブロックチェーンに関する 限られた情報にしかアクセスできない ● 決定論的 ○ 実行時のコンテキストが同じなら 誰が実行しても結果は同じ ● 不変 ○ デプロイすると変更できない 5
コントラクトの難しさ ● スマートコントラクトの実装は Web 開発とは異なる視点が必要 ○ ハードウェアとか金融プログラミングに似ている ■ 変更が困難 ■ バグが発生したときのリスクが高い ● 歴史が浅く様々な攻撃手法が発見されている ○ The DAO 事件 ○ Parity Multisig Wallet への攻撃 6
対策 ● 哲学を知る ● ベストプラクティスを知る ● 実装パターンを知る ● テストを書く ● 監査ツールを使う ● 監査組織に監査を依頼する ● 既知の攻撃と対策を知る 7
対策 ● 哲学を知る ● ベストプラクティスを知る ● 実装パターンを知る ● テストを書く ● 監査ツールを使う ● 監査組織に監査を依頼する ● 既知の攻撃と対策を知る ← この話をします 8
既知の攻撃 9
Reentrancy 10
Reentrancy ● DAO 事件で有名 ● 正常系 ○ 残高を取得 ○ 送金しながら外部のコントラクトを呼び出し ○ 残高をクリア 11
Reentrancy ● 異常系 ○ 残高を取得 ○ 送金しながら外部のコントラクトを呼び出し ○ 外部のコントラクトで withdrawBalance を呼び出し ○ 送金しながら外部のコントラクトを呼び出し ○ 外部のコントラクトで withdrawBalance を呼び出し ○ 送金しながら外部のコントラクトを呼び出し ○ 外部のコントラクトで withdrawBalance を呼び出し ○ 送金しながら外部のコントラクトを呼び出し ○ 外部のコントラクトで withdrawBalance を呼び出し ○ (無限に送金してしまう) 12
Reentrancy ● 対策 ○ 極力外部のコントラクトを call しない ○ call するなら内部状態を変更し終わった後にする ■ withdrawBalance だと2行目と3行目を逆にする ○ call.value()() の代わりに send() を使うなどして用途を限定する 13
Front-Running 14
Front-Running ● トランザクションの取り込みの順番に起因する攻撃 ● Bob は持っているトークンX売り出し それを Alice が購入するケースを考える 15
Front-Running 1. BobはトークンXに 10ETH の売値をつける 2. AliceはトークンXを購入する トランザクション T1を発行する 3. Bobはそのトランザクション T1を見て トークンXの売値を 20ETH に変更する トランザクション T2を発行する 4. ブロックチェーンはT2, T1の順番でトランザクションを取り込む (gas代を調整することで可能) 5. Aliceは 20ETH でトークンXを購入してしまう 16
Front-Running ● 対策 ○ gas代に上限を設定 ■ Bob からの攻撃は防げる ■ マイナーからの攻撃は防げない ○ commit–reveal scheme ■ 公開情報を乱数値と一緒にハッシュ化 ■ 例 じゃんけん 1. ブロックチェーンでのじゃんけんは 手が丸見えなので後出しし放題 2. 乱数値とじゃんけんの手をハッシュ化 3. ハッシュ値を提出後、乱数値とじゃんけんの手を公開 4. 嘘をついていないかはハッシュ値によってわかる 17
Integer Overflow 18
Integer Overflow ● int型やuint型の桁あふれのこと ● uint 型に 2^256 + 1 を格納すると値は 0 ● Overflow が発生しうる状況は20通り ○ https://github.com/ethereum/solidity/issues/796#issuecomment-253578925 19
Integer Overflow ● 対策 ○ SafeMath を使う ■ https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol ■ Overflow のチェックが入った算術演算子を 関数として提供しているライブラリ 20
DoS with (Unexpected) revert 21
DoS with (Unexpected) revert ● 以下のようなコードで発生する ○ 悪意のある入札者が現れると それ以降誰も入札できなくなる 22
DoS with (Unexpected) revert ● 対策 ○ 入札と払い戻しのロジックを分離する ○ Pull over Push パターン と呼ばれる ■ 前のリーダーに返金する withdrawRefund 関数を用意 ● bid 関数とは別に呼ぶ 23
DoS with Block Gas Limit 24
DoS with Block Gas Limit ● トランザクションの実行に消費される gas が ブロックに設定されている gas limit を超えると トランザクションは失敗する ● 攻撃者によってトランザクションの実行に 必要な gas が増えてしまう問題 25
DoS with Block Gas Limit ● 対策 ○ 動的配列に対して for 文を回すことを避ける ○ Pull over Push パターンで実装 ○ gas を常に確認する (画像) 26
参考資料 27
参考資料 ● Ethereum Smart Contract Best Practices ○ https://consensys.github.io/smart-contract-best-practices/ ● Mastering Ethereum ○ https://github.com/ethereumbook/ethereumbook ● Solidity Patterns ○ https://fravoll.github.io/solidity-patterns/ ● スマートコントラクトのセキュリティ Part 1 – LoomNetwork JP – Medium ○ https://link.medium.com/fvdoXrFBAY 28
参考資料 ● Onward with Ethereum Smart Contract Security ○ https://blog.openzeppelin.com/onward-with-ethereum-smart-contract-security-97a827e47702/ ● Solidity Security: Comprehensive list of known attackvectors and common anti-patterns ○ https://blog.sigmaprime.io/solidity-security.html ● Dapper Ethereum Smart Contract Wallet: SecurityReview ○ https://blog.sigmaprime.io/dapper-wallet-review.html 29