001 package hirondelle.web4j.security; 002 003 import hirondelle.web4j.action.Action; 004 import hirondelle.web4j.model.BadRequestException; 005 import hirondelle.web4j.model.ConvertParamError; 006 import hirondelle.web4j.model.ModelFromRequest; 007 import hirondelle.web4j.request.RequestParser; 008 009 /** 010 Perform <a href="#HardValidation">hard validation</a> on each incoming request. 011 012 <P>See {@link hirondelle.web4j.BuildImpl} for important information on how this item is configured. 013 {@link hirondelle.web4j.BuildImpl#forApplicationFirewall()} 014 returns the configured implementation of this interface. 015 016 <P>The main intent of an application firewall is to defend against malicious attacks. As a side effect, 017 an application firewall will often detect obvious bugs during unit testing - usually unexpected request 018 parameters. 019 020 <P><span class="highlight">The <a href="http://www.owasp.org/">Open Web Application Security Project</a> 021 is a superb resource for learning about web application security. Implementors of this interface are 022 highly recommended to read and use its guidelines.</span> 023 024 <P><span class="highlight">WEB4J divides validation tasks into <em>hard validation</em> and 025 <em>soft validation</em>.</span> They are distinguished by : 026 <ul> 027 <li>when they are applied 028 <li>their behavior when they fail 029 </ul> 030 031 <P><b><a name="HardValidation">"Hard" Validation</a></b><br> 032 Hard validation is applied earlier in processing. A failed hard validation 033 represents either a bug, or a malicious request (a "hack"). 034 When a hard validation fails, a curt and unpolished response can be sent. 035 Hard validations are performed by an <tt>ApplicationFirewall</tt>, ultimately called by the 036 {@link hirondelle.web4j.Controller}, as the first step in processing a request, 037 before any {@link Action} is executed. Items for hard validation might include : 038 <ul> 039 <li>overall request size 040 <li>parameter names 041 <li>parameter values (<em>not business validations</em>, however - see below) 042 <li>HTTP headers 043 <li>cookies 044 </ul> 045 046 <P><span class="highlight">For request parameters, hard validation must include only those checks whose failure 047 would constitute a bug or a malicious request.</span> 048 049 <P><b><a name="SoftValidation">"Soft" Validation</b><br> 050 Soft validation is applied later in processing. 051 If a soft validation fails, resulting response pages use a polished presentation. 052 They are applied to items that are input <em>directly</em> by the user, for example the content 053 of a <tt>text</tt> input control. Invalid values are handled as part of the normal operation of 054 the program. Soft validations are "problem domain" validations, and are usually implemented in a 055 Model Object constructor. 056 057 <P>To clarify, here are two examples, using the default implementation of 058 {@link ApplicationFirewallImpl}. 059 060 <P><b>Example 1</b> 061 <br>A <tt>select</tt> control named <tt>Spin</tt> submits two fixed values, <tt>UP</tt> and 062 <tt>DOWN</tt>. Under normal operation of the program, no other values are expected. In this 063 case, the submitted request parameter should undergo these checks : 064 065 <P> <em>Hard validation</em> - must be one of the two values <tt>UP</tt> or <tt>DOWN</tt>. 066 This is implemented by simply defining, in the 067 {@link Action} that handles this parameter, a single field : 068 <PRE> 069 public static final RequestParameter SPIN = RequestParameter.<a href="RequestParameter.html#withRegexCheck(java.lang.String,%20java.lang.String)">withRegexCheck</a>("Spin", "(UP|DOWN)"); 070 </PRE> 071 {@link ApplicationFirewallImpl} uses such fields to determine, for each {@link Action}, how to 072 do hard validation for request parameters. It checks permitted parameter names, and permitted parameter values 073 versus a regular expression. 074 075 <P> <em>Soft validation</em> - none. In this case, the hard validation checks the parameter value completely, 076 so there is no further validation to be performed. 077 </ul> 078 079 <P><b>Example 2</b> 080 <br>A text input control named <tt>Age</tt> accepts any text as input. That text should correspond to 081 an integer in the range <tt>0..130</tt>. In this case, the validation is <em>shared</em> between 082 hard validation and soft validation : 083 084 <P><em>Hard validation</em> - can only make a basic sanity check. For instance, a check that the parameter value 085 is not an unreasonable size - under 5K, for instance. This is meant only to detect obvious hacks. It has 086 nothing to do with business logic. That is, this size check does <em>not</em> correspond to the maximum number of 087 characters expected (3), since failure of a hard validation produces a response which should <em>not</em> be seen by 088 the typical user during normal operation of the program. In this case, the field declared in the {@link Action} 089 is : 090 <PRE> 091 public static final RequestParameter AGE = RequestParameter.<a href="RequestParameter.html#withLengthCheck(java.lang.String)">withLengthCheck</a>("Age"); 092 </PRE> 093 (The actual maximum length is set in <tt>web.xml</tt>.) 094 095 <P><em>Soft validation #1</em> - first, make sure the user input can be translated into an {@link Integer}. This is a very 096 common task, and is implemented by {@link RequestParser}, using its various <tt>toXXX</tt> methods (and, 097 at a higher lever, by {@link ModelFromRequest}). When user input cannot be parsed into 098 an {@link Integer}, then an error message is displayed to the user. See {@link ConvertParamError}. 099 100 <P><em>Soft validation #2</em> - make sure the {@link Integer} returned by the previous validation is in the 101 range <tt>0..150</tt>. This is an example of a typical business validation. These are usually implemented 102 in the constructor of a Model Object. Again, if a problem is detected, then an error message 103 is displayed to to the user. 104 105 <P>{@link hirondelle.web4j.model.Check} and {@link hirondelle.web4j.model.Validator} are provided to help you 106 implement soft validations. 107 */ 108 public interface ApplicationFirewall { 109 110 /** 111 Perform <a href="#HardValidation">hard validation</a> on each HTTP request. 112 113 <P>If a problem is detected, then a {@link BadRequestException} is thrown, indicating the 114 standard HTTP status code, as defined in {@link javax.servlet.http.HttpServletRequest}. 115 (An error message may also be included, if desired.) 116 The response will then be sent immediately, without further processing, using 117 {@link javax.servlet.http.HttpServletResponse#sendError(int)}, or 118 {@link javax.servlet.http.HttpServletResponse#sendError(int, java.lang.String)} if 119 {@link BadRequestException#getErrorMessage()} has content. 120 121 @param aAction corresponding to this request. If the underlying request is unknown 122 to {@link RequestParser#getWebAction()}, then that method will throw a 123 {@link BadRequestException}, and this method will not be called. 124 @param aRequestParser provides the raw underlying request, through 125 {@link RequestParser#getRequest()}; 126 */ 127 void doHardValidation(Action aAction, RequestParser aRequestParser) throws BadRequestException; 128 129 }