漏洞影響 |
攻擊者利用該漏洞可能致使php 1.網頁被篡改html 2.數據被篡改java 3. 核心數據被竊取mysql 4. 數據庫所在服務器被攻擊變成傀儡主機程序員 |
解決方法:正則表達式
1. 過濾用戶輸入的內容,檢查用戶輸入的內容中是否有非法內容。如,|(豎線符號)、 & (& 符號)、;(分號)、$(美圓符號)、%(百分比符號)、@(at 符號)、\'(單引號)、"(引號)、\\\'(反斜槓轉義單引號)、\\"(反斜槓轉義引號)、<>(尖括號)、()(括號)、+(加號)、 CR(回車符,ASCII 0x0d)、 LF(換行,ASCII 0x0a)、,(逗號)、\\(反斜槓)、)(結束括號)等符號。sql
2. 過濾危險的SQL語句關鍵字,如select,from,update,insert,delete等。數據庫
3. 利用存儲過程,將數據訪問抽象化,讓用戶不直接訪問表或視圖。當使用存儲過程時,請利用 ADO 命令對象來實施它們,以強化變量類型。api
4. 使用防注入系統。安全
5. 修復示例
Asp.Net
如下是保護 Web 應用程序免遭 SQL 注入攻擊的兩種可行方法:
5.1 使用存儲過程,不用動態構建的 SQL 查詢字符串。將參數傳遞給 SQL Server 存儲過程的方式,可防止使用單引號和連字符。
如下是如何在ASP.NET 中使用存儲過程的簡單示例:
\' Visual Basic example
Dim DS As DataSet
Dim MyConnection AsSqlConnection
Dim MyCommand AsSqlDataAdapter
Dim SelectCommand As String= "select * from users where username = @username"
...
MyCommand.SelectCommand.Parameters.Add(NewSqlParameter("@username", SqlDbType.NVarChar, 20))
MyCommand.SelectCommand.Parameters("@username").Value =UserNameField.Value
// C# example
String selectCmd ="select * from Authors where state = @username";
SqlConnection myConnection =new SqlConnection("server=...");
SqlDataAdapter myCommand =new SqlDataAdapter(selectCmd, myConnection);
myCommand.SelectCommand.Parameters.Add(newSqlParameter("@username", SqlDbType.NVarChar, 20));
myCommand.SelectCommand.Parameters["@username"].Value= UserNameField.Value;
5.2 您可使用驗證控件,將輸入驗證添加到「Web 表單」頁面。驗證控件提供適用於全部常見類型的標準驗證的易用機制,例如,測試驗證日期是否有效,或驗證值是否在範圍內,以及進行自定義編寫驗證的方法。此外,驗證控件還可使您可以完整定義向用戶顯示錯誤信息的方式。驗證控件可搭配「Web 表單」頁面的類文件中處理的任何控件使用,其中包括 HTML 和 Web 服務器控件。爲了確保用戶輸入僅包含有效值,您可使用如下其中一種驗證控件:
5.2.1 「RangeValidator」:檢查用戶條目(值)是否在指定的上下界限之間。 您能夠檢查配對數字、字母字符和日期內的範圍。
5.2.2 「RegularExpressionValidator」:檢查條目是否與正則表達式定義的模式相匹配。 此類型的驗證使您可以檢查可預見的字符序列,如電子郵件地址、電話號碼、郵政編碼等中的字符序列。最後:驗證控件不會阻止用戶輸入或更改頁面處理流程;它們只會設置錯誤狀態,併產生錯誤消息。程序員的職責是,在執行進一步的應用程序特定操做前,測試代碼中控件的狀態。有兩種方法可檢查用戶輸入的有效性: 1. 測試常規錯誤狀態:在您的代碼中,測試頁面的 IsValid 屬性。該屬性會將頁面上全部驗證控件的 IsValid 屬性值彙總(使用邏輯 AND)。若是將其中一個驗證控件設置爲無效,那麼頁面屬性將會返回 false。 2. 測試個別控件的錯誤狀態:在頁面的「驗證器」集合中循環,該集合包含對全部驗證控件的引用。而後,您就能夠檢查每一個驗證控件的 IsValid 屬性。
PHP
5.3過濾用戶輸入
將任何數據傳給 SQL 查詢以前,應始終先使用篩選技術來適當過濾。 這不管如何強調都不爲過。 過濾用戶輸入可以讓許多注入缺陷在到達數據庫以前便獲得更正。
5.4將用戶輸入加引號
不論任何數據類型,只要數據庫容許,便用單引號括住全部用戶數據。
5.5 轉義數據值
若是使用 MySQL4.3.0 或更新的版本,您應該用 mysql_real_escape_string() 來轉義全部字符串。 若是使用舊版的 MySQL,便應該使用mysql_escape_string() 函數。若是未使用 MySQL,您能夠選擇使用特定數據庫的特定換碼功能。若是不知道換碼功能,您能夠選擇使用較通常的換碼功能,例如,addslashes()。
若是使用 PEAR DB 數據庫抽象層,您可使用DB::quote() 方法或使用 ? 之類的查詢佔位符,它會自動轉義替換佔位符的值。參考資料http://ca3.php.net/mysql_real_escape_string
http://ca.php.net/mysql_escape_string
http://ca.php.net/addslasheshttp://pear.php.net/package-info.php?package=DB
5.6輸入數據驗證:雖然爲方便用戶而在客戶端層上提供數據驗證,但仍必須始終在服務器層上執行數據驗證。客戶端驗證自己就不安全,由於這些驗證可輕易繞過,例如,經過禁用 Javascript。一個好的設計一般須要 Web 應用程序框架,以提供服務器端實用程序例程,從而驗證如下內容:必需字段,字段數據類型(缺省狀況下,全部 HTTP 請求參數都是「字符串」),字段長度,字段範圍,字段選項,字段模式, cookie 值,HTTP 響應等,如下部分描述一些檢查的示例。
// PHP example to validaterequired fields
functionvalidateRequired($input) {
...
$pass = false;
if(strlen(trim($input))>0){
$pass = true;
}
return $pass;
...
}
...
if(validateRequired($fieldName)) {
// fieldName is valid,continue processing request
...
}
J2EE
** 預編譯語句:
如下是保護應用程序免遭 SQL 注入(即惡意篡改 SQL 參數)的三種可行方法。使用如下方法,而非動態構建 SQL 語句:
5.7 PreparedStatement,經過預編譯而且存儲在PreparedStatement 對象池中。 PreparedStatement 定義 setter 方法,以註冊與受支持的 JDBC SQL 數據類型兼容的輸入參數。例如,setString 應該用於 VARCHAR 或 LONGVARCHAR 類型的輸入參數(請參閱 Java API,以獲取進一步的詳細信息)。經過這種方法來設置輸入參數,可防止攻擊者經過注入錯誤字符(如單引號)來操縱 SQL 語句。
如何在 J2EE 中使用 PreparedStatement 的示例:
//J2EE PreparedStatemenet Example
//Get a connection to the database
Connection myConnection;
if(isDataSourceEnabled()) {
// using the DataSource to get a managed connection
Context ctx = new InitialContext();
myConnection =((DataSource)ctx.lookup(datasourceName)).getConnection(dbUserName, dbPassword);
}else {
try {
// using the DriverManager to get a JDBC connection
Class.forName(jdbcDriverClassPath);
myConnection = DriverManager.getConnection(jdbcURL, dbUserName,dbPassword);
} catch (ClassNotFoundException e) {
...
}
}
...
try{
PreparedStatement myStatement =myConnection.prepareStatement("select * from users where username =?");
myStatement.setString(1, userNameField);
ResultSet rs = myStatement.executeQuery();
...
rs.close();
}catch (SQLException sqlException) {
...
}finally {
myStatement.close();
myConnection.close();
}
5.8 CallableStatement,擴展PreparedStatement 以執行數據庫 SQL 存儲過程。該類繼承 PreparedStatement 的輸入 setter 方法(請參閱上面的 [1])。
如下示例假定已建立該數據庫存儲過程:
CREATE PROCEDURE select_user (@usernamevarchar(20)) AS SELECT * FROM USERS WHERE USERNAME = @username;
如何在 J2EE 中使用 CallableStatement 以執行以上存儲過程的示例:
//J2EE PreparedStatemenet Example
//Get a connection to the database
Connection myConnection;
if(isDataSourceEnabled()) {
// using the DataSource to get a managed connection
Context ctx = new InitialContext();
myConnection =((DataSource)ctx.lookup(datasourceName)).getConnection(dbUserName, dbPassword);
}else {
try {
// using the DriverManager to get a JDBC connection
Class.forName(jdbcDriverClassPath);
myConnection = DriverManager.getConnection(jdbcURL, dbUserName,dbPassword);
} catch (ClassNotFoundException e) {
...
}
}
...
try{
PreparedStatement myStatement = myConnection.prepareCall("{?= callselect_user ?,?}");
myStatement.setString(1, userNameField);
myStatement.registerOutParameter(1, Types.VARCHAR);
ResultSet rs = myStatement.executeQuery();
...
rs.close();
}catch (SQLException sqlException) {
...
}finally {
myStatement.close();
myConnection.close();
}
5.9實體 Bean,表明持久存儲機制中的EJB 業務對象。實體 Bean 有兩種類型:bean 管理和容器管理。當使用 bean 管理的持久性時,開發者負責撰寫訪問數據庫的 SQL 代碼。當使用容器管理的持久性時,EJB 容器會自動生成 SQL 代碼。所以,容器要負責防止惡意嘗試篡改生成的 SQL 代碼。
如何在 J2EE 中使用實體 Bean 的示例:
//J2EE EJB Example
try{
// lookup the User home interface
UserHome userHome = (UserHome)context.lookup(User.class);
// find the User remote interface
User = userHome.findByPrimaryKey(new UserKey(userNameField));
...
}catch (Exception e) {
...
}
推薦使用的 JAVA 工具不適用
參考資料http://java.sun.com/j2se/1.4.1/docs/api/java/sql/PreparedStatement.htmlhttp://java.sun.com/j2se/1.4.1/docs/api/java/sql/CallableStatement.html