SQL 注入
SQL 注入
SQL 注入是一種程式碼注入技術,可能會破壞您的資料庫。
SQL 注入是最常見的 Web 攻擊技術之一。
SQL 注入是透過網頁輸入,將惡意程式碼放置在 SQL 語句中。
網頁中的 SQL
SQL 注入通常發生在您要求使用者輸入資訊(如使用者名稱/使用者 ID)時,但使用者提供給您的不是姓名/ID,而是您將“不知情地”在資料庫上執行的 SQL 語句。
請看下面的示例,該示例透過將變數 (txtUserId) 新增到 select 字串中來建立 SELECT
語句。該變數從使用者輸入 (getRequestString) 中獲取。
示例
txtUserId = getRequestString("UserId");
txtSQL = "SELECT * FROM Users WHERE UserId = " + txtUserId;
本章的其餘部分將描述在 SQL 語句中使用使用者輸入的潛在危險。
基於 1=1 永真的 SQL 注入
再次看上面的示例。程式碼的原始目的是建立一個 SQL 語句,根據給定的使用者 ID 來選擇一個使用者。
如果沒有措施阻止使用者輸入“錯誤”的輸入,使用者可以輸入一些“聰明”的輸入,例如
UserId
然後,SQL 語句將如下所示
SELECT * FROM Users WHERE UserId = 105 OR 1=1;
上述 SQL 是有效的,並且將返回“Users”表中的所有行,因為 **OR 1=1** 始終為 TRUE。
上面的示例看起來危險嗎?如果“Users”表包含姓名和密碼呢?
上面的 SQL 語句與此非常相似
SELECT UserId, Name, Password FROM Users WHERE UserId = 105 or 1=1;
駭客只需在輸入欄位中插入 105 OR 1=1,就可以訪問資料庫中的所有使用者名稱和密碼。
基於 ""="" 永真的 SQL 注入
以下是網站使用者登入的示例
使用者名稱
密碼
示例
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 ""=" 即可訪問資料庫中的使用者名稱和密碼。
使用者名稱
密碼
伺服器上的程式碼將建立一個有效的 SQL 語句,如下所示
結果
SELECT * FROM Users WHERE Name ="" or ""="" AND Pass ="" or ""=""
上述 SQL 是有效的,並且將返回“Users”表中的所有行,因為 **OR ""=""** 始終為 TRUE。
基於批次 SQL 語句的 SQL 注入
大多數資料庫支援批次 SQL 語句。
批次 SQL 語句是一組兩個或多個 SQL 語句,用分號分隔。
以下 SQL 語句將返回“Users”表中的所有行,然後刪除“Suppliers”表。
示例
SELECT * FROM Users; DROP TABLE Suppliers
看下面的例子
示例
txtUserId = getRequestString("UserId");
txtSQL = "SELECT * FROM Users WHERE UserId = " + txtUserId;
以及以下輸入
User id
有效的 SQL 語句將如下所示
結果
SELECT * FROM Users WHERE UserId = 105; DROP TABLE Suppliers;
使用 SQL 引數進行保護
要保護網站免受 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 中的 INSERT INTO 語句
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 中的 INSERT INTO 語句
$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();