入力の検証や表現の問題は、メタキャラクター、代替エンコーディング、数値表現などによって引き起こされます。セキュリティの問題は、入力を信頼することに起因します。この問題に含まれるのは、「Buffer Overflow」、「Cross-Site Scripting」攻撃、「SQL Injection」などです。
owner
が一致するアイテムだけが表示されます。
...
string userName = ctx.GetAuthenticatedUserName();
string query = "SELECT * FROM items WHERE owner = '"
+ userName + "' AND itemname = '"
+ ItemName.Text + "'";
List items = sess.CreateSQLQuery(query).List();
...
SELECT * FROM items
WHERE owner = <userName>
AND itemname = <itemName>;
ItemName
に単一引用符が含まれない場合のみクエリは正しく動作します。ユーザー名 wiley
を持つ攻撃者が文字列「name' OR 'a'='a
」を ItemName
に入力すると、クエリは次のようになります。
SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name' OR 'a'='a';
OR 'a'='a'
条件を追加すると、where 句は常に真 (true) の評価を行います。そのため、このクエリは次のような単純なクエリと論理的に等しくなります。
SELECT * FROM items;
items
テーブルに格納されているすべてのエントリを返すようになりました。Example 1
で構築および実行されたクエリに悪意のある別の値が渡された場合の影響を検討します。ユーザー名 wiley
を持つ攻撃者が文字列「name'; DELETE FROM items; --
」を ItemName
に入力すると、クエリは次の 2 つのクエリになります。
SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name';
DELETE FROM items;
--'
Example 1
と同様の技法を使用すると一般的な攻撃を有効にできます。攻撃者が文字列「name'; DELETE FROM items; SELECT * FROM items WHERE 'a'='a
」を入力すると、次の 3 つの有効なステートメントが作成されます。
SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name';
DELETE FROM items;
SELECT * FROM items WHERE 'a'='a';
owner
が一致するアイテムだけが表示されます。
...
string userName = identity.User;
string itemName = apiGatewayProxyRequest.QueryStringParameters['item'];
string statement = $"SELECT * FROM items WHERE owner = '{userName}' AND itemname = '{itemName}'";
var executeStatementRequest = new ExecuteStatementRequest();
executeStatementRequest.Statement = statement;
var executeStatementResponse = await dynamoDBClient.ExecuteStatementAsync(executeStatementRequest);
return displayResults(executeStatementResponse.Items);
...
SELECT * FROM items
WHERE owner = <userName>
AND itemname = <itemName>;
itemName
に単一引用符が含まれない場合のみクエリは正しく動作します。ユーザー名 wiley
を持つ攻撃者が文字列「name' OR 'a'='a
」を itemName
に入力すると、クエリは次のようになります。
SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name' OR 'a'='a';
OR 'a'='a'
条件を追加すると、where 句は常に真 (true) の評価を行います。そのため、このクエリは次のような単純なクエリと論理的に等しくなります。owner
が一致するアイテムだけが表示されます。
...
String userName = identity.getUser();
String itemName = apiGatewayProxyRequest.getQueryStringParameters('item');
String statement = String.format("SELECT * FROM items WHERE owner = '%s' AND itemname = '%s'", userName, itemName);
ExecuteStatementRequest executeStatementRequest = new ExecuteStatementRequest();
executeStatementRequest.setStatement(statement);
ExecuteStatementResponse executeStatementResponse = dynamoDBClient.executeStatement(executeStatementRequest);
return displayResults(executeStatementResponse.items());
...
SELECT * FROM items
WHERE owner = <userName>
AND itemname = <itemName>;
itemName
に単一引用符が含まれない場合のみクエリは正しく動作します。ユーザー名 wiley
を持つ攻撃者が文字列「name' OR 'a'='a
」を itemName
に入力すると、クエリは次のようになります。
SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name' OR 'a'='a';
OR 'a'='a'
条件を追加すると、where 句は常に真 (true) の評価を行います。そのため、このクエリは次のような単純なクエリと論理的に等しくなります。
...
String userName = ctx.getAuthenticatedUserName();
String itemName = request.getParameter("itemName");
String query = "SELECT * FROM items WHERE owner = '"
+ userName + "' AND itemname = '"
+ itemName + "'";
ResultSet rs = stmt.execute(query);
...
SELECT * FROM items
WHERE owner = <userName>
AND itemname = <itemName>;
itemName
に単一引用符が含まれない場合のみクエリは正しく動作します。ユーザー名 wiley
を持つ攻撃者が文字列「name' OR 'a'='a
」を itemName
に入力すると、クエリは次のようになります。
SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name' OR 'a'='a';
OR 'a'='a'
条件を追加すると、where 句は常に真 (true) の評価をします。そのため、このクエリは次のような単純なクエリと論理的に等しくなります。
SELECT * FROM items;
items
テーブルに格納されているすべてのエントリを返すようになりました。Example 1
で構築および実行されたクエリに悪意のある別の値が渡された場合の影響を検討します。ユーザー名 wiley
を持つ攻撃者が文字列「name'; DELETE FROM items; --
」を itemName
に入力すると、クエリは次の 2 つのクエリになります。
SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name';
DELETE FROM items;
--'
Example 1
と同様の技法を使用すると一般的な攻撃を有効にできます。攻撃者が文字列「name'); DELETE FROM items; SELECT * FROM items WHERE 'a'='a
」を入力すると、次の 3 つの有効なステートメントが作成されます。
SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name';
DELETE FROM items;
SELECT * FROM items WHERE 'a'='a';
Example 1
を応用しています。
...
PasswordAuthentication pa = authenticator.getPasswordAuthentication();
String userName = pa.getUserName();
String itemName = this.getIntent().getExtras().getString("itemName");
String query = "SELECT * FROM items WHERE owner = '"
+ userName + "' AND itemname = '"
+ itemName + "'";
SQLiteDatabase db = this.openOrCreateDatabase("DB", MODE_PRIVATE, null);
Cursor c = db.rawQuery(query, null);
...
mysql_real_escape_string()
などのエンコーディング関数を使用すると、ある程度は SQL Injection の脆弱性に対する攻撃を防ぐことはできますが、完全に防ぐことはできません。このようなエンコーディング関数に頼ることは、脆弱な拒否リストを使用して SQL Injection を阻止しようとするのと同じことであり、攻撃者によるステートメントの改変や任意の SQL コマンドの実行が可能となる場合があります。動的に解釈されるコードの特定のセクション内のどこに入力が現れるのかを静的に判断することは必ずしも可能ではないため、Fortify Secure Coding Rulepacks は検証された動的 SQL データを「SQL Injection: Poor Validation」の問題として提示します。これは、検証によってコンテキスト内での SQL Injection を十分に防ぐことができるとしても同様です。mysqli_real_escape_string()
の動作が変更される場合について示したものです。 SQL モードが「NO_BACKSLASH_ESCAPES」に設定されている場合、バックスラッシュ文字はエスケープ文字ではなく、通常の文字として扱われます [5]。 mysqli_real_escape_string()
はこのことを考慮するため、次のクエリは SQL Injection に対して脆弱となります。これは、データベースの設定によって "
が \"
にエスケープされなくなるためです。
mysqli_query($mysqli, 'SET SQL_MODE="NO_BACKSLASH_ESCAPES"');
...
$userName = mysqli_real_escape_string($mysqli, $_POST['userName']);
$pass = mysqli_real_escape_string($mysqli, $_POST['pass']);
$query = 'SELECT * FROM users WHERE userName="' . $userName . '"AND pass="' . $pass. '";';
$result = mysqli_query($mysqli, $query);
...
password
フィールドを空白のままにして、userName
に対して " OR 1=1;--
と入力すると、引用符はエスケープされず、クエリの結果は次のようになります。
SELECT * FROM users
WHERE userName = ""
OR 1=1;
-- "AND pass="";
OR 1=1
によって where 句は常に真 (true) の評価を行い、二重ハイフンによってステートメントの残りの部分はコメントとして扱われるため、このクエリは次のような単純なクエリと論理的に等しくなります。
SELECT * FROM users;
owner
が一致するアイテムだけが表示されます。
...
string userName = ctx.getAuthenticatedUserName();
string query = "SELECT * FROM items WHERE owner = '"
+ userName + "' AND itemname = '"
+ ItemName.Text + "'";
IDataReader responseReader = new InlineQuery().ExecuteReader(query);
...
SELECT * FROM items
WHERE owner = <userName>
AND itemname = <itemName>;
itemName
に単一引用符が含まれない場合のみクエリは正しく動作します。ユーザー名 wiley
を持つ攻撃者が文字列「name' OR 'a'='a
」を itemName
に入力すると、クエリは次のようになります。
SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name' OR 'a'='a';
OR 'a'='a'
条件を追加すると、where 句は常に真 (true) の評価を行います。そのため、このクエリは次のような単純なクエリと論理的に等しくなります。
SELECT * FROM items;
items
テーブルに格納されているすべてのエントリを返すようになりました。Example 1
で構築および実行されたクエリに悪意のある別の値が渡された場合の影響を検討します。ユーザー名 wiley
を持つ攻撃者が文字列「name'); DELETE FROM items; --
」を itemName
に入力すると、クエリは次の 2 つのクエリになります。
SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name';
DELETE FROM items;
--'
Example 1
と同様の技法を使用すると一般的な攻撃を有効にできます。攻撃者が文字列「name'); DELETE FROM items; SELECT * FROM items WHERE 'a'='a
」を入力すると、次の 3 つの有効なステートメントが作成されます。
SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name';
DELETE FROM items;
SELECT * FROM items WHERE 'a'='a';