標籤:應用程式 serve 一個 cat 產生 檔案中 arch 詳細 資料庫預存程序
| 漏洞影響 |
攻擊者利用該漏洞可能導致
1.網頁被篡改
2.資料被篡改
3. 核心資料被竊取
4. 資料庫所在伺服器被攻擊變成傀儡主機 |
解決方案:
1. 過濾使用者輸入的內容,檢查使用者輸入的內容中是否有非法內容。如,|(豎線符號)、 & (& 符號)、;(分號)、$(貨幣符號)、%(百分比符號)、@(at 符號)、\‘(單引號)、"(引號)、\\\‘(反斜線轉義單引號)、\\"(反斜線轉義引號)、<>(角括弧)、()(括弧)、+(加號)、 CR(斷行符號符,ASCII 0x0d)、 LF(換行,ASCII 0x0a)、,(逗號)、\\(反斜線)、)(結束括弧)等符號。
2. 過濾危險的SQL語句關鍵字,如select,from,update,insert,delete等。
3. 利用預存程序,將資料訪問抽象化,讓使用者不直接存取表或視圖。當使用預存程序時,請利用 ADO 命令對象來實施它們,以強化變數類型。
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”:檢查條目是否與Regex定義的模式相匹配。 此類型的驗證使您能夠檢查可預見的字元序列,如電子郵件地址、電話號碼、郵遞區號等中的字元序列。最後:驗證控制項不會阻止使用者輸入或更改頁面處理流程;它們只會設定錯誤狀態,併產生錯誤訊息。程式員的職責是,在執行進一步的應用程式特定操作前,測試代碼中控制項的狀態。有兩種方法可檢查使用者輸入的有效性: 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
SQL注入漏洞 詳解