導入
Solana のプログラムは、渡されたアカウントを何でも信用してはいけません。誰でも任意のアカウント情報をトランザクションに詰め込んで送りつけることができるため、プログラム自身が「これは本当に正しい相手・正しいアカウントか」を毎回チェックする必要があります。これを怠ると、なりすましや資金の抜き取りにつながります。
説明
代表的な2つのチェックを見てみましょう。
1. 署名者チェック(is_signer チェック)
「このアカウントの持ち主が、本当にこの操作を許可したか」を確認します。
use solana_program::program_error::ProgramError;
if !signer.is_signer {
msg!("署名がありません");
return Err(ProgramError::MissingRequiredSignature);
}
もしこのチェックがないと、他人のカウンタアカウントを指定して「自分が署名した」と偽ることはできないものの、本来は所有者の同意が必要な操作を、無関係な第三者が勝手に実行できてしまう危険があります。「送金元は自分自身であるべきなのに、誰でも指定できてしまう」といった事故を防ぐのがこのチェックです。
2. 所有者チェック(owner チェック)
「渡されたデータアカウントが、本当に自分のプログラムが作った・管理しているアカウントか」を確認します。
if counter_account.owner != program_id {
msg!("このアカウントは自分のプログラムが所有していません");
return Err(ProgramError::IncorrectProgramId);
}
flowchart TD
A[渡されたアカウントを受け取る] --> B{is_signerはtrue?}
B -- いいえ --> E1["Err: MissingRequiredSignature<br/>(本人の許可がない)"]
B -- はい --> C{ownerはこのprogram_idと一致?}
C -- いいえ --> E2["Err: IncorrectProgramId<br/>(別プログラムのアカウント/偽物かもしれない)"]
C -- はい --> D[安全に処理を続行]
なぜこの2つが特に重要かというと、Solana では任意のアカウントのアドレスを、誰でも命令の中で指定できてしまうからです。悪意のあるクライアントが、まったく別のプログラムが管理しているアカウントや、他人のアカウントを紛れ込ませてくる可能性があります。所有者チェックを忘れると、「見た目はカウンタのデータに見えるが、実は別プログラムが作った・改ざんされた偽物のデータ」を信用して処理してしまう、といった脆弱性につながります。
演習
もし「所有者チェック」を省略したプログラムがあったとして、悪意のある人はどんな入力を送りつけて悪用できそうか、具体的なシナリオを想像してみましょう。
ヒント1を見る
counter_account として、本来のプログラムとは無関係な別のアカウント(自分で自由に中身を作れるアカウント)を指定したらどうなるでしょうか。
ヒント2を見る
プログラムは「data の中身が CounterAccount の形をしていれば」信用してしまいます。中身が本物かどうかは owner チェックがなければ分かりません。