Back to Blog

Solanaエコシステムを守る(4)— アカウント検証

2022年4月1日
6 min read

0. レビュー

1. 概要

前回のブログでは、プログラムのアップグレード方法について説明しました。今回の投稿では、DeFi分野において最も一般的かつ基本的なセキュリティトピックの一つであるアクセス制御に関連する問題を紹介します。

2. インストラクション

Solanaでは、各プログラムはentrypoint!で定義された単一のentrypointをエクスポートします。Ethereumとは異なり、クライアントはentrypointとして定義された単一の関数(通常process_instructionと呼ばれる)しか呼び出すことができません。entrypoint関数は3つのパラメータを受け取ります。それらはスマートコントラクトのプログラムID、プログラムが操作するアカウント、そしてインストラクションデータです。インストラクションデータはどのインストラクションが呼び出されるかを指定します。以下の図はその例を示しています。インストラクションデータをアンパックすることで、異なるインストラクション(例:Lock、Unlock)が選択されます。したがって、entrypointから到達できるインストラクションは誰にでも公開されており、指定されたインストラクションデータで実行できます。

3. アカウントの検証

前述のとおり、プログラムは読み取りまたは書き込みが必要なアカウントを受け取ります。この設計により2つの問題が生じます。読み取られるアカウントについては、アカウントに保存されているデータが信頼できることをどのように保証するか。書き込まれるアカウントについては、権限を持つユーザーのみがアカウントへの書き込みインストラクションを呼び出せることをどのように保証するか。以下では、アクセス制御の問題を説明します。すべてのテストコードはこちらで確認できます。

3.1 コードレビュー (PrivilegeOwner)

まずDoorとConfigという2つの構造体を定義します。構造体doorで指定されたkeyアカウント(17行目)のみが作成されたdoorを開くことができます。ただし、構造体Config(81行目)で指定されたシステム状態がロックされている場合、ドアを開くことはできません。

前述のとおり、Configアカウントはドアを開けるかどうかを指定します。この場合、プログラム内にConfigアカウントは1つだけ存在する必要があります。これを実現するために、PDAを使用してConfigのデータを保存します。Configアカウントを初期化した後、攻撃者によって再初期化されないよう属性is_initializedをtrueに設定します(108行目〜110行目)。

インストラクションOpen()はドアを開くために使用されます。このインストラクションは、開くべきドアアカウント、configアカウント、およびdoorを開こうとするownerアカウントを含む複数のアカウントを受け取ります。ドアがプログラムに属し設定が有効であることを保証するために、doorアカウントとconfigアカウントのオーナーを確認します(204行目〜205行目)。これにより、悪意あるユーザーが偽のアカウントを渡すことを防ぎます。これが最初の質問への答えです。読み取られるアカウントが信頼できることを保証するには、アカウントのオーナーを確認する必要があります!doorアカウントのオーナーのみがドアを開くことができることに注意してください。この場合、ownerアカウントがdoorの実際のownerであるかどうか、そして重要なことに、インストラクションがオーナーによって承認されているかどうかを確認します(217行目〜219行目)。

関数validate_owner()では、まず2つのアカウントの公開鍵が同じかどうかを確認し、次にオーナーの署名を確認します。これが2番目の質問への答えです。権限を持つユーザーのみがopenインストラクションを呼び出せることを保証するには、アカウントのオーナーと署名者を確認する必要があります。closeインストラクションはopenと同様であり、詳細はコードで確認できます。

プログラムをテストネットにデプロイしました。以下のリンクで確認できます。

https://explorer.solana.com/address/2Q7FFMWCthBvc6ubLQRx9TRswvaimmd66VaCAfHwsYuC?cluster=testnet

すべてのテストトランザクションを以下に示します。このトランザクションの全体的なプロセスは AllocatePDA()-> InitializeDoor()-> InitializeConfig()-> Unlock() -> Open() -> Close() です。

https://explorer.solana.com/tx/2X9CyMrHTNEvbzXTE95gem2j8spnvsQsabFeSpV8hiNpYjiQPPzLRqt5KN86ZYRjnQvydvs7y5eUjJK7no8knDhk?cluster=testnet
https://explorer.solana.com/tx/2XfVWiXeQeHbpqAEYm3AH2RU6hunnqtr155EC4EAM5Bq9VVZNP6QocAav9cPjEQdJFcQrbsSSxiKadr4HPMov8pz?cluster=testnet
https://explorer.solana.com/tx/5Em41sg7yFXeNpnEJnhUQJanfLWKwjMqiBeNAqEEzFrSN9P8zKKafcv5F7RKT2pseB171qeoa8Uz4fKgazzayCnW?cluster=testnet
https://explorer.solana.com/tx/2PMtzpSgjnKDLGmRWBdUSFBPimWnudCPekUYbWzPzokENFYa4N4ab4HCtynfGrzswFPTgGYKHU8PccUMHv3mXHkR?cluster=testnet
https://explorer.solana.com/tx/3kviP9MqkWGMV4yA7k7yPQ5BGfXmcYLcctmY1u2D7n56eT1nx8jMtDumkUNJy8yA3KkmzrmfQLjqpigc8ehGZzBN?cluster=testnet
https://explorer.solana.com/tx/38iEaJBzuGMLbfcszdVB8pkniezH8JrA3XGq7JdADZTQ4hNQC82GSTUA2bmcypdVy3t7htWnUzkZ4F8EakmNvqz8?cluster=testnet

3.2 攻撃トランザクション

オーナーチェックと署名者チェックの重要性を示すために、2つの攻撃シナリオを例として使用します。

最初のシナリオ

1つ目は、configがロックされている状態でドアのオーナーがドアを開こうとするケースです。これを実現するために、別のプログラムに偽のconfigアカウントを作成し、属性is_lockに値falseを割り当てます。カスタムプログラムのコードを以下に示します。

偽のconfigアカウントを作成するトランザクションを送信します。偽のconfigアカウントの公開鍵は: 2MtSrbWp24VjPZQcSUkiWrvNro7qqKemVCsh3Yxc8LTy です。

https://explorer.solana.com/tx/2qSyrL5gdQXmgGCFzmzMm1StFQRkDgWpss9A9jV11q2fgDGM5C1XRuXvbX1N5Dt3q2pRqnmyXHVtXGF5dqadAzpJ?cluster=testnet

偽のconfigアカウントが作成されたら、それをプログラムに渡します(423行目)。

結果を以下に示します。ログにはincorrect program id for instructionと表示されており、configアカウントのオーナーはそのプログラムでなければならないことを意味します。したがって、攻撃者はこのチェックを回避できません。

2番目のシナリオ

2番目のシナリオは、悪意あるユーザーがドアのロックが解除されている状態でドアを開こうとするケースです。

この場合、実際のオーナーアカウントをプログラムに渡し(419行目)、トランザクションを送信します。結果を以下に示します。

Signature verification failedと表示されており、ドアを開くには実際のオーナーがトランザクションに署名しなければならないことを意味します。したがって、2番目の攻撃も失敗します。

4. まとめ

Solanaでは、インストラクションはクライアントまたは他のプログラムから渡された異なるアカウントに基づいて指定されたロジックを実装します。そのため、アカウントの適切なチェックは非常に重要です。

この記事では、アカウントを適切にチェックする方法を紹介し、2つの攻撃シナリオを使用してこれらのチェックの重要性を説明しました。引き続きご覧ください。今後もさらに多くの記事を共有していきます。

このシリーズの他の記事を読む:


BlockSecについて

BlockSecは、世界的に著名なセキュリティ専門家のグループによって2021年に設立された先駆的なブロックチェーンセキュリティ企業です。同社は、大規模な普及を促進するために、新興のWeb3世界のセキュリティとユーザビリティの向上に取り組んでいます。そのために、BlockSecはスマートコントラクトおよびEVMチェーンのセキュリティ監査サービス、セキュリティ開発と脅威のプロアクティブなブロッキングのためのPhalconプラットフォーム、資金追跡と調査のためのMetaSleuthプラットフォーム、そして暗号世界を効率的に閲覧するweb3ビルダー向けのMetaSuites拡張機能を提供しています。

現在までに、同社はMetaMask、Uniswap Foundation、Compound、Forta、PancakeSwapなど300社以上の著名なクライアントにサービスを提供し、Matrix Partners、Vitalbridge Capital、Fenbushi Capitalなどの著名な投資家から2回の資金調達ラウンドで数千万米ドルを調達しています。

公式ウェブサイト: https://blocksec.com/

公式Twitterアカウント: https://twitter.com/BlockSecTeam

Sign up for the latest updates
約387万 USDの損失:Autheo NetworkとUNCXへのハッキング | BlockSecウィークリー
Security Insights

約387万 USDの損失:Autheo NetworkとUNCXへのハッキング | BlockSecウィークリー

この週次レポートでは、2026年10月12日–2026年10月18日に発生した3件のセキュリティインシデントを取り上げます。推定損失額の合計は約387万 USDです。Autheo Networkでは秘密鍵の侵害により約176万 USD、Qubic Walletでは脆弱なシード生成により約130万 USDの損失が発生しました。また、Ethereum、BNB Chain、Base、Robinhood Chain上のUNCX NetworkのSmart Token Vesting V2コントラクトでは、会計処理上の誤りにより約80.7万 USDの損失が発生しました。重点的に取り上げるUNCXの分析では、シェア総数の計算に欠陥があり、異なるトークン対シェア比率で作成されたベスティングのトランシェが混同された結果、共通プールからの過剰な引き出しが可能になった仕組みを説明します。

SEAL認証とは?暗号資産における運用セキュリティの保証
Security Insights

SEAL認証とは?暗号資産における運用セキュリティの保証

SEAL認証は、合意された範囲内で暗号資産分野の運用セキュリティについて独立した保証を提供します。その6つのモジュール、証拠資料の要件、認証の限界、BlockSecの評価プロセスを解説します。

約54万2,000ドルの損失:MakerDaoBotへの攻撃 | BlockSec週間ニュース
Security Insights

約54万2,000ドルの損失:MakerDaoBotへの攻撃 | BlockSec週間ニュース

本レポートは2026/10/05~10/11にEthereumで発生したセキュリティ事故1件を扱う。推定損失は約54.2万ドル。攻撃コントラクトは悪意あるアダプターを展開し、アクセス制御のないMakerDaoBot関数に渡して、ボット内部のMakerDAO残高への操作権限を付与させた。アダプターは旧ETH-Aオークション4件を決済し、ETH-A担保200単位をWETHに変換。攻撃コントラクトがWETHをETHに戻し、攻撃者へ200 ETHを送金した。