今天要介紹SQL Injection,中文可以翻譯為SQL注入,網路上介紹的相關文章非常多,我這一次參考的是這一篇文章
SQL Injection 的多種攻擊方式與防護討論
SQL Injection簡單說就是利用程式的漏洞,原本應該是要輸入正確的帳號密碼才可以登入,但是以我昨天的語法,裡面有個很大的漏洞,語法如下
string strSQL = "SELECT 1 FROM `userdata` WHERE `account` = '" + account + "' AND `password` = '" + password + "';";
這次看到的文章的語法跟之前寫的不大一樣,如下圖
帳號輸入 ' or 1=1; /* ,密碼輸入 */-- ,組起來的語法如下
SELECT * FROM `userdata` WHERE `account` = '' or 1=1; /* and `password` = '*/--';
實際嘗試的結果,在HeidiSQL可以顯示出資料,但是在我的程式裡面會丟出意外,最後還是無法成功登入
但是如果改成以下這樣
重點是帳號,密碼的部分隨便輸入皆可
結果語法就會變成這樣
SELECT 1 FROM `userdata` WHERE `account` = '' OR 1=1 OR '' AND `password` = '(輸入的內容)';
這個句子有幾個部分
account
= '' 這個條件一定不會成立password
= '(輸入的內容)' 這個條件一定不會成立三個條件用OR結合起來,結論是一定會成立,所以就可以成功登入,一般在登入之後會帶入使用者資料,會抓到第一個或最後一個使用者的資料(看程式怎麼寫),當然也可以判斷是不是抓到很多行,如果有很多行就不讓它通過,但這不是好方法。
其中一種方法是使用參數查詢的方式,我們改用參數代替實際的資料,然後再定義參數的內容,並且決定參數的型態,(如字串、數字等)在這個例子將整個輸入的內容當成字串,不論對方輸入什麼,都當成是獨立的字串來看,如此就不會有上述的問題,必須這個字串跟帳號、密碼內的字串一模一樣,才能夠順利通過,將上述的語法改成如下
string strSQL = "SELECT 1 FROM `userdata` WHERE `account` = @account AND `password` @password;";
MySqlCommand cmd = new MySqlCommand(strSQL, conn);
cmd.Parameters.Add("@account", MySqlDbType.VarChar).Value = account;
cmd.Parameters.Add("@password", MySqlDbType.VarChar).Value = password;
完整的函式如下
public bool CheckUserData(string account, string password)
{
try
{
Connect();
string strSQL = "SELECT 1 FROM `userdata` WHERE `account` = @account AND `password` = @password;";
MySqlCommand cmd = new MySqlCommand(strSQL, conn);
cmd.Parameters.Add("@account", MySqlDbType.VarChar).Value = account;
cmd.Parameters.Add("@password", MySqlDbType.VarChar).Value = password;
using (MySqlDataReader reader = cmd.ExecuteReader())
{
if (reader.Read())
return true;
}
return false;
}
catch(Exception ex)
{
string error = ex.ToString();
return false;
}
finally
{
Disconnect();
}
}
再輸入同樣的內容,就會得到以下的結果
如此就不會讓對方順利蒙混過關了
--
小弟不才,
如果有謬誤或是要補充的,
都歡迎一起來討論!