SQLインジェクション
SQLインジェクションは、データベースを破壊する可能性のあるコードインジェクション手法です。
SQLインジェクションは、最も一般的なWebハッキング手法の 1 つです。
SQLインジェクションは、Webページの入力を介して、SQLステートメントに悪意のあるコードを配置することです。
WebページのSQL
SQLインジェクションは通常、ユーザーにユーザー名やユーザーIDのような入力を求めたときに発生します。
変数(txtUserId)をselect文字列に追加してSELECT文を作成する次の例を見てください。この変数は、ユーザー入力(getRequestString)から取得されます。
例
txtUserId = getRequestString("UserId");
txtSQL = "SELECT *FROM Users WHERE UserId = " + txtUserId;
この章の残りの部分では、SQLステートメントでユーザー入力を使用することの潜在的な危険性について説明します。
1=1が常にTrueであることに基づくSQLインジェクション
上の例をもう一度見てください。このコードの本来の目的は、特定のユーザーIDを持つユーザーを選択するためのSQL文を作成することです。
ユーザーが「間違った」入力をするのを防ぐものが何もない場合、ユーザーは次のような「スマートな」入力を入力できます。
ユーザーID:105 OR 1=1
次に、SQLステートメントは次のようになります。
SELECT * FROM Users WHERE UserId = 105 OR 1=1;
上記のSQLは有効であり、"Users"テーブルからすべての行を返します。または 1=1は常にTrueです。
上記の例は危険に見えますか? 「Users」テーブルに名前とパスワードが含まれている場合はどうなりますか?
上記のSQLステートメントは、次のステートメントとほとんど同じです。
SELECT UserId, Name, PasswordFROM Users WHERE UserId = 105 or 1=1;
ハッカーは、入力フィールドに105 OR 1=1を挿入するだけで、データベース内のすべてのユーザー名とパスワードにアクセスできる可能性があります。
""=""に基づくSQLインジェクションは常にTrue
Webサイトでのユーザー ログインの例を次に示します。
ユーザー名:John Doe
パスワード:myPass
例
uName = getRequestString("username");
uPass = getRequestString("userpassword");
sql = 'SELECT * FROM Users WHERE Name ="' + uName + '" AND Pass ="' + uPass + '"'
結果
SELECT * FROM Users WHERE Name ="John Doe" AND Pass ="myPass"
ハッカーは、ユーザー名またはパスワードのテキスト ボックスに「 OR ""=" 」を挿入するだけで、データベース内のユーザー名とパスワードにアクセスできる可能性があります。
ユーザー名:" or ""="
パスワード:" or ""="
サーバーのコードは、次のような有効なSQLステートメントを作成します。
結果
SELECT * FROM Users WHERE Name ="" or ""="" AND Pass ="" or ""=""
上記のSQLは有効であり、"Users"テーブルからすべての行を返します。または ""=""は常にTrueです。
バッチ化されたSQLステートメントに基づくSQLインジェクション
ほとんどのデータベースは、バッチSQLステートメントをサポートしています。
SQLステートメントのバッチは、セミコロンで区切られた2つ以上のSQLステートメントのグループです。
以下のSQLステートメントは、"Users"テーブルからすべての行を返し、"Suppliers"テーブルを削除します。
例
SELECT * FROM Users; DROP TABLE Suppliers
次の例を見てください。
例
txtUserId = getRequestString("UserId");
txtSQL = "SELECT *FROM Users WHERE UserId = " + txtUserId;
そして、次の入力:
ユーザーID:105; DROP TABLE Suppliers
有効なSQLステートメントは次のようになります。
結果
SELECT * FROM Users WHERE UserId = 105; DROP TABLE Suppliers;
保護のためにSQLパラメータを使用する
WebサイトをSQLインジェクションから保護するために、SQLパラメータを使用できます。
SQLパラメータは、実行時に制御された方法で SQLクエリに追加される値です。
ASP.NET Razor の例
txtUserId = getRequestString("UserId");
txtSQL = "SELECT *FROM Users WHERE UserId = @0";
db.Execute(txtSQL,txtUserId);
パラメータは、@マーカーによってSQLステートメントで表されることに注意してください。
SQLエンジンは、各パラメーターをチェックして、その列に対して正しく、実行されるSQLの一部としてではなく、文字どおりに処理されることを確認します。
もう一つの例
txtNam = getRequestString("CustomerName");
txtAdd = getRequestString("Address");
txtCit = getRequestString("City");
txtSQL = "INSERT INTO Customers (CustomerName,Address,City) Values(@0,@1,@2)";
db.Execute(txtSQL,txtNam,txtAdd,txtCit);
例
次の例は、いくつかの一般的なWeb言語でパラメーター化されたクエリを作成する方法を示しています。
ASP.NETのSELECTステートメント:
txtUserId = getRequestString("UserId");
sql = "SELECT * FROM Customers WHERE CustomerId = @0";
command = new SqlCommand(sql);
command.Parameters.AddWithValue("@0",txtUserId);
command.ExecuteReader();
ASP.NETのステートメントに挿入:
txtNam = getRequestString("CustomerName");
txtAdd = getRequestString("Address");
txtCit = getRequestString("City");
txtSQL = "INSERT INTO Customers (CustomerName,Address,City) Values(@0,@1,@2)";
command = new SqlCommand(txtSQL);
command.Parameters.AddWithValue("@0",txtNam);
command.Parameters.AddWithValue("@1",txtAdd);
command.Parameters.AddWithValue("@2",txtCit);
command.ExecuteNonQuery();
PHPのステートメントに挿入:
$stmt = $dbh->prepare("INSERT INTO Customers (CustomerName,Address,City)
VALUES (:nam, :add, :cit)");
$stmt->bindParam(':nam', $txtNam);
$stmt->bindParam(':add', $txtAdd);
$stmt->bindParam(':cit', $txtCit);
$stmt->execute();