「你如何預防 SQL Injection?」這個問題已經成為了一個顯學,現在我們寫程式如果沒有把解決 SQL Injection 的方式變成習慣,我們就絕對是個不及格的程式設計師,一個領域如果夠成熟,那這個領域會累積一定厚度的必學項目,像 SQL Injection 的問題就是累積來的,面試也常常會問。
黑大在 2007 年的時候寫了一篇文章,第一段就是在講 SQL Injection,黑大講得非常清楚,裡面也還有其他 Security 的議題,建議大家可以閱讀這篇文章。
接下來我舉一個例子來說明 SQL Injection 是怎麼發生的,下圖的畫面上有一個輸入框,輸入 Id 就可以取得該 Id 所賦予的角色權限,但是只有 1 這個 Id 是保留的,因為權限最大,所以可以看到當 Id 輸入 1 時,是顯示「拒絕存取」的訊息。
不過當我輸入 '' OR 1=1
這串字串,神奇的事情發生了,我取得了所有的權限,我愛用哪一個權限就用哪一個權限。
這個就是一種 SQL Injection 的攻擊,通常發生的原因都是我們用組字串的方式來組 SQL 的查詢條件。
using (SqlConnection sql = new SqlConnection(connectionString))
{
sql.Open();
using (SqlCommand sqlCmd = new SqlCommand())
{
sqlCmd.Connection = sql;
sqlCmd.CommandText =
@"SELECT *
FROM Member
WHERE Id = " + id;
using (SqlDataReader sqlReader = sqlCmd.ExecuteReader())
{
if (sqlReader.HasRows)
{
while (sqlReader.Read())
{
...
}
}
}
}
}
現在如果還看到有程式設計師這樣在寫 Production Code 的話,應該被抓去關,讓他不要再出來害人。
在 .Net 要防範 SQL Injection 一勞永逸的方法就是使用參數化查詢,將 SQL 查詢條件的值宣告為 SQL 參數,再使用 SqlParameter 將 SQL 查詢條件真正的值塞給指定的參數。
using (SqlConnection sql = new SqlConnection(connectionString))
{
sql.Open();
using (SqlCommand sqlCmd = new SqlCommand())
{
sqlCmd.Connection = sql;
sqlCmd.CommandText =
@"SELECT *
FROM Member
WHERE Id = @Id";
sqlCmd.Parameters.AddWithValue("@Id", id);
using (SqlDataReader sqlReader = sqlCmd.ExecuteReader())
{
if (sqlReader.HasRows)
{
while (sqlReader.Read())
{
...
}
}
}
}
}
這時候我再輸入 '' OR 1=1
進行 SQL Injection 攻擊,就無效了。
再次提醒大家,SQL Injection 會對資訊安全造成很大的影響,尤其是對於機敏資料會產生非常嚴重的威脅,一定要防範!