SOQL インジェクション
他のプログラミング言語では、上記の弱点を SQL インジェクションといいます。Apex では SQL を使用しませんが、独自のデータベースクエリ言語 SOQL を使用します。SOQL は、SQL より単純で、機能が制限されています。そのため、SOQL インジェクションのリスクは SQL と比較して大幅に低くなりますが、攻撃は従来の SQL インジェクションとほぼ同じです。集計時は、SQL/SOQL インジェクションではユーザが提供した入力を取得し、これらの値を動的 SOQL クエリに使用します。入力が検証されない場合、SOQL ステートメントを事実上変更する SOQL コマンドを指定し、アプリケーションにトリックを仕掛けて意図しないコマンドを実行するようにします。
Apex での SOQL インジェクションの脆弱性
以下に SOQL に対して脆弱な Apex コードおよび Visualforce の単純な例を示します。
1<apex:page controller="SOQLController" >
2 <apex:form>
3 <apex:outputText value="Enter Name" />
4 <apex:inputText value="{!name}" />
5 <apex:commandButton value="Query" action="{!query}“ />
6 </apex:form>
7</apex:page>
8public class SOQLController {
9 public String name {
10 get { return name;}
11 set { name = value;}
12 }
13 public PageReference query() {
14 String qryString = 'SELECT Id FROM Contact WHERE ' +
15 '(IsDeleted = false and Name like \'%' + name + '%\')';
16 List<Contact> queryResult = Database.query(qryString);
17 System.debug('query result is ' + queryResult);
18 return null;
19 }
20}これは単純な例ですが、ロジックについて説明しています。コードは、削除されていない取引先責任者の検索を行うためのものです。ユーザは name という入力値を指定します。値はユーザが指定する任意の値で、検証されません。SOQL クエリは動的に構築され、Database.query メソッドで実行されます。ユーザが正当な値を指定すると、ステートメントは次のように期待どおり実行されます。
1// User supplied value: name = Bob
2// Query string
3SELECT Id FROM Contact WHERE (IsDeleted = false and Name like '%Bob%')ただし、次のようにユーザが予期しない値を入力したかのようになります。
この場合、クエリ文字列は次のようになります。
1// User supplied value for name: test%') OR (Name LIKE '1SELECT Id FROM Contact WHERE (IsDeleted = false AND Name LIKE '%test%') OR (Name LIKE '%')結果には削除されていない取引先責任者だけでなく、すべての取引先責任者が表示されます。SOQL インジェクションにより、脆弱なクエリの対象となるロジックを変更することができます。
SOQL インジェクションの防御策
SOQL インジェクションの攻撃を回避するには、動的 SOQL クエリを使用しないようにします。代わりに、静的クエリとバインド変数を使用します。上記の脆弱な例は、静的 SOQL を使用して次のように書き直すことができます。
1public class SOQLController {
2 public String name {
3 get { return name;}
4 set { name = value;}
5 }
6 public PageReference query() {
7 String queryName = '%' + name + '%';
8 List<Contact> queryResult = [SELECT Id FROM Contact WHERE
9 (IsDeleted = false and Name like :queryName)];
10 System.debug('query result is ' + queryResult);
11 return null;
12 }
13}動的 SOQL を使用する必要がある場合、escapeSingleQuotes メソッドを使用して、ユーザ指定の入力を削除します。このメソッドは、ユーザから渡される文字列のすべての単一引用符にエスケープ文字 (\) を追加します。このメソッドにより、すべての単一引用符を、データベースコマンドではなく、囲まれた文字列として処理します。