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 }