Skip to end of metadata
Go to start of metadata

HTML allows fields in a web form to be visible or hidden. Hidden fields supply values to a web server but do not provide the user with a mechanism to modify their contents. However, there are techniques that attackers can use to modify these contents anyway. A web servlet that uses a GET form to obtain parameters can also accept these parameters through a URL. URLs allow a user to specify any parameter names and values in the web request. Consequently, hidden form fields should not be considered any more trustworthy than visible form fields.

Noncompliant Code Example

The following servlet demonstrates a servlet that accepts a visible field and a hidden field, and echoes them back to the user. The visible parameter is sanitized before being passed to the browser, but the hidden field is not.

public class SampleServlet extends HttpServlet {

  public void doGet(HttpServletRequest request, HttpServletResponse response)
    throws IOException, ServletException {
    response.setContentType("text/html");
    PrintWriter out = response.getWriter();
    out.println("<html>");

    String visible = request.getParameter("visible");
    String hidden = request.getParameter("hidden");

    if (visible != null || hidden != null) {
      out.println("Visible Parameter:");
      out.println( sanitize(visible));
      out.println("<br>Hidden Parameter:");
      out.println(hidden);
    } else {
      out.println("<p>");
      out.print("<form action=\"");
      out.print("SampleServlet\" ");
      out.println("method=POST>");
      out.println("Parameter:");
      out.println("<input type=text size=20 name=visible>");
      out.println("<br>");

      out.println("<input type=hidden name=hidden value=\'a benign value\'>");
      out.println("<input type=submit>");
      out.println("</form>");
    }
  }

  public void doPost(HttpServletRequest request, HttpServletResponse response)
    throws IOException, ServletException {
    doGet(request, response);
  }

  // Filter the specified message string for characters
  // that are sensitive in HTML. 
  public static String sanitize(String message) {
    // ...
  }
}

When fed the parameter param1, the web page displays the following:

Visible Parameter: param1
Hidden Parameter: a benign value

However, an attacker can easily supply a value to the hidden parameter by encoding it in the URL as follows:

http://localhost:8080/sample/SampleServlet?visible=dummy&hidden=%3Cfont%20color=red%3ESurprise%3C/font%3E!!!

When this URL is provided to the browser, the browser displays:

Visible Parameter: dummy
Hidden Parameter: Surprise!!!

Compliant Solution

This compliant solution applies the same sanitization to the hidden parameter as is applied to the visible parameter:

public class SampleServlet extends HttpServlet {
  public void doGet(HttpServletRequest request, HttpServletResponse response)
    throws IOException, ServletException {
    response.setContentType("text/html");
    PrintWriter out = response.getWriter();
    out.println("<html>");

    String visible = request.getParameter("visible");
    String hidden = request.getParameter("hidden");

    if (visible != null || hidden != null) {
      out.println("Visible Parameter:");
      out.println( sanitize(visible));
      out.println("<br>Hidden Parameter:");
      out.println( sanitize(hidden));          // Hidden variable sanitized
    } else {
      out.println("<p>");
      out.print("<form action=\"");
      out.print("SampleServlet\" ");
      out.println("method=POST>");
      out.println("Parameter:");
      out.println("<input type=text size=20 name=visible>");
      out.println("<br>");

      out.println("<input type=hidden name=hidden value=\'a benign value\'>");
      out.println("<input type=submit>");
      out.println("</form>");
    }
  }

  public void doPost(HttpServletRequest request, HttpServletResponse response)
    throws IOException, ServletException {
    doGet(request, response);
  }

  // Filter the specified message string for characters
  // that are sensitive in HTML. 
  public static String sanitize(String message) {
    // ...
  }
}

Consequently, when the malicious URL is entered into a browser, the servlet produces the following:

Visible Parameter: dummy
Hidden Parameter: <font color=red>Surprise</font>!!!

Risk Assessment

Trusting the contents of hidden form fields may lead to all sorts of nasty problems.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

IDS14-J

High

Probable

High

P6

L2

Automated Detection

Tool
Version
Checker
Description
The Checker Framework

2.1.3

Tainting CheckerTrust and security errors (see Chapter 8)
Fortify6.10.0120

Hidden_Field

Implemented

Bibliography

 


5 Comments

  1. Random thoughts:

    1. I don't really like it when we elude large portions of the compliant solution.

    2. There is a method to "filter the specified message string for characters that are sensitivein HTML." This appears to be part of the compliant solution as it is eluded by the CS (see 1).  Are we sure that this is a valid sanitize method and that it catches everything?  Don't we give advise elsewhere not to develop custom sanitization methods and instead use methods that are provided by the components that support it?  

      1. I'm thinking that maybe we don't need to show an implement for this method.
      2. If we do show it, perhaps we can break it out of the NCE/CS and just define it in the intro or something and show it as neutral.
      3. Maybe we can have another rule somewhere else that says "sanitize HTML" and shows this solution that we can then refer to.
    3. Automated detection should be a table.
  2. Two more comments:

    1. The sanitize() method has a level of commenting that is not consistent with our other methods.  Clearly this is better, but it sort of raises the question of why we aren't doing this everywhere.
    2. After Benito went through all our C rules and added the includes, I've sort of taken to adding/including the import statements.  We need to reach a broader consensus on if we should include them or not.  Basically, how buildable should the examples be?
  3. Right now, I'm going to address the issue of the sanitization function:

    Its true that we advocate using whatever sanitization routines are provided by the platform (in this case JavaEE). Alas, many times the platform provides no sanitization routines, and this is one such case.

    There are third-party tools like this one: https://www.owasp.org/index.php/OWASP_Java_HTML_Sanitizer_Project

    Part of the problem is that there are many levels of sanitization available, depending on if you want the input to contain simple HTML tags like <b>. The solution I sued allows no HTML tags or external entities.

    The subject of HTML sanization prob deserves its own rule. (it used to be part of IDS00-J before that rule blew up). So offhand the best thing to do here is to elide the sanitize() routine and devote a new rule to exploring HTML sanitization possiblities.

  4. I'm just going to focus on includes here.

    In the past (and the future), this has mainly been addressed by automated testing...using our scrapers to make files of source code and ru nning them through the compiler to see if it finds errors. IIRC for C we added all the standard includes before compiling. So a code example only needed includes if it included something outside the standard.

    I would suggest the same approach for Java. Eclipse has the ability to suggest the correct package to import if you use it to compile Java code with a missing package...I bet other IDEs do too. So I recommend that code that relies on Java SE needs no explicit import statements.

    Of course, that doesn't include servlets, which are Java EE. So we could decide to include J2EE as 'implicit includes'. I would recommend that, at least for this rule.

  5. I've addressed all of Rob's issues.