問題
開発者は、システムに存在する ContactSearchApexクラスのセキュリティレビューを実行するよう命じられました。このクラスの中で、開発者は以下のメソッドがセキュリティ上の脅威であることを特定しました。
List<Contact> performSearch(String lastName) {
return Database.query('Select Id, FirstName, LastName FROM Contact WHERE LastName Like%' + lastName +'%');
}
SOQL インジェクション攻撃を防ぐために、開発者がメソッドを改善できる方法は何ですか。2つ選びなさい。
- クラスに@ReadOnlyアノテーションとwith sharingキーワードを使用する。
- escapeSingleQuotes メソッドを使用して、使用前にパラメータをサニタイズする。
- パラメータに正規表現式を使用して特殊文字を削除する。
- 変数バインディングを使用し、動的クエリを静的SOQLに置き換える。
正解
- クラスに@ReadOnlyアノテーションとwith sharingキーワードを使用する。
- escapeSingleQuotes メソッドを使用して、使用前にパラメータを消去する。
- パラメータに正規表現式を使用して特殊文字を削除する。
- 変数バインディングを使用し、動的クエリを静的SOQLに置き換える。
解説
現在のコード
List<Contact> performSearch(String lastName) {
return Database.query('Select Id, FirstName, LastName FROM Contact WHERE LastName Like%' + lastName +'%');
}
の中で、Database.query('Select Id, FirstName, LastName FROM Contact WHERE LastName Like%' + lastName +'%');
の部分が危険です。
理由は以下の通りです。
- 動的クエリの使用:
lastName
というユーザーからの入力を直接動的クエリに組み込んでいます。これにより、悪意のあるユーザーが特定の文字列をlastName
に入力することで、クエリの意味を変更する可能性があります。 - サニタイズの不足:ユーザーからの入力
lastName
がサニタイズや検証を受けずに直接クエリに組み込まれています。これにより、SOQLインジェクション攻撃が可能となります。
具体的には、ユーザーがlastName
として”test%') OR (Name LIKE '
“のような値を入力すると、意図しないすべてのContactレコードを取得するクエリが生成される可能性があります。
それぞれの選択肢の理由について説明します。
□ クラスに@ReadOnlyアノテーションとwith sharingキーワードを使用する。
これは不正解です。 @ReadOnly
アノテーションはトランザクションが読み取り専用であることを指示し、リソースの制限を緩和するために使用されますが、SOQLインジェクション攻撃を防ぐものではありません。with sharing
キーワードはレコードの可視性に基づいて実行を制御するもので、セキュリティを強化する可能性はありますが、SOQLインジェクションそのものを防ぐものではないため、ここでは不適切です。
□ escapeSingleQuotes メソッドを使用して、使用前にパラメータを消去する。
これは正解です。escapeSingleQuotes()
メソッドは、文字列内のシングルクォートをエスケープしてSOQLインジェクション攻撃を防ぐために使用されます。このメソッドを使用することで、攻撃者が有害なSOQLを注入するリスクを軽減できます。
□ パラメータに正規表現式を使用して特殊文字を削除する。
これは不正解です。 正規表現を使用して特殊文字を削除することは一種のサニタイズと見なすことができますが、攻撃者がSOQLインジェクションを実行するために使う可能性のある特定の文字列パターンを除去するためには、非常に複雑で確実な正規表現が必要になります。これは一般的な解決策として推奨されず、エスケープ処理に比べて安全ではありません。
□ 変数バインディングを使用し、動的クエリを静的SOQLに置き換える。
これは正解です。変数バインディングを使用して静的なSOQLクエリに変換することで、SOQLインジェクションのリスクを取り除くことができます。これにより、Apexが提供するクエリの文字列を適切に処理し、ユーザーが提供した値を安全に使うことができるようになります。
正解の選択肢を使用したコードの改善例:
List<Contact> performSearch(String lastName) {
lastName = String.escapeSingleQuotes(lastName);
return [Select Id, FirstName, LastName FROM Contact WHERE LastName LIKE :('%' + lastName + '%')];
}
このコードでは、String.escapeSingleQuotes() メソッドを使用してlastNameをサニタイズし、変数バインディングを使用してクエリを実行しています。
コメント