读书人

J2EE数据印证的一些开发建议

发布时间: 2012-10-07 17:28:51 作者: rapoo

J2EE数据验证的一些开发建议
说在前面:非原创。

输入数据验证:虽然为了用户的方便,可以提供“客户端”层数据的数据验证,但必须使用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(f ieldValue)) {      // fieldValue is valid, continue processing request      ...  }

[2] 输入的 Web 应用程序中的字段数据类型和输入参数欠佳。例如,所有 HTTP 请求参数或cookie值的类型都是“字符串”。开发者负责验证输入的数据类型是否正确。 使用Java基本包装程序类,来检查是否可将字段值安全地转换为所需的基本数据类型。
验证数字字段(int 类型)的方式的示例:
  // Java example to validate that a f ield 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 f ieldValue = request.getParameter("f ieldName");  if (Validator.validateInt(f ieldValue)) {      // f ieldValue 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 f ieldValue = request.getParameter("f ieldName");  if (Validator.validateInt(f ieldValue)) {      // convert f ieldValue to an Integer      Integer integerValue = Integer.getInteger(f ieldValue);    // store integerValue in a request attribute      request.setAttribute("f ieldName", integerValue);  }  ...  / / Use the request attribute for further processing  Integer integerValue = (Integer)request.getAttribute("f ieldName");  ...

应用程序应处理的主要 Java 数据类型:
ByteShortIntegerLongFloatDoubleDate
[3] 字段长度“始终”确保输入参数(HTTP请求参数或cookie值)有最小长度和/或最大长度的限制。
以下示例验证 userName 字段的长度是否在 8 至 20 个字符之间:
  // Example to validate the f ield 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 f ield range  public Class Validator {      ...      public static boolean validateRange(int value, int min, int max) {          return (value >= min && value <= max);      }      ...  }  ...  String f ieldValue = request.getParameter("numberOfChoices");if (Validator.validateRequired(f ieldValue)) {      if (Validator.validateInt(f ieldValue)) {          int numberOfChoices = Integer.parseInt(f ieldValue);          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]*$。
执行正则表达式验证的示例:
  // Example to validate that a given value matches a specif ied 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;      }      ...  }  ...  // Verify that the userName request parameter is alphanumeric  String userName = request.getParameter("userName");  if (Validator.matchPattern(userName, "^[a-zA-Z0-9]*$")) {      / / userName is valid, continue processing request      ...  }

[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) {      // f ind 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 f ilter sensitive data to prevent cross-site scripting  public Class Validator {      ...      public static String f ilter(String value) {          if (value == null) {              return null;          }                  StringBuf fer result = new StringBuf fer(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("&#59;");                  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.f ilter 来用“Servlet 过滤器”清理响应:
  // Example to f ilter all sensitive characters in the HTTP response using a Java Filter.  // This example is for illustration purposes since it will f ilter 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.f ilter(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);


全文结束,有问题的可以留言大家探讨。

读书人网 >J2EE开发

热点推荐