スマートコントラクトに対するセキュリティ・ガイドライン
Solidity
スマートコントラクト
セキュリティ
中級
以下に挙げる主な推奨事項を遵守することで、よりセキュアなスマートコントラクト開発が実現します。
設計ガイドライン
まず、コードを書く前に、コントラクトの設計について十分に議論を深める必要があります。
ドキュメントと仕様
ドキュメンテーションは様々な水準で作成でき、コントラクトの実装時に内容を修正する必要があります。
- システムの平易な英語による説明。コントラクトが何を行い、コードベースにどのような前提条件があるかを記述します。
- スキーマとアーキテクチャ図。コントラクト間の相互作用やシステムの状態マシンを含みます。 Slitherプリンター (opens in a new tab)は、これらのスキーマの生成に役立ちます。
- 徹底的なコードドキュメント。SolidityではNatspec形式 (opens in a new tab)が使用できます。
オンチェーン計算とオフチェーン計算
- **できるだけ多くのコードをオフチェーンに置いてください。**オンチェーンレイヤーは小さく保ちます。 オンチェーンでの検証がシンプルになるように、オフチェーンのコードでデータを前処理します。 順序付きリストが必要か確認します。 必要な場合は、オフチェーンでリストをソートしてから、オンチェーンでは順序のみをチェックするようにします。
アップグレード可能性
私たちのブログ投稿 (opens in a new tab)で、さまざまなアップグレード可能性のソリューションについて説明しました。 コード開発を開始する事前に、アップグレードに対応するか否かをはっきり決定してください。 この決定により、どのような構造のコードを開発するべきかが変わってきます。 一般論として、以下を推奨します:
- **アップグレード可能性よりもコントラクトのマイグレーション (opens in a new tab)を優先すること。**マイグレーションシステムはアップグレード可能なシステムと同じ利点の多くを持ちながら、その欠点はありません。
- delegatecallproxyパターンよりもデータ分離パターンを使用すること。 プロジェクトに明確な抽象化分離がある場合、データ分離を使用したアップグレードは、わずかな調整しか必要ありません。 委任呼び出しのプロキシ は、EVMの知識が必要であり、エラー発生の頻度が高まります。
- デプロイ前に、移行/アップグレードの手順を文書化すること。 ガイドラインがない状態でストレス下で対応しなければならない場合、ミスを犯すでしょう。 遵守すべき手順を前もって策定しておきましょう。 具体的には、以下を定めます:
- 新たなコントラクトを開始する呼び出し。
- キーの保存場所と、アクセス方法。
- デプロイの確認方法。 デプロイ後のスクリプトを開発、テストしておきます。
実装ガイドライン
**シンプルさを追求すること。**常に目的に合った最もシンプルなソリューションを使用してください。 あなたのソリューションは、チーム全員が理解できるものでなければなりません。
関数の構成
コードベースのアーキテクチャは、レビューしやすいものでなければなりません。 コードの正確性を判定しにくくするようなアーキテクチャ関連の決定は避けてください。
- **システムのロジックを分割すること。**複数のコントラクトに分けるか、類似した関数(例: 認証、算術演算など)をグループ化します。
- 明確な目的を持つ小さな関数を書くこと。 これにより、レビューが容易になり、個々のコンポーネントのテストが可能になります。
継承
- **継承を管理可能なものに保つこと。**継承はロジックを分割するために使用すべきですが、プロジェクトでは継承ツリーの深さと幅を最小限に抑えることを目指すべきです。
- Slitherの継承プリンター (opens in a new tab)を使用してコントラクトの階層を確認してください。 継承プリンターは、階層のサイズを確認するのに役立ちます。
イベント
- すべての重要な操作をログに記録してください。 イベントは、開発中のコントラクトのデバッグやデプロイ後の監視に役立ちます。
既知の落とし穴を避ける
- 最も一般的なセキュリティ問題に注意してください。 Ethernaut CTF (opens in a new tab)、Capture the Ether (opens in a new tab)、Not so smart contracts (opens in a new tab)など、一般的な問題について学ぶためのオンラインリソースはたくさんあります。
- Solidityドキュメント (opens in a new tab)の警告セクションに注意してください。 警告セクションは、言語の自明でない挙動について知らせてくれます。
依存関係
- 十分にテストされたライブラリを使用すること。 十分にテストされたライブラリからコードをインポートすることで、バグの多いコードを書く可能性が低くなります。 ERC20コントラクトを書きたい場合は、OpenZeppelin (opens in a new tab)を使用してください。
- 依存関係マネージャーを使用し、コードのコピー&ペーストは避けてください。 外部ソースに依存する場合は、元のソースに合わせて最新の状態に保つ必要があります。
テストと検証
- 徹底的な単体テストを書くこと。 広範なテストスイートは、高品質なソフトウェアを構築するために不可欠です。
- Slither (opens in a new tab)、Echidna (opens in a new tab)、Manticore (opens in a new tab)のカスタムチェックとプロパティを記述すること。 自動化ツールは、コントラクトの安全性を確保するのに役立ちます。 効率的なチェックおよびプロパティを作成するには、本ガイドの該当記事を参照してください。
- **crytic.io (opens in a new tab)を使用してください。**CryticはGitHubと統合されており、プライベートなSlither検出器へのアクセスを提供し、Echidnaからカスタムプロパティチェックを実行します。
Solidity
- Solidityは0.4や0.6よりも0.5を優先すること。 私たちの意見では、Solidity 0.5は0.4よりも安全で、より優れた組み込みプラクティスを備えています。 一方、0.6は現時点において本番環境の使用に耐えうる安定性を持たず、さらなるアップデートが必要な状態です。
- コンパイルには安定版リリースを使用し、警告のチェックには最新リリースを使用すること。 最新のコンパイラバージョンでコードに問題が報告されないことを確認してください。 しかし、Solidityはリリースサイクルが速く、コンパイラのバグの履歴があるため、デプロイに最新バージョンを使用することはお勧めしません(Slitherのsolcバージョン推奨 (opens in a new tab)を参照)。
- インラインアセンブリは使用しないこと。 アセンブリにはEVMの専門知識が必要です。 イエローペーパーを_マスター_していない場合は、EVMコードを書かないでください。
デプロイガイドライン
コントラクトの開発が完了し、デプロイしたら、以下を確認します:
- コントラクトを監視してください。 ログを監視し、コントラクトやウォレットが不正利用された場合に備えて、対応できるようにしておきましょう。
- 連絡先情報をblockchain-security-contacts (opens in a new tab)に追加してください。 このリストは、セキュリティ上の欠陥が発見された場合に第三者があなたに連絡するのに役立ちます。
- 権限のあるユーザーのウォレットを保護すること。 ハードウェアウォレットにキーを保管する場合は、私たちのベストプラクティス (opens in a new tab)に従ってください。
- インシデント対応計画を準備しておくこと。 スマートコントラクトが侵害される可能性があることを考慮してください。 開発したコントラクトにバグが含まれていない場合でも、攻撃者はコントラクト所有者の鍵を悪用しようとする可能性があります。
最終更新: 2025年9月30日