0x01 引见
一些 Web 运用顺序将 XML 文件用于种种用处,从设置到完全数据库功用。用户输入一般会传
播到这些文件中,进而定制设置或更新运用顺序数据库。假如在运用用户输入之前未清算或考证毛病字符,那末这会成为平安隐患。当未采用任何预防措施时,歹意用户可以变动设置指令,增加新用户(假如用户列表经由历程 XML 文件举行庇护),猎取更高的特权等等。以下证实易受进击的 J2EE 运用顺序:
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);
以下内容演示相似的易受进击的 .NET 运用顺序:
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 文件中而未恰当清算。依据运用顺序运用 XML 文件的体式格局,可以种种要领运用此破绽。
0x02 要挟影响
由于未对用户输入准确实行风险字符清算,此进击的最坏情况取决于在客户端所修正的页面高低文,可以会损坏运用顺序逻辑
0x03 修复思绪
若干题目的弥补要领在于对用户输入举行清算。经由历程考证用户输入未包含风险字符,便可以防备歹意的用户致使运用顺序实行计划外的使命,比方:启动恣意 SQL 查询、嵌入将在客户端实行的 Javascript 代码、运转种种操纵系统敕令,等等。
1 发起过滤字符
[1] |(竖线标记)
[2] & (& 标记)
[3];(分号)
[4] $(美圆标记)
[5] %(百分比标记)
[6] @(at 标记)
[7] '(单引号)
[8] "(引号)
[9] \'(反斜杠转义单引号)
[10] \"(反斜杠转义引号)
[11] <>(尖括号)
[12] ()(括号)
[13] +(加号)
[14] CR(回车符,ASCII 0x0d)
[15] LF(换行,ASCII 0x0a)
[16] ,(逗号)
[17] \(反斜杠)
以下部份形貌种种题目、题目的订正发起以及可以触发这些题目的风险字符:
2 SQL 注入和 SQL 盲注
A. 确保用户输入的值和范例(如 Integer、Date 等)有用,且相符运用顺序预期。
B. 运用存储历程,将数据接见抽象化,让用户不直接接见表或视图。当运用存储历程时,请运用 ADO 敕令对象来实行它们,以强化变量范例。
C. 清算输入以消除高低文变动标记,比方:
[1] '(单引号)
[2] "(引号)
[3] \'(反斜线转义单引号)
[4] \"(反斜杠转义引号)
[5] )(完毕括号)
[6] ;(分号)
3 跨站点剧本编制
A. 清算用户输入,并过滤出 JavaScript 代码。我们发起您过滤以下字符:
[1] <>(尖括号)
[2] "(引号)
[3] '(单引号)
[4] %(百分比标记)
[5] ;(分号)
[6] ()(括号)
[7] &(& 标记)
[8] +(加号)
B. 假如要订正 <%00script> 变体,请参阅 MS 文章 821349
C. 关于 UTF-7 进击: [-] 可以的话,发起您实施特定字符集编码(运用 'Content-Type' 头或 <meta> 标记)。
4 HTTP 相应支解
清算用户输入(至少是稍后嵌入在 HTTP 相应中的输入)请确保输入未包含歹意的字符,比方:
[1] CR(回车符,ASCII 0x0d)
[2] LF(换行,ASCII 0x0a)长途敕令实行:清算输入以消除对实行操纵系统敕令有意义的标记,比方:
[1] |(竖线标记)
[2] & (& 标记)
[3];(分号)
5 实行 shell 敕令
A. 绝不将未搜检的用户输入传递给 eval()、open()、sysopen()、system() 之类的 Perl 敕令。
B. 确保输入未包含歹意的字符,比方:
[1] $(美圆标记)
[2] %(百分比标记)
[3] @(at 标记)
XPath 注入:清算输入以消除高低文变动标记,比方:
[1] '(单引号)
[2] "(引号) 等
6 LDAP 注入
A. 运用正面考证。字母数字过滤(A..Z,a..z,0..9)合适大部份 LDAP 查询。
B. 应当过滤出或举行转义的特别 LDAP 字符:
[1] 在字符串开首的空格或“#”字符
[2] 在字符串末端的空格字符
[3] ,(逗号)
[4] +(加号)
[5] "(引号)
[6] \(反斜杠)
[7] <>(尖括号)
[8] ;(分号)
[9] ()(括号)
7 MX 注入
应当过滤出特别 MX 字符:
[1] CR(回车符,ASCII 0x0d)
[2] LF(换行,ASCII 0x0a)纪录捏造:
应当过滤出特别纪录字符:
[1] CR(回车符,ASCII 0x0d)
[2] LF(换行,ASCII 0x0a)
[3] BS(退格,ASCII 0x08)
8 ORM 注入
A. 确保用户输入的值和范例(如 Integer、Date 等)有用,且相符运用顺序预期。
B. 运用存储历程,将数据接见抽象化,让用户不直接接见表或视图。C. 运用参数化查询 API
D. 清算输入以消除高低文变动标记,比方: (*):
[1] '(单引号)
[2] "(引号)
[3] \'(反斜线转义单引号)
[4] \"(反斜杠转义引号)
[5] )(完毕括号)
[6] ;(分号)
(*) 这适用于 SQL。高等查询言语可以须要差别的清算机制。
0x04 Asp.Net
1 整体发起
[1] 我们发起您将服务器升级至 .NET Framework 2.0(或更新的版本),它自身就包含针对跨站点剧本编制进击举行庇护的平安搜检。
[2] 您可以运用考证控件,将输入考证增加到“Web 表单”页面。 考证控件供应适用于规范考证的一切罕见范例的易用机制(比方,测试考证日期是不是有用,或考证值是不是在局限内)。 别的,考证控件也支撑定制编写考证,可以让您完全定制向用户展现毛病信息的体式格局。 考证控件可以搭配“Web 表单”页面类文件中处置惩罚的任何控件来运用,个中包含 HTML 和 Web 服务器控件。
2 确保用户输入仅包含有用值
[1] “RangeValidator”:搜检用户条目(值)是不是在指定的高低界线之间。您可以搜检配对数字、字母字符和日期内的局限。
[2] “RegularExpressionValidator”:搜检条目是不是与正则表达式定义的情势相婚配。此范例的考证使您可以搜检可预感的字符序列,如社会保险号码、电子邮件地址、电话号码、邮政编码等中的字符序列。有助于阻挠跨站点剧本编制的正则表达式示例:
- 可以谢绝基础跨站点剧本编制变体的正则表达式可以以下:^([^<]|\<[^a-zA-Z])*[<]?$
- 谢绝上述一切字符的平常正则表达式可以以下:^([^\<\>\"\'\%\;\)\(\&\+]*)$
重要注重事项:考证控件不会阻挠用户输入或变动页面处置惩罚流程;它们只会设置毛病状况,并发生毛病音讯。顺序员的职责是,在实行进一步的运用顺序特定操纵前,测试代码中控件的状况。
有两种要领可搜检用户输入的有用性:
1. 测试通例毛病状况:
在您的代码中,测试页面的 IsValid 属性。 该属性会将页面上一切考证控件的 IsValid 属性值汇总(运用逻辑 AND)。假如将个中一个考证控件设置为无效,那末页面属性将会返回 false。
2. 测试一般控件的毛病状况:
在页面的“考证器”鸠合中轮回,该鸠合包含对一切考证控件的援用。 然后,您就可以搜检每一个考证控件的 IsValid 属性。
3 编码输入
发起运用 Microsoft Anti-Cross Site Scripting Library(V1.5 更高版本)对不受信托的用户输入举行编码。
Anti-Cross Site Scripting Library 展现以下要领:
[1] HtmlEncode - 将在 HTML 中运用的输入字符串编码
[2] HtmlAttributeEncode - 将在 HTML 属性中运用的输入字符串编码
[3] JavaScriptEncode - 将在 JavaScript 中运用的输入字符串编码
[4] UrlEncode - 将在“一致资本定位器 (URL)”中运用的输入字符串编码
[5] VisualBasicScriptEncode - 将在 Visual Basic 剧本中运用的输入字符串编码
[6] XmlEncode - 将在 XML 中运用的输入字符串编码
[7] XmlAttributeEncode - 将在 XML 属性中运用的输入字符串编码
假如要恰当运用 Microsoft Anti-Cross Site Scripting Library 来庇护 ASP.NET Web 运用顺序,您必须运转以下操纵:
第 1 步:复查生成输出的 ASP.NET 代码
第 2 步:推断是不是包含不受信托的输入参数
第 3 步:推断不受信托的输入的高低文是不是作为输出,推断要运用哪一个编码要领
第 4 步:编码输出
第 3 步骤的示例:
注重:假如要运用不受信托的输入来装置 HTML 属性,便应当运用 Microsoft.Security.Application.HtmlAttributeEncode 要领,将不受信托的输入编码。别的,假如要在 JavaScript 的高低文中运用不受信托的输入,便应当运用 Microsoft.Security.Application.JavaScriptEncode 来编码。
// Vulnerable code // Note that untrusted input is being treated as an HTML attribute Literal1.Text = "<hr noshade size=[untrusted input here]>"; // Modified code Literal1.Text = "<hr noshade size="+Microsoft.Security.Application.AntiXss.HtmlAttributeEncode([untrusted input here])+">";
第 4 步骤的示例:将输出编码时,必须记着的一些重要事项:
[1] 输出应当编码一次。
[2] 输出的编码与现实撰写,应当尽量靠近。 比方,假如运用顺序读取用户输入、处置惩罚输入,再用某种情势将它从新写出,便应当紧接在撰写输出之前举行编码。
// 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 输入数据考证
虽然为了用户的随意马虎,可以供应“客户端”层数据的数据考证,但必须运用 Servlet 在服务器层实行考证。 客户端考证自身就不平安,由于这些考证可随意马虎绕过,比方,经由历程禁用 Javascript。一份好的设想一般须要 Web 运用顺序框架,以供应服务器端实用顺序例程,从而考证以下内容:[1] 必须字段[2] 字段数据范例(缺省情况下,一切 HTTP 要求参数都是“字符串”)[3] 字段长度[4] 字段局限[5] 字段选项[6] 字段情势[7] cookie 值[8] HTTP 相应好的做法是将以上例程作为“考证器”实用顺序类中的静态要领完成。以下部份形貌考证器类的一个示例。
[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] 字段数据范例
输入的 Web 运用顺序中的字段数据范例和输入参数欠佳。比方,一切 HTTP 要求参数或 cookie 值的范例都是“字符串”。开辟者担任考证输入的数据范例是不是准确。 运用 Java 基础包装顺序类,来搜检是不是可将字段值平安地转换为所需的基础数据范例。考证数字字段(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 要求参数转换为其各自的数据范例。比方,开辟者应将要求参数的“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");
运用顺序应处置惩罚的重要 Java 数据范例:
- Byte
- Short
- Integer
- Long
- Float
- Double
- Date
[3] 字段长度
“一直”确保输入参数(HTTP 要求参数或 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] 字段局限
一直确保输入参数是在由功用需求定义的局限内。以下示例考证输入 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 运用顺序一般会为用户展现一组可供挑选的选项(比方,运用 SELECT HTML 标记),但不能实行服务器端考证以确保选定的值是个中一个许可的选项。请记着,歹意用户可以随意马虎修正任何选项值。一直针对由功用需求定义的受许可的选项来考证选定的用户值。以下示例考证用户针对许可的选项列表举行的挑选:
// 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 字段应仅许可字母数字字符,且不辨别大小写,那末请运用以下正则表达式:^[a-zA-Z0-9]*$
Java 1.4 引进了一种新的正则表达式包(java.util.regex)。以下是运用新的 Java 1.4 正则表达式包的 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 值的雷同的考证划定规矩(如上所述)取决于运用顺序需求(如考证必须值、考证长度等)。考证必须 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<cookies.length; ++i) { if (cookies[i].getName().equals("user")) { // validate the cookie value if (Validator.validateRequired(cookies[i].getValue()) { // valid cookie value, continue processing request ... } } } }
[8] HTTP 相应
[8-1] 过滤用户输入
要庇护运用顺序免遭跨站点剧本编制的进击,请经由历程将敏感字符转换为其对应的字符实体来清算 HTML。这些是 HTML 敏感字符:< > " ' % ; ) ( & +
以下示例经由历程将敏感字符转换为其对应的字符实体来过滤指定字符串:
// 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<value.length(); ++i) { switch (value.charAt(i)) { 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; 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 引进了过滤器,它支撑阻拦和转换 HTTP 要求或相应。以下示例运用 Validator.filter 来用“Servlet 过滤器”清算相应:
// 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] 庇护 cookie
在 cookie 中存储敏感数据时,确保运用 Cookie.setSecure(布尔标志)在 HTTP 相应中设置 cookie 的平安标志,以指点浏览器运用平安协定(如 HTTPS 或 SSL)发送 cookie。
庇护“用户”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 运用顺序体系结构都遵照“模子视图控制器(MVC)”情势。在该情势中,Servlet 饰演“控制器”的角色。Servlet 将运用顺序处置惩罚委派给 EJB 会话 Bean(模子)之类的 JavaBean。然后,Servlet 再将要求转发给 JSP(视图),以显现处置惩罚结果。Servlet 应搜检一切的输入、输出、返回码、毛病代码和已知的非常,以确保现实处置惩罚按预期举行。
数据考证可庇护运用顺序免遭歹意数据改动,而有用的毛病处置惩罚战略则是防备运用顺序不测泄漏内部毛病音讯(如非常客栈跟踪)所不可或缺的。好的毛病处置惩罚战略会处置惩罚以下项:
[1] 定义毛病
[2] 报告毛病
[3] 显现毛病
[4] 毛病映照
[1] 定义毛病
应防止在运用顺序层(如 Servlet)中硬编码毛病音讯。 相反地,运用顺序应当运用映照到已知运用顺序毛病的毛病密钥。好的做法是定义毛病密钥,且该毛病密钥映照到 HTML 表单字段或其他 Bean 属性的考证划定规矩。比方,假如须要“user_name”字段,其内容为字母数字,而且必须在数据库中是唯一的,那末就应定义以下毛病密钥:
(a) ERROR_USERNAME_REQUIRED:该毛病密钥用于展现音讯,以关照用户须要“user_name”字段;
(b) ERROR_USERNAME_ALPHANUMERIC:该毛病密钥用于展现音讯,以关照用户“user_name”字段应当是字母数字;
(c) ERROR_USERNAME_DUPLICATE:该毛病密钥用于展现音讯,以关照用户“user_name”值在数据库中反复;
(d) ERROR_USERNAME_INVALID:该毛病密钥用于展现平常音讯,以关照用户“user_name”值无效;
好的做法是定义用于存储和报告运用顺序毛病的以下框架 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 层运用顺序毛病:
(a) Servlet 毛病机制、(b) JSP 毛病机制
[2-a] Servlet 毛病机制
Servlet 可经由历程以下体式格局报告毛病:
- 转发给输入 JSP(已将毛病存储在要求属性中),或
- 运用 HTTP 毛病代码参数来挪用 response.sendError,或
- 抛出非常
好的做法是处置惩罚一切已知运用顺序毛病(如 [1] 部份所述),将这些毛病存储在要求属性中,然后转发给输入 JSP。输入 JSP 应展现毛病音讯,并提醒用户从新输入数据。以下示例说明转发给输入 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 没法转发给已知的 JSP 页面,那末第二个选项是运用 response.sendError 要领,将 HttpServletResponse.SC_INTERNAL_SERVER_ERROR(状况码 500)作为参数,来报告毛病。 请参阅 javax.servlet.http.HttpServletResponse 的 Javadoc,以猎取有关种种 HTTP 状况码的更多细致信息。返回 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 毛病机制
JSP 页面经由历程定义 errorPage 伪指令来供应机制,以处置惩罚运转时非常,如以下示例所示:
<%@ page errorPage="/errors/userValidation.jsp" %>
未捕捉的 JSP 非常被转发给指定的 errorPage,而且原始非常设置在名称为 javax.servlet.jsp.jspException 的要求参数中。毛病页面必须包含 isErrorPage 伪指令:
<%@ page isErrorPage="true" %>
isErrorPage 伪指令致使“exception”变量初始化为所抛出的非常对象。
[3] 显现毛病
J2SE Internationalization API 供应使运用顺序资本外部化以及将音讯花样化的实用顺序类,个中包含:
(a) 资本束、(b) 音讯花样化
[3-a] 资本束
资本束经由历程将本地化数据从运用该数据的源代码中星散来支撑国际化。每一资本束都邑为特定的言语环境存储键/值对的映照。
java.util.PropertyResourceBundle 将内容存储在外部属性文件中,对其举行运用或扩大都很罕见,如以下示例所示:
################################################ # 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
可定义多种资本,以支撑差别的言语环境(因而名为资本束)。比方,可定义 ErrorMessages_fr.properties 以支撑该束系列的法语成员。假如要求的言语环境的资本成员不存在,那末会运用缺省成员。在以上示例中,缺省资本是 ErrorMessages.properties。运用顺序(JSP 或 Servlet)会依据用户的言语环境从恰当的资本检索内容。
[3-b] 音讯花样化
J2SE 规范类 java.util.MessageFormat 供应运用替代占位符来建立音讯的通例要领。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 来显现毛病音讯的越发周全的示例:
// 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 标记(如 displayErrors),以迭代处置惩罚并显现毛病音讯,如以上示例所示。
[4] 毛病映照
一般情况下,“Servlet 容器”会返回与相应状况码或非常相对应的缺省毛病页面。可以运用定制毛病页面来指定状况码或非常与 Web 资本之间的映照。好的做法是开辟不会泄漏内部毛病状况的静态毛病页面(缺省情况下,大部份 Servlet 容器都邑报告内部毛病音讯)。该映照设置在“Web 布置形貌符(web.xml)”中,如以下示例所指定:
<!-- Mapping of HTTP error codes and application exceptions to error pages --> <error-page> <exception-type>UserValidationException</exception-type> <location>/errors/validationError.html</error-page> </error-page> <error-page> <error-code>500</exception-type> <location>/errors/internalError.html</error-page> </error-page> <error-page> ... </error-page>
0x06 PHP
1 输入数据考证
虽然为随意马虎用户而在客户端层上供应数据考证,但仍必须一直在服务器层上实行数据考证。客户端考证自身就不平安,由于这些考证可随意马虎绕过,比方,经由历程禁用 Javascript。一份好的设想一般须要 Web 运用顺序框架,以供应服务器端实用顺序例程,从而考证以下内容:[1] 必须字段[2] 字段数据范例(缺省情况下,一切 HTTP 要求参数都是“字符串”)[3] 字段长度[4] 字段局限[5] 字段选项[6] 字段情势[7] cookie 值[8] HTTP 相应好的做法是完成一个或多个考证每一个运用顺序参数的函数。以下部份形貌一些搜检的示例。
[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] 字段数据范例
输入的 Web 运用顺序中的字段数据范例和输入参数欠佳。比方,一切 HTTP 要求参数或 cookie 值的范例都是“字符串”。开辟者担任考证输入的数据范例是不是准确。
[3] 字段长度
“一直”确保输入参数(HTTP 要求参数或 cookie 值)有最小长度和/或最大长度的限定。
[4] 字段局限
一直确保输入参数是在由功用需求定义的局限内。
[5] 字段选项
Web 运用顺序一般会为用户展现一组可供挑选的选项(比方,运用 SELECT HTML 标记),但不能实行服务器端考证以确保选定的值是个中一个许可的选项。请记着,歹意用户可以随意马虎修正任何选项值。一直针对由功用需求定义的受许可的选项来考证选定的用户值。
[6] 字段情势
一直搜检用户输入与由功用需求定义的情势是不是婚配。比方,假如 userName 字段应仅许可字母数字字符,且不辨别大小写,那末请运用以下正则表达式:^[a-zA-Z0-9]+$
[7] cookie 值
适用于 cookie 值的雷同的考证划定规矩(如上所述)取决于运用顺序需求(如考证必须值、考证长度等)。
[8] HTTP 相应
[8-1] 过滤用户输入要庇护运用顺序免遭跨站点剧本编制的进击,开辟者应经由历程将敏感字符转换为其对应的字符实体来清算 HTML。这些是 HTML 敏感字符:< > " ' % ; ) ( & +PHP 包含一些自动化清算实用顺序函数,如 htmlentities():
$input = htmlentities($input, ENT_QUOTES, 'UTF-8');
另外,为了防止“跨站点剧本编制”的 UTF-7 变体,您应当显式定义相应的 Content-Type 头,比方:
<?php header('Content-Type: text/html; charset=UTF-8'); ?>
[8-2] 庇护 cookie
在 cookie 中存储敏感数据且经由历程 SSL 来传输时,请确保先在 HTTP 相应中设置 cookie 的平安标志。这将会指导浏览器仅经由历程 SSL 衔接来运用该 cookie。为了庇护 cookie,您可以运用以下代码示例:
<$php $value = "some_value"; $time = time()+3600; $path = "/application/"; $domain = ".example.com"; $secure = 1; setcookie("CookieName", $value, $time, $path, $domain, $secure, TRUE); ?>
以上就是细致引见XML注入的引见与代码防备的细致内容,更多请关注ki4网别的相干文章!