使用參數化查詢防止SQL注入漏洞(轉)


SQL注入的原理

  以往在Web應用程序訪問數據庫時一般是采取拼接字符串的形式,比如登錄的時候就是根據用戶名和密碼去查詢:

1 string sql = "SELECT TOP 1 * FROM [User] WHERE UserName = '" + userName + "' AND Password = '" + password + "'";

  其中userName和password兩個變量的值是由用戶輸入的。在userName和password都合法的情況下,這自然沒有問題,但是用戶輸入是不可信的,一些惡意用戶只要用一些技巧,就可以繞過用戶名、密碼登錄。

  假設password的值是"1' or '1' = '1",userName的值隨便取,比如是"abc",那變量sql的值就是:

1 "SELECT TOP 1 * FROM [User] WHERE UserName = 'abc' AND Password = '1' or '1' = '1'"

  由於'1' = '1'恆為真,因此只要User表中有數據,不管UserName、Password的值是否匹配,這條SQL命令准能查出記錄來。就這樣,登錄系統就被破解了。

 以往的防御方式

  以前對付這種漏洞的方式主要有三種:

  • 字符串檢測:限定內容只能由英文、數字等常規字符,如果檢查到用戶輸入有特殊字符,直接拒絕。但缺點是,系統中不可避免地會有些內容包含特殊字符,這時候總不能拒絕入庫。
  • 字符串替換:把危險字符替換成其他字符,缺點是危險字符可能有很多,一一枚舉替換相當麻煩,也可能有漏網之魚。
  • 存儲過程:把參數傳到存儲過程進行處理,但並不是所有數據庫都支持存儲過程。如果存儲過程中執行的命令也是通過拼接字符串出來的,還是會有漏洞。

 參數化查詢

  近年來,自從參數化查詢出現后,SQL注入漏洞已成明日黃花。

  參數化查詢(Parameterized Query 或 Parameterized Statement)是訪問數據庫時,在需要填入數值或數據的地方,使用參數 (Parameter) 來給值。

  在使用參數化查詢的情況下,數據庫服務器不會將參數的內容視為SQL指令的一部份來處理,而是在數據庫完成SQL指令的編譯后,才套用參數運行,因此就算參數中含有指令,也不會被數據庫運行。Access、SQL Server、MySQL、SQLite等常用數據庫都支持參數化查詢。

  在ASP程序中使用參數化查詢

  ASP環境下的參數化查詢主要由Connection對象Command對象完成。

  Access數據庫只支持匿名參數,在傳入參數的位置用問號代替即可。SQL Server數據庫雖然支持匿名和非匿名的參數,但是在ASP中也僅能使用匿名參數。

 1 var conn = Server.CreateObject("ADODB.Connection");
 2 conn.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + Server.MapPath("Test.mdb");
 3 conn.Open();
 4 var cmd = Server.CreateObject("ADODB.Command");
 5 cmd.ActiveConnection = conn;
 6 cmd.CommandType = 1;
 7 cmd.CommandText = "SELECT TOP 1 * FROM [User] WHERE UserName = ? AND Password = ?";
 8 cmd.Parameters.Append(cmd.CreateParameter("@UserName", 200, 1, 20, "user01"));
 9 cmd.Parameters.Append(cmd.CreateParameter("@Password", 200, 1, 16, "123456"));
10 var rs = cmd.Execute();
11 Response.Write(rs("UserId").value);
12 rs.Close();
13 conn.Close();

  在ASP.NET程序中使用參數化查詢

  ASP.NET環境下的查詢化查詢也是通過Connection對象和Command對象完成。如果數據庫是SQL Server,就可以用有名字的參數了,格式是“@”字符加上參數名

 1 SqlConnection conn = new SqlConnection("server=(local)\\SQL2005;user id=sa;pwd=12345;initial catalog=TestDb");
 2 conn.Open();
 3 SqlCommand cmd = new SqlCommand("SELECT TOP 1 * FROM [User] WHERE UserName = @UserName AND Password = @Password");
 4 cmd.Connection = conn;
 5 cmd.Parameters.AddWithValue("UserName", "user01");
 6 cmd.Parameters.AddWithValue("Password", "123456");
 7 SqlDataReader reader = cmd.ExecuteReader();
 8 reader.Read();
 9 int userId = reader.GetInt32(0);
10 reader.Close();
11 conn.Close();

  MySQL的參數格式與SQL Server有點區別,是以“?”加上參數名

 1 MySqlConnection conn = new MySqlConnection("server=127.0.0.1;uid=root;pwd=12345;database=test;");
 2 conn.Open();
 3 MySqlCommand cmd = new MySqlCommand(“SELECT * FROM `User` WHERE UserName = ?UserName AND Password = ?Password LIMIT 1″);
 4 cmd.Connection = conn;
 5 cmd.Parameters.AddWithValue(”UserName”, “user01″);
 6 cmd.Parameters.AddWithValue(”Password”, “123456″);
 7 MySqlDataReader reader = cmd.ExecuteReader();
 8 reader.Read();
 9 int userId = reader.GetInt32(0);
10 reader.Close();
11 conn.Close();

本文轉自http://kb.cnblogs.com/page/75453/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM