真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

XML注入的示例分析

小編給大家分享一下XML注入的示例分析,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

成都創(chuàng)新互聯(lián)堅持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:做網(wǎng)站、網(wǎng)站制作、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時代的梁平網(wǎng)站設(shè)計、移動媒體設(shè)計的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!

0x01 介紹

       一些 Web 應(yīng)用程序?qū)?XML 文件用于各種用途,從配置到完整數(shù)據(jù)庫功能。用戶輸入通常會傳

播到這些文件中,進(jìn)而定制配置或更新應(yīng)用程序數(shù)據(jù)庫。如果在使用用戶輸入之前未清理或驗證錯誤字符,那么這會成為安全隱患。當(dāng)未采取任何預(yù)防措施時,惡意用戶可以變更配置指令,添加新用戶(如果用戶列表通過 XML 文件進(jìn)行維護(hù)),獲取更高的特權(quán)等等。以下證明易受攻擊的 J2EE 應(yīng)用程序:

  		Document doc = docBuilder.newDocument();
  		Element rootElement = doc.createElement("root");
  		doc.appendChild(rootElement);
  		Element firstElement = doc.createElement("first");
  		rootElement.appendChild(firstElement);
  		Element childElement = doc.createElement("child");
  		childElement.appendChild(doc.createTextNode(--User_Supplied_Text--)); // un-sanitized text
  		rootElement.appendChild(childElement);

以下內(nèi)容演示類似的易受攻擊的 .NET 應(yīng)用程序:

  		String nodeText = request.getParameter("node");
  		XmlWriterSettings settings = new XmlWriterSettings();
  		writer = XmlWriter.Create(m_Document, settings);
  		writer.WriteElementString("newNode", nodeText); // un-sanitized text
  		 writer.WriteEndElement();

以此代碼為例,用戶輸入傳播到 XML 文件中而未適當(dāng)清理。根據(jù)應(yīng)用程序使用 XML 文件的方式,可以各種方法利用此漏洞。

0x02 威脅影響

      由于未對用戶輸入正確執(zhí)行危險字符清理,此攻擊的最壞情形取決于在客戶端所修改的頁面上下文,可能會破壞應(yīng)用程序邏輯

0x03 修復(fù)思路

若干問題的補救方法在于對用戶輸入進(jìn)行清理。通過驗證用戶輸入未包含危險字符,便可能防止惡意的用戶導(dǎo)致應(yīng)用程序執(zhí)行計劃外的任務(wù),例如:啟動任意 SQL 查詢、嵌入將在客戶端執(zhí)行的 Javascript 代碼、運行各種操作系統(tǒng)命令,等等。

1 建議過濾字符

[1] |(豎線符號)

[2] & (& 符號)

[3];(分號)

[4] $(美元符號)

[5] %(百分比符號)

[6] @(at 符號)

[7] '(單引號)

[8] "(引號)

[9] \'(反斜杠轉(zhuǎn)義單引號)

[10] \"(反斜杠轉(zhuǎn)義引號)

[11] <>(尖括號)

[12] ()(括號)

[13] +(加號)

[14] CR(回車符,ASCII 0x0d)

[15] LF(換行,ASCII 0x0a)

[16] ,(逗號)

[17] \(反斜杠)

以下部分描述各種問題、問題的修訂建議以及可能觸發(fā)這些問題的危險字符:

2 SQL 注入和 SQL 盲注

A. 確保用戶輸入的值和類型(如 Integer、Date 等)有效,且符合應(yīng)用程序預(yù)期。

B. 利用存儲過程,將數(shù)據(jù)訪問抽象化,讓用戶不直接訪問表或視圖。當(dāng)使用存儲過程時,請利用 ADO 命令對象來實施它們,以強(qiáng)化變量類型。

C. 清理輸入以排除上下文更改符號,例如:

[1] '(單引號)

[2] "(引號)

[3] \'(反斜線轉(zhuǎn)義單引號)

[4] \"(反斜杠轉(zhuǎn)義引號)

[5] )(結(jié)束括號)

[6] ;(分號)

3 跨站點腳本編制

A. 清理用戶輸入,并過濾出 JavaScript 代碼。我們建議您過濾下列字符:

[1] <>(尖括號)

[2] "(引號)

[3] '(單引號)

[4] %(百分比符號)

[5] ;(分號)

[6] ()(括號)

[7] &(& 符號)

[8] +(加號)

B. 如果要修訂 <%00script> 變體,請參閱 MS 文章 821349

C. 對于 UTF-7 攻擊: [-] 可能的話,建議您施行特定字符集編碼(使用 'Content-Type' 頭或 標(biāo)記)。

4  HTTP 響應(yīng)分割

清理用戶輸入(至少是稍后嵌入在 HTTP 響應(yīng)中的輸入)請確保輸入未包含惡意的字符,例如:

[1] CR(回車符,ASCII 0x0d)

[2] LF(換行,ASCII 0x0a)遠(yuǎn)程命令執(zhí)行:清理輸入以排除對執(zhí)行操作系統(tǒng)命令有意義的符號,例如:

[1] |(豎線符號)

[2] & (& 符號)

[3];(分號)

5 執(zhí)行 shell 命令

A. 絕不將未檢查的用戶輸入傳遞給 eval()、open()、sysopen()、system() 之類的 Perl 命令。

B. 確保輸入未包含惡意的字符,例如:

[1] $(美元符號)

[2] %(百分比符號)

[3] @(at 符號)

XPath 注入:清理輸入以排除上下文更改符號,例如:

[1] '(單引號)

[2] "(引號) 等

6 LDAP 注入

A. 使用正面驗證。字母數(shù)字過濾(A..Z,a..z,0..9)適合大部分 LDAP 查詢。

B. 應(yīng)該過濾出或進(jìn)行轉(zhuǎn)義的特殊 LDAP 字符:

[1] 在字符串開頭的空格或“#”字符

[2] 在字符串結(jié)尾的空格字符

[3] ,(逗號)

[4] +(加號)

[5] "(引號)

[6] \(反斜杠)

[7] <>(尖括號)

[8] ;(分號)

[9] ()(括號)

7 MX 注入

應(yīng)該過濾出特殊 MX 字符:

[1] CR(回車符,ASCII 0x0d)

[2] LF(換行,ASCII 0x0a)記錄偽造:

應(yīng)該過濾出特殊記錄字符:

[1] CR(回車符,ASCII 0x0d)

[2] LF(換行,ASCII 0x0a)

[3] BS(退格,ASCII 0x08)

8  ORM 注入

A. 確保用戶輸入的值和類型(如 Integer、Date 等)有效,且符合應(yīng)用程序預(yù)期。

B. 利用存儲過程,將數(shù)據(jù)訪問抽象化,讓用戶不直接訪問表或視圖。C. 使用參數(shù)化查詢 API

D. 清理輸入以排除上下文更改符號,例如: (*):

[1] '(單引號)

[2] "(引號)

[3] \'(反斜線轉(zhuǎn)義單引號)

[4] \"(反斜杠轉(zhuǎn)義引號)

[5] )(結(jié)束括號)

[6] ;(分號)

(*) 這適用于 SQL。高級查詢語言可能需要不同的清理機(jī)制。

0x04 Asp.Net

1 總體建議

[1] 我們建議您將服務(wù)器升級至 .NET Framework 2.0(或更新的版本),它本身就包括針對跨站點腳本編制攻擊進(jìn)行保護(hù)的安全檢查。

[2] 您可以使用驗證控件,將輸入驗證添加到“Web 表單”頁面。 驗證控件提供適用于標(biāo)準(zhǔn)驗證的所有常見類型的易用機(jī)制(例如,測試驗證日期是否有效,或驗證值是否在范圍內(nèi))。 另外,驗證控件也支持定制編寫驗證,可讓您完整定制向用戶顯示錯誤信息的方式。 驗證控件可以搭配“Web 表單”頁面類文件中處理的任何控件來使用,其中包括 HTML 和 Web 服務(wù)器控件。

2 確保用戶輸入僅包含有效值

[1] “RangeValidator”:檢查用戶條目(值)是否在指定的上下界限之間。您可以檢查配對數(shù)字、字母字符和日期內(nèi)的范圍。

[2] “RegularExpressionValidator”:檢查條目是否與正則表達(dá)式定義的模式相匹配。此類型的驗證使您能夠檢查可預(yù)見的字符序列,如社會保險號碼、電子郵件地址、電話號碼、郵政編碼等中的字符序列。有助于阻止跨站點腳本編制的正則表達(dá)式示例:

- 可以拒絕基本跨站點腳本編制變體的正則表達(dá)式可能如下:^([^<]|\<[^a-zA-Z])*[<]?$

- 拒絕上述所有字符的一般正則表達(dá)式可能如下:^([^\<\>\"\'\%\;\)\(\&\+]*)$

重要注意事項:驗證控件不會阻止用戶輸入或更改頁面處理流程;它們只會設(shè)置錯誤狀態(tài),并產(chǎn)生錯誤消息。程序員的職責(zé)是,在執(zhí)行進(jìn)一步的應(yīng)用程序特定操作前,測試代碼中控件的狀態(tài)。

有兩種方法可檢查用戶輸入的有效性:

1. 測試常規(guī)錯誤狀態(tài):

在您的代碼中,測試頁面的 IsValid 屬性。 該屬性會將頁面上所有驗證控件的 IsValid 屬性值匯總(使用邏輯 AND)。如果將其中一個驗證控件設(shè)置為無效,那么頁面屬性將會返回 false。

2. 測試個別控件的錯誤狀態(tài):

在頁面的“驗證器”集合中循環(huán),該集合包含對所有驗證控件的引用。 然后,您就可以檢查每個驗證控件的 IsValid 屬性。

3 編碼輸入

建議使用 Microsoft Anti-Cross Site Scripting Library(V1.5 更高版本)對不受信任的用戶輸入進(jìn)行編碼。

Anti-Cross Site Scripting Library 顯現(xiàn)下列方法:

[1] HtmlEncode - 將在 HTML 中使用的輸入字符串編碼

[2] HtmlAttributeEncode - 將在 HTML 屬性中使用的輸入字符串編碼

[3] JavaScriptEncode - 將在 JavaScript 中使用的輸入字符串編碼

[4] UrlEncode - 將在“統(tǒng)一資源定位器 (URL)”中使用的輸入字符串編碼

[5] VisualBasicScriptEncode - 將在 Visual Basic 腳本中使用的輸入字符串編碼

[6] XmlEncode - 將在 XML 中使用的輸入字符串編碼

[7] XmlAttributeEncode - 將在 XML 屬性中使用的輸入字符串編碼

如果要適當(dāng)使用 Microsoft Anti-Cross Site Scripting Library 來保護(hù) ASP.NET Web 應(yīng)用程序,您必須運行下列操作:

第 1 步:復(fù)查生成輸出的 ASP.NET 代碼

第 2 步:判斷是否包括不受信任的輸入?yún)?shù)

第 3 步:判斷不受信任的輸入的上下文是否作為輸出,判斷要使用哪個編碼方法

第 4 步:編碼輸出

第 3 步驟的示例:

注意:如果要使用不受信任的輸入來安裝 HTML 屬性,便應(yīng)該使用 Microsoft.Security.Application.HtmlAttributeEncode 方法,將不受信任的輸入編碼。另外,如果要在 JavaScript 的上下文中使用不受信任的輸入,便應(yīng)該使用 Microsoft.Security.Application.JavaScriptEncode 來編碼。

  // Vulnerable code
  // Note that untrusted input is being treated as an HTML attribute
  Literal1.Text = "";
  // Modified code
  Literal1.Text = "";

第 4 步驟的示例:將輸出編碼時,必須記住的一些重要事項:

[1] 輸出應(yīng)該編碼一次。

[2] 輸出的編碼與實際撰寫,應(yīng)該盡可能接近。 例如,如果應(yīng)用程序讀取用戶輸入、處理輸入,再用某種形式將它重新寫出,便應(yīng)該緊接在撰寫輸出之前進(jìn)行編碼。

  // Incorrect sequence
  protected void Button1_Click(object sender, EventArgs e)
  {
      // Read input
      String Input = TextBox1.Text;
      // Encode untrusted input
      Input = Microsoft.Security.Application.AntiXss.HtmlEncode(Input);
      // Process input
      ...
      // Write Output
      Response.Write("The input you gave was"+Input);
  }
  // Correct Sequence
  protected void Button1_Click(object sender, EventArgs e)
  {
      // Read input
      String Input = TextBox1.Text;
      // Process input
      ...
      // Encode untrusted input and write output
      Response.Write("The input you gave was"+ 
          Microsoft.Security.Application.AntiXss.HtmlEncode(Input));
  }

0x05 J2EE

1 輸入數(shù)據(jù)驗證

雖然為了用戶的方便,可以提供“客戶端”層數(shù)據(jù)的數(shù)據(jù)驗證,但必須使用 Servlet 在服務(wù)器層執(zhí)行驗證。 客戶端驗證本身就不安全,因為這些驗證可輕易繞過,例如,通過禁用 Javascript。一份好的設(shè)計通常需要 Web 應(yīng)用程序框架,以提供服務(wù)器端實用程序例程,從而驗證以下內(nèi)容:[1] 必需字段[2] 字段數(shù)據(jù)類型(缺省情況下,所有 HTTP 請求參數(shù)都是“字符串”)[3] 字段長度[4] 字段范圍[5] 字段選項[6] 字段模式[7] cookie 值[8] HTTP 響應(yīng)好的做法是將以上例程作為“驗證器”實用程序類中的靜態(tài)方法實現(xiàn)。以下部分描述驗證器類的一個示例。

[1] 必需字段

必需字段“始終”檢查字段不為空,并且其長度要大于零,不包括行距和后面的空格。如何驗證必需字段的示例:

  // Java example to validate required fields
  public Class Validator {
      ...
      public static boolean validateRequired(String value) {
          boolean isFieldValid = false;
          if (value != null && value.trim().length() > 0) {
              isFieldValid = true;
          }
          return isFieldValid;
      }
  }
  String fieldValue = request.getParameter("fieldName");
  if (Validator.validateRequired(fieldValue)) {
      // fieldValue is valid, continue processing request
  }

[2] 字段數(shù)據(jù)類型

輸入的 Web 應(yīng)用程序中的字段數(shù)據(jù)類型和輸入?yún)?shù)欠佳。例如,所有 HTTP 請求參數(shù)或 cookie 值的類型都是“字符串”。開發(fā)者負(fù)責(zé)驗證輸入的數(shù)據(jù)類型是否正確。 使用 Java 基本包裝程序類,來檢查是否可將字段值安全地轉(zhuǎn)換為所需的基本數(shù)據(jù)類型。驗證數(shù)字字段(int 類型)的方式的示例:

  // Java example to validate that a field is an int number
  public Class Validator {
      public static boolean validateInt(String value) {
          boolean isFieldValid = false;
          try {
              Integer.parseInt(value);
              isFieldValid = true;
          } catch (Exception e) {
              isFieldValid = false;
          }
          return isFieldValid;
      }
  }
  // check if the HTTP request parameter is of type int
  String fieldValue = request.getParameter("fieldName");
  if (Validator.validateInt(fieldValue)) {
      // fieldValue is valid, continue processing request
  }

好的做法是將所有 HTTP 請求參數(shù)轉(zhuǎn)換為其各自的數(shù)據(jù)類型。例如,開發(fā)者應(yīng)將請求參數(shù)的“integerValue”存儲在請求屬性中,并按以下示例所示來使用:

  // Example to convert the HTTP request parameter to a primitive wrapper data type
  // and store this value in a request attribute for further processing
  String fieldValue = request.getParameter("fieldName");
  if (Validator.validateInt(fieldValue)) {
      // convert fieldValue to an Integer
      Integer integerValue = Integer.getInteger(fieldValue);
      // store integerValue in a request attribute
      request.setAttribute("fieldName", integerValue);
  }
  // Use the request attribute for further processing
  Integer integerValue = (Integer)request.getAttribute("fieldName");

應(yīng)用程序應(yīng)處理的主要 Java 數(shù)據(jù)類型:

- Byte

- Short

- Integer

- Long

- Float

- Double

- Date

[3] 字段長度

“始終”確保輸入?yún)?shù)(HTTP 請求參數(shù)或 cookie 值)有最小長度和/或最大長度的限制。以下示例驗證 userName 字段的長度是否在 8 至 20 個字符之間:

  // Example to validate the field length
  public Class Validator {
      public static boolean validateLength(String value, int minLength, int maxLength) {
          String validatedValue = value;
          if (!validateRequired(value)) {
              validatedValue = "";
          }
          return (validatedValue.length() >= minLength &&
                      validatedValue.length() <= maxLength);
      }
  }
  String userName = request.getParameter("userName");
  if (Validator.validateRequired(userName)) {
      if (Validator.validateLength(userName, 8, 20)) {
          // userName is valid, continue further processing
      }
  }

[4] 字段范圍

始終確保輸入?yún)?shù)是在由功能需求定義的范圍內(nèi)。以下示例驗證輸入 numberOfChoices 是否在 10 至 20 之間:

  // Example to validate the field range
  public Class Validator {
      ...
      public static boolean validateRange(int value, int min, int max) {
          return (value >= min && value <= max);
      }
  }
  String fieldValue = request.getParameter("numberOfChoices");
  if (Validator.validateRequired(fieldValue)) {
      if (Validator.validateInt(fieldValue)) {
          int numberOfChoices = Integer.parseInt(fieldValue);
          if (Validator.validateRange(numberOfChoices, 10, 20)) {
              // numberOfChoices is valid, continue processing request
          }
      }
  }

[5] 字段選項

Web 應(yīng)用程序通常會為用戶顯示一組可供選擇的選項(例如,使用 SELECT HTML 標(biāo)記),但不能執(zhí)行服務(wù)器端驗證以確保選定的值是其中一個允許的選項。請記住,惡意用戶能夠輕易修改任何選項值。始終針對由功能需求定義的受允許的選項來驗證選定的用戶值。以下示例驗證用戶針對允許的選項列表進(jìn)行的選擇:

  // Example to validate user selection against a list of options
  public Class Validator {
      public static boolean validateOption(Object[] options, Object value) {
          boolean isValidValue = false;
          try {
              List list = Arrays.asList(options);
              if (list != null) {
                  isValidValue = list.contains(value);
              }
          } catch (Exception e) {
          }
          return isValidValue;
      }
  }
  // Allowed options
  String[] options = {"option1", "option2", "option3");
  // Verify that the user selection is one of the allowed options
  String userSelection = request.getParameter("userSelection");
  if (Validator.validateOption(options, userSelection)) {
      // valid user selection, continue processing request
  }

[6] 字段模式

始終檢查用戶輸入與由功能需求定義的模式是否匹配。例如,如果 userName 字段應(yīng)僅允許字母數(shù)字字符,且不區(qū)分大小寫,那么請使用以下正則表達(dá)式:^[a-zA-Z0-9]*$

Java 1.4 引進(jìn)了一種新的正則表達(dá)式包(java.util.regex)。以下是使用新的 Java 1.4 正則表達(dá)式包的 Validator.matchPattern 修訂版:

  // Example to validate that a given value matches a specified pattern
  // using the Java 1.4 regular expression package
  import java.util.regex.Pattern;
  import java.util.regexe.Matcher;
  public Class Validator {

      public static boolean matchPattern(String value, String expression) {
          boolean match = false;
          if (validateRequired(expression)) {
              match = Pattern.matches(expression, value);
          }
          return match;
      }
  }

[7] cookie 值

使用 javax.servlet.http.Cookie 對象來驗證 cookie 值。適用于 cookie 值的相同的驗證規(guī)則(如上所述)取決于應(yīng)用程序需求(如驗證必需值、驗證長度等)。驗證必需 cookie 值的示例:

  // Example to validate a required cookie value
  // First retrieve all available cookies submitted in the HTTP request
  Cookie[] cookies = request.getCookies();
  if (cookies != null) {
      // find the "user" cookie
      for (int i=0; i

[8] HTTP 響應(yīng)

[8-1] 過濾用戶輸入

要保護(hù)應(yīng)用程序免遭跨站點腳本編制的攻擊,請通過將敏感字符轉(zhuǎn)換為其對應(yīng)的字符實體來清理 HTML。這些是 HTML 敏感字符:< > " ' % ; ) ( & +

以下示例通過將敏感字符轉(zhuǎn)換為其對應(yīng)的字符實體來過濾指定字符串:

  // Example to filter sensitive data to prevent cross-site scripting
  public Class Validator {
      public static String filter(String value) {
          if (value == null) {
              return null;
          }        
          StringBuffer result = new StringBuffer(value.length());
          for (int i=0; i': 
                  result.append(">");
                  break;
              case '"': 
                  result.append(""");
                  break;
              case '\'': 
                  result.append("'");
                  break;
              case '%': 
                  result.append("%");
                  break;
              case ';': 
                  result.append(";");
                  break;
              case '(': 
                  result.append("(");
                  break;
              case ')': 
                  result.append(")");
                  break;
              case '&': 
                  result.append("&");
                  break;
              case '+':
                  result.append("+");
                  break;
              default:
                  result.append(value.charAt(i));
                  break;
          }        
          return result;
      }
  }
  // Filter the HTTP response using Validator.filter
  PrintWriter out = response.getWriter();
  // set output response
  out.write(Validator.filter(response));
  out.close();

Java Servlet API 2.3 引進(jìn)了過濾器,它支持?jǐn)r截和轉(zhuǎn)換 HTTP 請求或響應(yīng)。以下示例使用 Validator.filter 來用“Servlet 過濾器”清理響應(yīng):

  // Example to filter all sensitive characters in the HTTP response using a Java Filter.
  // This example is for illustration purposes since it will filter all content in the response, including HTML tags!
  public class SensitiveCharsFilter implements Filter {
      ...
      public void doFilter(ServletRequest request,
                      ServletResponse response,
                      FilterChain chain)
              throws IOException, ServletException {
          PrintWriter out = response.getWriter();
          ResponseWrapper wrapper = new ResponseWrapper((HttpServletResponse)response);
          chain.doFilter(request, wrapper);
          CharArrayWriter caw = new CharArrayWriter();
          caw.write(Validator.filter(wrapper.toString())); 
          response.setContentType("text/html");
          response.setContentLength(caw.toString().length());
          out.write(caw.toString());
          out.close();
      }
      public class CharResponseWrapper extends HttpServletResponseWrapper {
          private CharArrayWriter output;
          public String toString() {
              return output.toString();
          }
          public CharResponseWrapper(HttpServletResponse response){
              super(response);
              output = new CharArrayWriter();
          }
          public PrintWriter getWriter(){
              return new PrintWriter(output);
          }
      }
  } 
  }

[8-2] 保護(hù) cookie

在 cookie 中存儲敏感數(shù)據(jù)時,確保使用 Cookie.setSecure(布爾標(biāo)志)在 HTTP 響應(yīng)中設(shè)置 cookie 的安全標(biāo)志,以指導(dǎo)瀏覽器使用安全協(xié)議(如 HTTPS 或 SSL)發(fā)送 cookie。

保護(hù)“用戶”cookie 的示例:

  // Example to secure a cookie, i.e. instruct the browser to
  // send the cookie using a secure protocol
  Cookie cookie = new Cookie("user", "sensitive");
  cookie.setSecure(true);
  response.addCookie(cookie);

2 錯誤處理

許多 J2EE Web 應(yīng)用程序體系結(jié)構(gòu)都遵循“模型視圖控制器(MVC)”模式。在該模式中,Servlet 扮演“控制器”的角色。Servlet 將應(yīng)用程序處理委派給 EJB 會話 Bean(模型)之類的 JavaBean。然后,Servlet 再將請求轉(zhuǎn)發(fā)給 JSP(視圖),以呈現(xiàn)處理結(jié)果。Servlet 應(yīng)檢查所有的輸入、輸出、返回碼、錯誤代碼和已知的異常,以確保實際處理按預(yù)期進(jìn)行。

數(shù)據(jù)驗證可保護(hù)應(yīng)用程序免遭惡意數(shù)據(jù)篡改,而有效的錯誤處理策略則是防止應(yīng)用程序意外泄露內(nèi)部錯誤消息(如異常堆棧跟蹤)所不可或缺的。好的錯誤處理策略會處理以下項:

[1] 定義錯誤

[2] 報告錯誤

[3] 呈現(xiàn)錯誤

[4] 錯誤映射

[1] 定義錯誤

應(yīng)避免在應(yīng)用程序?qū)樱ㄈ?Servlet)中硬編碼錯誤消息。 相反地,應(yīng)用程序應(yīng)該使用映射到已知應(yīng)用程序故障的錯誤密鑰。好的做法是定義錯誤密鑰,且該錯誤密鑰映射到 HTML 表單字段或其他 Bean 屬性的驗證規(guī)則。例如,如果需要“user_name”字段,其內(nèi)容為字母數(shù)字,并且必須在數(shù)據(jù)庫中是唯一的,那么就應(yīng)定義以下錯誤密鑰:

(a) ERROR_USERNAME_REQUIRED:該錯誤密鑰用于顯示消息,以通知用戶需要“user_name”字段;

(b) ERROR_USERNAME_ALPHANUMERIC:該錯誤密鑰用于顯示消息,以通知用戶“user_name”字段應(yīng)該是字母數(shù)字;

(c) ERROR_USERNAME_DUPLICATE:該錯誤密鑰用于顯示消息,以通知用戶“user_name”值在數(shù)據(jù)庫中重復(fù);

(d) ERROR_USERNAME_INVALID:該錯誤密鑰用于顯示一般消息,以通知用戶“user_name”值無效;

好的做法是定義用于存儲和報告應(yīng)用程序錯誤的以下框架 Java 類:

- ErrorKeys:定義所有錯誤密鑰

      // Example: ErrorKeys defining the following error keys:    
      //    - ERROR_USERNAME_REQUIRED
      //    - ERROR_USERNAME_ALPHANUMERIC
      //    - ERROR_USERNAME_DUPLICATE
      //    - ERROR_USERNAME_INVALID
      //    ...
      public Class ErrorKeys {
          public static final String ERROR_USERNAME_REQUIRED = "error.username.required";
          public static final String ERROR_USERNAME_ALPHANUMERIC = "error.username.alphanumeric";
          public static final String ERROR_USERNAME_DUPLICATE = "error.username.duplicate";
          public static final String ERROR_USERNAME_INVALID = "error.username.invalid";
      }

- Error:封裝個別錯誤

      // Example: Error encapsulates an error key.
      // Error is serializable to support code executing in multiple JVMs.
      public Class Error implements Serializable {
          
          // Constructor given a specified error key
          public Error(String key) {
              this(key, null);
          }
          // Constructor given a specified error key and array of placeholder objects
          public Error(String key, Object[] values) {
              this.key = key;
              this.values = values;
          }
          // Returns the error key
          public String getKey() {
              return this.key;
          }
          // Returns the placeholder values
          public Object[] getValues() {
              return this.values;
          }
          private String key = null;
          private Object[] values = null;
      }

- Errors:封裝錯誤的集合

      // Example: Errors encapsulates the Error objects being reported to the presentation layer.
      // Errors are stored in a HashMap where the key is the bean property name and value is an
      // ArrayList of Error objects.
      public Class Errors implements Serializable {
      
          // Adds an Error object to the Collection of errors for the specified bean property.
          public void addError(String property, Error error) {
              ArrayList propertyErrors = (ArrayList)errors.get(property);
              if (propertyErrors == null) {
                  propertyErrors = new ArrayList();
                  errors.put(property, propertyErrors);
              }
              propertyErrors.put(error);            
          }
          // Returns true if there are any errors
          public boolean hasErrors() {
              return (errors.size > 0);
          }
          // Returns the Errors for the specified property
          public ArrayList getErrors(String property) {
              return (ArrayList)errors.get(property);
          }
          private HashMap errors = new HashMap();
      }

以下是使用上述框架類來處理“user_name”字段驗證錯誤的示例:

  // Example to process validation errors of the "user_name" field.
  Errors errors = new Errors();
  String userName = request.getParameter("user_name");
  // (a) Required validation rule
  if (!Validator.validateRequired(userName)) {
      errors.addError("user_name", new Error(ErrorKeys.ERROR_USERNAME_REQUIRED));
  } // (b) Alpha-numeric validation rule
  else if (!Validator.matchPattern(userName, "^[a-zA-Z0-9]*$")) {
      errors.addError("user_name", new Error(ErrorKeys.ERROR_USERNAME_ALPHANUMERIC));
  }
  else
  {
      // (c) Duplicate check validation rule
      // We assume that there is an existing UserValidationEJB session bean that implements
      // a checkIfDuplicate() method to verify if the user already exists in the database.
      try {
          ...        
          if (UserValidationEJB.checkIfDuplicate(userName)) {
              errors.addError("user_name", new Error(ErrorKeys.ERROR_USERNAME_DUPLICATE));
          }
      } catch (RemoteException e) {
          // log the error
          logger.error("Could not validate user for specified userName: " + userName);
          errors.addError("user_name", new Error(ErrorKeys.ERROR_USERNAME_DUPLICATE);
      }
  }
  // set the errors object in a request attribute called "errors"
  request.setAttribute("errors", errors);

[2] 報告錯誤

有兩種方法可報告 web 層應(yīng)用程序錯誤:

(a) Servlet 錯誤機(jī)制、(b) JSP 錯誤機(jī)制

[2-a] Servlet 錯誤機(jī)制

Servlet 可通過以下方式報告錯誤:

- 轉(zhuǎn)發(fā)給輸入 JSP(已將錯誤存儲在請求屬性中),或

- 使用 HTTP 錯誤代碼參數(shù)來調(diào)用 response.sendError,或

- 拋出異常

好的做法是處理所有已知應(yīng)用程序錯誤(如 [1] 部分所述),將這些錯誤存儲在請求屬性中,然后轉(zhuǎn)發(fā)給輸入 JSP。輸入 JSP 應(yīng)顯示錯誤消息,并提示用戶重新輸入數(shù)據(jù)。以下示例闡明轉(zhuǎn)發(fā)給輸入 JSP(userInput.jsp)的方式:

  // Example to forward to the userInput.jsp following user validation errors
  RequestDispatcher rd = getServletContext().getRequestDispatcher("/user/userInput.jsp");
  if (rd != null) {
      rd.forward(request, response);
  }

如果 Servlet 無法轉(zhuǎn)發(fā)給已知的 JSP 頁面,那么第二個選項是使用 response.sendError 方法,將 HttpServletResponse.SC_INTERNAL_SERVER_ERROR(狀態(tài)碼 500)作為參數(shù),來報告錯誤。 請參閱 javax.servlet.http.HttpServletResponse 的 Javadoc,以獲取有關(guān)各種 HTTP 狀態(tài)碼的更多詳細(xì)信息。返回 HTTP 錯誤的示例:

  // Example to return a HTTP error code
  RequestDispatcher rd = getServletContext().getRequestDispatcher("/user/userInput.jsp");
  if (rd == null) {
      // messages is a resource bundle with all message keys and values
      response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
                              messages.getMessage(ErrorKeys.ERROR_USERNAME_INVALID));
  }

作為最后的手段,Servlet 可以拋出異常,且該異常必須是以下其中一類的子類:

- RuntimeException

- ServletException

- IOException

[2-b] JSP 錯誤機(jī)制

JSP 頁面通過定義 errorPage 偽指令來提供機(jī)制,以處理運行時異常,如以下示例所示:

      <%@ page errorPage="/errors/userValidation.jsp" %>

未捕獲的 JSP 異常被轉(zhuǎn)發(fā)給指定的 errorPage,并且原始異常設(shè)置在名稱為 javax.servlet.jsp.jspException 的請求參數(shù)中。錯誤頁面必須包括 isErrorPage 偽指令:

      <%@ page isErrorPage="true" %>

isErrorPage 偽指令導(dǎo)致“exception”變量初始化為所拋出的異常對象。

[3] 呈現(xiàn)錯誤

J2SE Internationalization API 提供使應(yīng)用程序資源外部化以及將消息格式化的實用程序類,其中包括:

(a) 資源束、(b) 消息格式化

[3-a] 資源束

資源束通過將本地化數(shù)據(jù)從使用該數(shù)據(jù)的源代碼中分離來支持國際化。每一資源束都會為特定的語言環(huán)境存儲鍵/值對的映射。

java.util.PropertyResourceBundle 將內(nèi)容存儲在外部屬性文件中,對其進(jìn)行使用或擴(kuò)展都很常見,如以下示例所示:

  ################################################
  # ErrorMessages.properties
  ################################################
  # required user name error message
  error.username.required=User name field is required
  # invalid user name format
  error.username.alphanumeric=User name must be alphanumeric
  # duplicate user name error message
  error.username.duplicate=User name {0} already exists, please choose another one

可定義多種資源,以支持不同的語言環(huán)境(因此名為資源束)。例如,可定義 ErrorMessages_fr.properties 以支持該束系列的法語成員。如果請求的語言環(huán)境的資源成員不存在,那么會使用缺省成員。在以上示例中,缺省資源是 ErrorMessages.properties。應(yīng)用程序(JSP 或 Servlet)會根據(jù)用戶的語言環(huán)境從適當(dāng)?shù)馁Y源檢索內(nèi)容。

[3-b] 消息格式化

J2SE 標(biāo)準(zhǔn)類 java.util.MessageFormat 提供使用替換占位符來創(chuàng)建消息的常規(guī)方法。MessageFormat 對象包含嵌入了格式說明符的模式字符串,如下所示:

  // Example to show how to format a message using placeholder parameters
  String pattern = "User name {0} already exists, please choose another one";
  String userName = request.getParameter("user_name");
  Object[] args = new Object[1];
  args[0] = userName;
  String message = MessageFormat.format(pattern, args);

以下是使用 ResourceBundle 和 MessageFormat 來呈現(xiàn)錯誤消息的更加全面的示例:

  // Example to render an error message from a localized ErrorMessages resource (properties file)
  // Utility class to retrieve locale-specific error messages
  public Class ErrorMessageResource {   
      // Returns the error message for the specified error key in the environment locale
      public String getErrorMessage(String errorKey) {
          return getErrorMessage(errorKey, defaultLocale);
      }  
      // Returns the error message for the specified error key in the specified locale
      public String getErrorMessage(String errorKey, Locale locale) {
          return getErrorMessage(errorKey, null, locale);
      } 
      // Returns a formatted error message for the specified error key in the specified locale
      public String getErrorMessage(String errorKey, Object[] args, Locale locale) {    
          // Get localized ErrorMessageResource
          ResourceBundle errorMessageResource = ResourceBundle.getBundle("ErrorMessages", locale);
          // Get localized error message
          String errorMessage = errorMessageResource.getString(errorKey);
          if (args != null) {
              // Format the message using the specified placeholders args
              return MessageFormat.format(errorMessage, args);
          } else {
              return errorMessage;
          }
      }
      // default environment locale
      private Locale defaultLocale = Locale.getDefaultLocale();
  }
  // Get the user's locale
  Locale userLocale = request.getLocale();
  // Check if there were any validation errors
  Errors errors = (Errors)request.getAttribute("errors");
  if (errors != null && errors.hasErrors()) {
      // iterate through errors and output error messages corresponding to the "user_name" property
      ArrayList userNameErrors = errors.getErrors("user_name");
      ListIterator iterator = userNameErrors.iterator();
      while (iterator.hasNext()) {
          // Get the next error object
          Error error = (Error)iterator.next();
          String errorMessage = ErrorMessageResource.getErrorMessage(error.getKey(), userLocale);
          output.write(errorMessage + "\r\n");
      }
  }

建議定義定制 JSP 標(biāo)記(如 displayErrors),以迭代處理并呈現(xiàn)錯誤消息,如以上示例所示。

[4] 錯誤映射

通常情況下,“Servlet 容器”會返回與響應(yīng)狀態(tài)碼或異常相對應(yīng)的缺省錯誤頁面??梢允褂枚ㄖ棋e誤頁面來指定狀態(tài)碼或異常與 Web 資源之間的映射。好的做法是開發(fā)不會泄露內(nèi)部錯誤狀態(tài)的靜態(tài)錯誤頁面(缺省情況下,大部分 Servlet 容器都會報告內(nèi)部錯誤消息)。該映射配置在“Web 部署描述符(web.xml)”中,如以下示例所指定:

  
  
    UserValidationException
    /errors/validationError.html
  
  
    500
    /errors/internalError.html
  
  
  ...
  

0x06 PHP

1  輸入數(shù)據(jù)驗證

雖然為方便用戶而在客戶端層上提供數(shù)據(jù)驗證,但仍必須始終在服務(wù)器層上執(zhí)行數(shù)據(jù)驗證??蛻舳蓑炞C本身就不安全,因為這些驗證可輕易繞過,例如,通過禁用 Javascript。一份好的設(shè)計通常需要 Web 應(yīng)用程序框架,以提供服務(wù)器端實用程序例程,從而驗證以下內(nèi)容:[1] 必需字段[2] 字段數(shù)據(jù)類型(缺省情況下,所有 HTTP 請求參數(shù)都是“字符串”)[3] 字段長度[4] 字段范圍[5] 字段選項[6] 字段模式[7] cookie 值[8] HTTP 響應(yīng)好的做法是實現(xiàn)一個或多個驗證每個應(yīng)用程序參數(shù)的函數(shù)。以下部分描述一些檢查的示例。

[1] 必需字段

“始終”檢查字段不為空,并且其長度要大于零,不包括行距和后面的空格。如何驗證必需字段的示例:

  // PHP example to validate required fields
  function validateRequired($input) {
      ...
      $pass = false;
      if (strlen(trim($input))>0){
          $pass = true;
      }
      return $pass;
  }
  if (validateRequired($fieldName)) {
      // fieldName is valid, continue processing request
  }

[2] 字段數(shù)據(jù)類型

輸入的 Web 應(yīng)用程序中的字段數(shù)據(jù)類型和輸入?yún)?shù)欠佳。例如,所有 HTTP 請求參數(shù)或 cookie 值的類型都是“字符串”。開發(fā)者負(fù)責(zé)驗證輸入的數(shù)據(jù)類型是否正確。

[3] 字段長度

“始終”確保輸入?yún)?shù)(HTTP 請求參數(shù)或 cookie 值)有最小長度和/或最大長度的限制。

[4] 字段范圍<
分享文章:XML注入的示例分析
URL地址:http://weahome.cn/article/ghjpdd.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部