SQL注入漏洞 詳解

漏洞影響

 

攻擊者利用該漏洞可能致使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

相關文章
相關標籤/搜索