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 noncompliant code example 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:
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 Checker | Trust and security errors (see Chapter 8) |
CodeSonar | 8.1p0 | JAVA.IO.INJ.CODE | Code Injection (Java) |
Fortify | 6.10.0120 | Hidden_Field | Implemented |
5 Comments
Robert Seacord
Random thoughts:
I don't really like it when we elude large portions of the compliant solution.
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?
Robert Seacord
Two more comments:
David Svoboda
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.
David Svoboda
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.
David Svoboda
I've addressed all of Rob's issues.