Sanitizing user input

There are at least two general ways to deal with the disastrous result of Attack from the dark side :

  • Keep the database server from interpreting user input completely. This is probably the best way and will be discussed in the section called “java.sql.PreparedStatement.

  • Let the application check and process user input. Dangerous user input may be modified prior to being embedded in SQL statements or being rejected completely.

The first method is definitely superior in most cases. There are however cases where the restrictions being implied are too severe. We may for example choose dynamically which tables shall be accessed. So an SQL statement's structure rather than just its predicates is affected by user input. There are at least two standard procedures dealing with this problem:

Input Filtering

In the simplest case we check a user's input by regular expressions. An example is an input field in a login window representing a system user name. Legal input may allows letters and digits only. Special characters, whitespace etc. are typically prohibited. The input does have a minimum length of one character. A maximum length may be imposed as well. So we may choose the regular expression [A-Za-z0-9]+ to check valid user names.

Whitelisting

In many cases Input fields only allow a restricted set of values. Consider an input field for names of planets. An application may keep a dictionary table to validate user input:

Mercury 1
Venus 2
Earth 3
... ...
Neptune 9
Default: 0

So if a user enters a valid planet name a corresponding number representing this particular planet will be sent to the database. If the user enters an invalid string an error message may be raised.

In a GUI in many situations this may be better accomplished by presenting the list of planets to choose from. In this case a user has no chance to enter invalid or even malicious code.

So we have an interceptor sitting between user input fields and SQL generating code:

Figure 865. Validating user input prior to dynamically composing SQL statements. Slide presentation Create comment in forum
Validating user input prior to dynamically composing SQL statements.

exercise No. 30

Using regular expressions in Java Create comment in forum

Q:

This exercise is a preparation for Input validation by regular expressions . The aim is to deal with regular expressions and to use them in Java. If you don't know yet about regular expressions / pattern matching you may want to read either of:

Complete the implementation of the following skeleton:

...
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public static void main(String[] args) {
   final String [] wordList = new String [] {"Eric", "126653BBb", "_login","some text"};
   final String [] regexpList = new String[] {"[A-K].*", "[^0-9]+.*", "_[a-z]+", ""};

   for (final String word: wordList) {
      for (final String regexp: regexpList) {
         testMatch(word, regexp);
      }
   }
}

/**
 * Matching a given word by a regular expression. A log message is being
 * written to stdout.
 *
 * Hint: The implementation is based on the explanation being given in the
 * introduction to {@link Pattern}
 *
 * @param word This string will be matched by the subsequent argument.
 * @param regexp The regular expression tested to match the previous argument.
 * @return true if regexp matches word, false otherwise.
 */
public static boolean testMatch(final String word, final String regexp) {
.../* to be implemented by **YOU**   */
}

As being noted in the Java above you may want to read the documentation of class java.util.regex.Pattern. The intended output of the above application is:

The expression '[A-K].*' matches 'Eric'
The expression '[^0-9]+.*' ...
...

A:

A possible implementation is given by:

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * This class is intended to gain some basic experience with
 * regular expressions and their usage in Java
 *
 * @author goik
 *
 */
public class RegexpPrimer {


   public static void main(String[] args) {
      final String [] wordList = new String [] {"Eric", "126653BBb", "_login","some text"};
      final String [] regexpList = new String[] {"[A-K].*", "[^0-9]+.*", "_[a-z]+", ""};

      for (final String word: wordList) {
         for (final String regexp: regexpList) {
            testMatch(word, regexp);
         }
      }
   }

   /**
    * Matching a given word by a regular expression. A log message is being
    * written to stdout.
    *
    * Hint: The implementation is based on the explanation being given in the
    * introduction to {@link Pattern}
    *
    * @param word This string will be matched by the subsequent argument.
    * @param regexp The regular expression tested to match the previous argument.
    * @return true if regexp matches word, false otherwise.
    */
   public static boolean testMatch(final String word, final String regexp) {
      Pattern p = Pattern.compile(regexp);
      Matcher m = p.matcher(word);
      if (m.matches()) {
         System.out.println("The expression '" + regexp + "' matches '" + word + "'");
         return true;
      } else {
         System.out.println("The expression '" + regexp + "' does not match '" + word + "'");
         return false;
      }
   }
}

exercise No. 31

Input validation by regular expressions Create comment in forum

Q:

The application of Attack from the dark side proved to be vulnerable to SQL injection. Sanitize the two user input field's values to prevent such behaviour.

  • Find appropriate validators to check both username and email. Some hints:

    username

    Regarding SQL injection the ; character is among the most critical. You may want to exclude certain special characters like (,) and similar as well by means of a regular expression. This doesn't harm since their presence in a user's name is most likely a typo rather then any sensitive input. On the other hand it becomes increasingly hard to construct suitable injection attack strings.

    email

    There are tons of ultimate regular expressions available to check email addresses. Remember that rather avoiding wrong email addresses the present task is to avoid SQL injection. So find a reasonable one which may be too permissive regarding RFC email syntax rules but sufficient to secure your application.

    A concise definition of an email's syntax is being given in RFC5322. Its implementation is beyond scope of the current lecture. Moreover it is questionable whether E-mail clients and mail transfer agents implement strict RFC compliance.

    Both regular expressions must cover the whole user input from the beginning to the end. This can be achieved by using ^ ... $.

  • The Java standard class javax.swing.InputVerifier may help you validating user input.

  • The following screen shot may provide an idea for GUI realization and user interaction in case of errors. Of course the submit button's action should be disabled in case of erroneous input. The user should receive a helpful error message instead.

    Figure 866. Error message being presented to the user.
    Error message being presented to the user.

    In the current example the trailing ; within the E-Mail field is invalid.


Tip

Vaadin does provide regular expression based validation support. You may want to consider EmailValidator instead.

A:

Validation will be based on both on regular expressions and Vaadins built in EmailValidator:

   @Override
   protected void init(final VaadinRequest vaadinRequest) {

    ...
      // Sanitizing user names by regular expression
      nameField.addValidator(new RegexpValidator("[^;\"'()]+",
        "Sorry but this does not appear to be a user's name"));

      // Adding an input validator for sanitizing username and e-mail input values.
      // Caveat: Vaadin's validator will refuse e.g. "domainregistry@de"
      // and may generally be non-RFC compliant.
      emailField.addValidator(new EmailValidator("Not a valid email"));
    ...
}
...

   void conditionallyActivateInsertButton() {
      final boolean isValid =
            0 < nameField.getValue().trim().length() &&
            nameField.isValid() &&

            // empty fields are not being validated!
            0 < emailField.getValue().trim().length() &&
            emailField.isValid();
                ...