Version 4.10.0

Package hirondelle.web4j.security

Tools for making your web application more secure.

See:
          Description

Interface Summary
ApplicationFirewall Perform hard validation on each incoming request.
FetchIdentifierOwner Look up the login name of the user who owns an untrusted identifer.
LoginTasks Perform tasks required after successful user login.
PermittedCharacters Characters accepted by the SafeText class.
SpamDetector Determine if text is likely spam.
UntrustedProxyForUserId Determines if a request has an ownership constraint which needs explicit validation for a user id proxy.
 

Class Summary
ApplicationFirewallImpl Default implementation of ApplicationFirewall.
CsrfFilter Protect your application from a Cross Site Request Forgery (CSRF).
PermittedCharactersImpl Default implementation of PermittedCharacters.
SafeText Models free-form text entered by the user, and protects your application from Cross Site Scripting (XSS).
SpamDetectorImpl Fails all text containing links, except those appearing in wiki-style formatting.
SuppressUnwantedSessions Suppress the creation of unwanted sessions.
UntrustedProxyForUserIdImpl Default implementation of UntrustedProxyForUserId.
 

Package hirondelle.web4j.security Description

Tools for making your web application more secure.

The Open Web App Security Project (OWASP) is an excellent guide for increasing the security of your web application, and is highly recommended.

An important point to understand is the separation of validation into two distinct parts - hard validation, and soft validation - see ApplicationFirewall for more information.

Recommendations and Reminders

SafeText

Free-form user input should always be modeled as SafeText, not String. This provides protection against XSS (Cross Site Scripting) attacks, without forcing you to continually escape special characters in JSPs.

POST versus GET

Forms should always specify the correct method attribute. The general rule is that any action that has a side effect (database edits, logging off) should be a POST, while an action without any side-effect (list or search operations, reports) should be a GET.

Content-Type

Always specify the content-type. This can be done in template JSPs, to reduce the repetition of identical markup. Example using a directive to specify an HTTP header :
<%@ page contentType="text/html" %>
Such directives must appear at the start of the page.

The jsp-property-group setting in web.xml can specify an include-prelude JSP, which will be automatically included at the start of your JSPs.

Filter

The CsrfFilter should be configured, to protect against CSRF attacks.

This filter requires configuration for FormSourceIdRead and FormSourceIdWrite. These items reference SqlIds. As usual, these SqlIds need to be declared in one of your application's classes, and also appear in an .sql file. (This ensures the usual matching of .sql file content to SqlIds will not fail. See hirondelle.web4j.database for more information.)

ApplicationFirewall

The ApplicationFirewallImpl provided by the framework is an excellent default for the ApplicationFirewall interface. It performs sanity checks on every request, to make sure they aren't hacks. You can subclass that implementation in order to add further checks, if desired. (Replacing the implementation entirely is possible, but is usually an extensive task, and should likely be attempted only if you are experienced.)

SpamDetector

Implementations for the SpamDetector interface can vary widely. The SpamDetectorImpl is a simple default, but you will occasionally need to replace it with something more appropriate> This will usually be easy to implement.

Cross Site Scripting (XSS) Attacks

The SafeText class is provided as the main defense against XSS attacks. The SafeText.toString() method performs proper escaping for HTML, and SafeText.getXmlSafe() performs proper escaping for XML documents. For the most common case of presenting data in a web page, a SafeText object will be rendered safely by default. It is highly recommended that all free-form text input by the user be represented in a Model Object using SafeText instead of String.

Using SafeText will greatly increase your safety when using JSTL. The JSTL is a bit defective when it comes to protecting you from XSS attacks:

When JSTL is used with a SafeText object, however, these problems do not occur, since by default SafeText.toString() will do the correct escaping for you in the background.

Cross Site Request Forgery (CSRF) Attacks

The central idea of protecting against CSRF attacks is that a server should be able to answer the question "Did this POSTed form really come from me?", and not from some unknown third party. The CsrfFilter is provided as a defense against CSRF attacks.

To use it, you must have the CsrfFilter configured as a Servlet Filter in web.xml. As part of that configuration, you must provide two SqlId's, to tell the Filter what SQL statements to use to read and write 'form-source ids', the tokens used to identify forms generated by your web app.

Although it is not really necessary for those simply wanting to use CsrfFilter, the following is a description of its implementation.

Form-Source Ids

When a user logs in, CsrfFilter will create a 'form-source id', and store it in the user's session under the key 'web4j_key_for_form_source_id'. This form-source id is constant for each session, and is hard to guess. The CsrfFilter will automatically modify all of your forms having method='POST' to include a hidden request parameter of the same name (web4j_key_for_form_source_id), whose value is simply the value created upon login.

Verifying Form-Source Ids

The default ApplicationFirewallImpl will verify that each POSTed form includes a parameter named web4j_key_for_form_source_id, and that its value matches either the current value stored in the user's session, or the form-source id used in the immediately preceding session for the same user.

The form-source id used in the previous session is needed to ensure smooth behavior upon re-login. Here is the use case in more detail :

When the form is POSTed, the user will of course need to log in a second time. After successful authentication, the action will continue in the usual way. In this case, however, note that there is a new session. Thus, the old form-source id attached to the first session is POSTed, not the current one. What is to be done? Well, if this use case is to be handled gracefully, then the 'old' form-source id must be remembered (in the database) and treated as second valid value. Then, a POSTed form will succeed only if its web4j_key_for_form_source_id has either the current form-source id value, or the 'old' form-source id value of the immediately preceding session.

This is the reason for the two SqlId configuration settings for the CsrfFilter: they tell the Filter how to read and write the form-source id for a given user. This allows the Filter to remember the previous form-source id value for each user.

When a user logs out, or when a session is about to expire, CsrfFilter will extract the user's form-source id from the session, and store it in the database for possible future use.

Sessions With No Login

There are some common forms for which no valid login is possible : In this case, a session is used, but without the usual corresponding login. Since the usual login mechanism does not apply, the Action itself must ensure that a session exists, and that a CSRF token is created. This is done simply by calling ActionImpl.createSessionAndCsrfToken() (typically in the Action's constructor).

There is one difference when a session does not include a user login: when a session expires, there's no way to recover using a 'previous' token from a previous session. Again, this is because the session is not attached to a specific user.


Version 4.10.0

Copyright Hirondelle Systems. Published October 19, 2013 - User Guide - All Docs.