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 メソッドを使用して、ユーザー指定の入力を削除します。このメソッドは、ユーザーから渡される文字列のすべての単一引用符にエスケープ文字 (\) を追加します。このメソッドにより、すべての単一引用符を、データベースコマンドではなく、囲まれた文字列として処理します。