Control Flow Myths busted in Java

balaji
By balaji

December 31, 2011

There are many things that we assume and use in this crazy world of "programming" without analyzing the behavior of programming entities. The more complex applications we build and use, the more we can understand their behavior in terms of their execution pattern. There are a few myths or misconceptions about certain programming entities in Java, which if left unexplored, can inadvertently lead to major programming flaws in the application. We will try and decipher these myths one by one.

java-myths.jpg

There are many things that we assume and use in this crazy world of "programming" without analyzing the behavior of programming entities. The more complex applications we build and use, the more we can understand their behavior in terms of their execution pattern. There are a few myths or misconceptions about certain programming entities in Java, which if left unexplored, can inadvertently lead to major programming flaws in the application. We will try and decipher these myths one by one.

Myth 1: The execution stops after "Catch" or "Finally"

We perform "exception handling" with the help of "Try–Catch" blocks in our programs. The "Catch" block contains the code required to carry out necessary action in case an exception occurs. Web applications preferably use user-defined exceptions in order to deal with violations in business rules; hence, we may find snippets of exception-handling code scattered across the application.

Let's see what happens to the execution flow when an exception is encountered within a "Try–Catch" block.

  1. The execution stops at that point within the Try block.
  2. The execution is transferred to the corresponding Catch block followed by Finally block (if present).
  3. The execution then continues from the end of the Catch/Finally block till the end of the program.

Point number 3 mentioned above is important. Assuming that the execution flow would terminate after the Catch/Finally may lead to anomalous program behavior.

Why is it a risk?

Consider the scenario of a Branch Creation page in the application that is used to add new branch entries in the system. This feature incorporates a page token and the corresponding branch creation servlet validates the request based on the token value. The servlet calls a POJO to validate a request token and the validating POJO sends an exception to the servlet in case the token is invalid. Here, if the servlet assumes that the only way to terminate the processing of the request when the POJO returns an exception (i.e. when the token is invalid) is to handle the exception in a Catch block, then the implementation may be flawed. The code snippet of the servlet is shown in the screenshot below wherein a user-defined exception is used to identify any validation failure. The branch creation logic is present below the exception-handling block. Here, it is assumed that the execution flow would stop in case the validation fails and the processing of the request will then be terminated without creating a new branch entry for that request.

myth_fig1.png

Let's find out why this implementation isn't foolproof.

Step 1: Access the "Branch Creation" page as shown in the screenshot below. Enter test data and submit the request.

myth_fig2.png

Step 2: Capture the submitted request using a web proxy editor as shown in the screenshot below. Note that this request carries a random token value as marked in the screenshot.

myth_fig3.png

Step 3: Change the value of the token parameter to any invalid value and forward the request.

myth_fig4.png

Step 4: Observe that the server responds with the error – "The request is invalid", as expected.

myth_fig5.png

However, although the error message is displayed to the user, it was observed that the branch creation logic was also executed. A new branch was added in the database using the test data as shown in the screenshot below:

myth_fig6.png

This confirms that the execution flow did not stop after the "Catch" block and the assumption about the Catch block terminating the execution was incorrect.

Caution:

  • Use all business logic code only within the Try block.
  • Always implement the exception-handling code at the end without any processing logic after it.
  • Use a "return" statement in the "Catch" block to terminate the execution flow in the program if an exception occurs, as shown in the screenshot below. In this case, whenever the servlet receives an invalid token exception from the validating POJO, the Catch block will display a message to the user and cause the execution flow to terminate immediately with the help of the "return" statement.
myth_fig7.png

Myth 2: The execution stops after the "forward/sendRedirect" call in a servlet/JSP.

Forwards and Redirects are used by servlets and JSPs to extend the control to any other servlet/JSP in the application. Forwards are used by servlets to silently push the control to another web component without the knowledge of the user. However, in "redirect", the server sends a redirection response to the user who then gets redirected to the desired web component, which processes the request further. There may be many reasons to use "forward/sendRedirect" calls within an application based on its framework and design.

A general assumption or myth prevalent in this case is that the forward/sendRedirect calls terminate the execution flow in the forwarding servlet/JSP page. This may lead to a major flaw in the application if any web component is designed based on this assumption.

Why is it a risk?

Consider a scenario wherein the application performs a classic authentication check (i.e. using the session variable) in the internal pages before serving or processing the page content and redirects the user to the Login/Index page if the session is not an authenticated one, as shown in the screenshot below.

myth_fig8.png

In the above screenshot, observe that the secure operation is present in the scriptlet block after the session check.

Here, it is assumed that if this page is accessed without authentication, the user will be redirected to the "index.jsp" page; as a result of which, the secure operation should not get executed.

Let's see if this assumption works -

Try to access "SecurePage.jsp" without a valid session, as shown in the screenshot below.

myth_fig9.png

Observe that, as expected, "SecurePage.jsp" redirects the user to "index.jsp" due to the invalid session, as shown in the screenshot below.

myth_fig10.png

However, even though the "SecurePage.jsp" page is not served, the logic present in it gets executed as shown in the screenshot below.

myth_fig11.png

Here, the assumption was that if the user session is not updated, the user would be redirected to the "index" page using the "sendRedirect" method. But, as the execution flow does not stop after the "sendRedirect" method even though the user could not view the "SecurePage.jsp" page, the secure operation code got executed.

The above case is applicable even if the "RequestDispatcher’s forward" method is used instead of "sendRedirect". This is shown in the screenshot below.

myth_fig12.png

What will happen if the <jsp:forward> tag is used instead of the "RequestDispatcher" forward or the "sendRedirect" method?

The <jsp:forward> tag is a safer option and an exception to the scenario explained above. Here, the execution flow in the forwarding servlet will stop at the forward tag.

In the above case, if the "<jsp:forward>" tag is used to forward the request to the "index.jsp" page, the secure operation will not execute in case there is a session check violation.

myth_fig13.png

What will happen when the "forward/sendRedirect" call is within a "catch" block, as shown in the screenshot below? Does the behavior change?

myth_fig14.png

No, it is the same. The execution flow neither stops after the RequestDispatcher forward/sendRedirect call in the catch block. The <jsp:forward> tag is the only exception as mentioned before.

Forwards and redirects are commonly seen in the case of error handling. It is a common practice to use them in "Catch" blocks in order to display error pages to users.

Ideally, in case of an error, it is expected that the execution flow should reach the "Catch" block and the content of the error page should be displayed to the user. What actually happens is that as expected, the error page is displayed to the user, but behind the scenes, even the code below the "Catch" block gets executed.

We often notice custom validation routines checking for the presence of page tokens, implementing a role-based validation, etc. within servlets; whereas, JSPs prefer to generate an application exception in case of any violation of business rules. But the validation is rendered null and void because of the failure in the termination of the execution flow.

Caution:

  • Always use the "return" statement after the "sendRedirect" statement and/or "forward" block, if the execution flow must be stopped. This is shown in the screenshot below:
myth_fig15.png
  • Ensure that the "Catch" block having forwards/redirects is the last code segment of any servlet/JSP.

In servlets, it is advisable to have a "service" method to call a separate method that performs all the processing and generates application-specific exceptions back to it. The service method would then be restricted only to handling the exception without any processing logic. Its error-handling block can then have the logic to forward the control to an error page with or without a return statement, as it would be the last piece of code of the service method.

For instance:

doGet(ServletRequest request, ServletResponse response){
try{
processRequest(request, response);
    } catch (Exception e) {
       RequestDispatcher rd = request.getRequestDispatcher(“Error.jsp”);
        rd.forward(request, response);
   }
}
Protected void processRequest(HttpServletRequest req,
HttpServletResponse res) throws ApplicationException {
//Processing logic throws exception
in case of any validation failure…no forwards
}

In JSPs:

  • Use POJOs to process and validate data.
  • Set the "errorPage" directive for the page instead of forwarding/redirecting the request to an error page with the help of the "RequestDispatcher" instance/"sendRedirect" method.
  • Use the <jsp:forward> tag instead of the RequestDispatcher forward wherever the forward is required.

Myth 3: The "throw" keyword will always generate an exception

When different utility classes are used for different validations, they generally "throw" user-defined exceptions in case of any validation failure. The "throw" keyword is used to propagate exceptions in the application. However, if a "throw" statement is used within a Try block of the "Try–Catch–Finally" structure then it will fail to generate an exception, if the Finally block has a "return" statement.

For instance:

Try
{ …. Some processing
If (x) then throw exception
}
Catch (<Any Exception> e)
{
throw new <User Defined Exception>();
}
Finally {
return;
}

In the above case, the exception "thrown" by the Catch block will not be propagated to the calling servlet.

Why is it a risk?

Consider a scenario like the "servlet" below, which calls an intermediary method called the "processRequest" to validate the uploaded file. Observe that here, it is dependent on the user-defined exception in order to determine the validity of the uploaded file and deletes the uploaded file only if an exception is generated. Otherwise, it processes the uploaded file.

myth_fig16.png

The "processRequest" method checks the extension of the uploaded files and accepts files having ".txt" extensions. In the rest of the cases, it generates an exception indicating that the file is invalid.

myth_fig17.png

However, as the Finally block contains a "return" statement, the exception that the logic is supposed to "throw" for invalid file types will never be generated.

Let's check if this is true:

Step 1: Upload any invalid file type, e.g. an index.html file and submit the request.

myth_fig18.png

Step 2: Observe that the "html" file gets uploaded onto the server. This confirms that the return statement in the Finally block prevented an exception from being generated in "processRequest" for an invalid file.

myth_fig19.png

Step 3: Now, remove the "return" statement of the Finally block and run the application.

myth_fig20.png

Step 4: Note that this time an attempt to upload an HTML file onto the server generates an error, as expected.

myth_fig21.png

In this case, as the "return" statement was not present, the "exception" was generated and the servlet could take the necessary measure.

Caution:

Do not make use of the "return" statement in the "Finally" block when the "Try" or the "Catch" blocks are supposed to generate business exceptions.

Myth 4: The servlet and JSP "forwards" can be used only to forward the control to other JSP/servlets in the application

"Forward" is an option available for any servlet/JSP component to transfer the control flow preferably to any of its counterparts. A servlet/JSP would finish its work and then use these options to call another web component to take charge. "Forwards" take place at the server end. A servlet silently pushes the control to another component without the knowledge of the client.

It is a common misconception that the servlet/JSP can forward the request only to another servlet or a JSP page.

On the contrary, forwards can be used to send the request to any resource on the web server. This means that, using forwards, we can render the control to an HTML page or any other file instead of a servlet/JSP page.

This common misconception can lead to a major security flaw if the application uses user input to construct URLs used by "forward".

Why is it a risk?

Consider a scenario, as shown in the screenshot below, wherein a servlet named "InsecureForward" forwards the control to a resource whose path information is obtained from a user input named "path". It assumes that the path information sent in the request would be the name of the valid servlet to which the request must be sent for processing. This would be true in normal scenarios; however, an adversary can use this "path" parameter and the ability of the "forward" method to render the control to any resource on the server in order to fetch the contents of any arbitrary file on the server.

myth_fig22.png

Here, when the servlet is run, the vulnerable "path" parameter can be used to fetch any file on the server, e.g. web.xml as shown in the screenshot below.

myth_fig23.png

Note: This is applicable even for <jsp:forward> and <jsp:include> tags.

Caution:

  • Do not pass user input to forwards.
  • Always validate user input before making it a part of the file path using a whitelist mechanism, i.e. allow only names that can be accepted.
  • Use relative file paths for forwards.

Myth 5: The servlet/JSP can work with the output stream of the response before forwarding the control to another servlet/JSP

If the response's output stream is used anywhere before or after the forwards, then it might result in a runtime exception – Illegalstateexception

Usually the servlet that forwards the control to another servlet/JSP is not supposed to write anything to the response (i.e. the buffer of the output stream must be empty). If such a forwarding servlet/JSP has already written something to the response's output stream in the exception-handling logic, etc., the container would generate an exception at the time of forwarding the request.

Does it apply even to the <jsp:forward> tag?

In case of JSP pages using <jsp:forward> tags, it is dependent on the page directive "buffer". The exception will be generated only if this directive is set to "none" as <% page buffer="none"%>. If this attribute is not set to "none", then the exception is not generated even if the output stream has been used for writing by the JSP before the forward tag.

Why is it a risk?

If such a runtime exception is not detected, it might reveal the entire stack trace information to end users. However, this programming irregularity will be detected while program debugging, but it is good to be cautious about this while designing programs.

Consider a scenario wherein a servlet uses a response's outstream to display the error message in the Catch block and has a forward logic at the end to transfer the control to any view component, as shown in the screenshot below.

myth_fig24.png

Here, it seems that the "outstream" will be called only when an "exception" is generated and the forward will go undisturbed. But in reality, when the above servlet is accessed, a runtime exception gets generated in all the cases, as shown in the screenshot below.

myth_fig25.png

Caution:

  • Do not use the response output stream if forwards are being used.
  • Set a global error page in the application to mask any sort of runtime exception reaching the client.

Conclusion

On the basis of the above cases we can conclude that the following steps must be taken to ensure that the application is secure:

  • Use the entire business logic within the Try block.
  • Use all the processing logic within a separate POJO or method. Handle user-defined exceptions if any, in the calling method or servlet.
  • Use a "return" statement whenever a termination in the execution flow is required:
    • At the end of the Catch block.
    • After a forward/sendRedirect call.
  • Do not use the "return" statement in the Finally block, if the Try/Catch blocks generates an exception to the calling method.
  • Do not use user input to form resource names in the forwards and jsp:include features.
  • Do not use the output stream of the response if forwards are implemented in the servlet.

We must be careful while handling the control-flow entities in our programs. It is a good practice to debug the programs in order to ensure that they behave as expected in both positive and negative test scenarios.

Conducting a step-by-step test to stimulate and verify all possible test cases can go a long way in ensuring the overall security of the applications and help us get away from all such myths.


Tags: Best Practices

About

balaji

SUBSCRIBE TO OUR BLOG

Buyers-Guide-Collateral

WHITEPAPER

Buyer’s Guide to Managed Detection and Response

Download
MDR

Get AI Powered

Managed Detection and Response

MDR-learmore-btn

 

MDR-Guide-Collateral

REPORT

AI-Driven Managed Detection and Response

Download Report
Episode

EPISODE-25

Red-LineAsset-6

Why Your ‘Likes’ on Facebook May Be Revealing Far More than You Thought

Click URL in the Post for the Full Podacst
  • FacebookAsset
  • LinkedinAsset
  • TwitterAsset