Secure coding

How to mitigate XSS Vulnerabilities

Srinivas
October 19, 2020 by
Srinivas

Introduction:

In the previous articles, we discussed what Cross Site Scripting vulnerabilities are, what causes Cross Site Scripting vulnerabilities and how one can detect and exploit them. While this all sounds fun from an attacker’s point of view, it is important to understand how to mitigate such web vulnerabilities in order to secure the web applications. This article discusses some of the most common mitigation techniques for Cross Site Scripting vulnerabilities. 

Learn Secure Coding Fundamentals

Learn Secure Coding Fundamentals

Build your secure coding skills as you progress through 14 courses focused on discovering, exploiting and mitigating common coding vulnerabilities.

How to mitigate Cross Site Scripting Vulnerabilities?

Following are the two most commonly used techniques to mitigate Cross Site Scripting vulnerabilities in web applications.

  • Input Validation
  • Output Encoding

In the next few sections, we will discuss these techniques in detail.

Input Validation:

Input Validation is a technique to ensure that the user supplied data is sufficiently validated before it is processed by the application. Input validation should always be done on the user supplied code to prevent unwanted characters from being processed by the application. Use of regular expressions is one of the ways to achieve this. 

Vulnerable source code example:

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

// TODO Auto-generated method stub

String studentid = request.getParameter("studentid");

if(studentid.isEmpty()) {

 

request.setAttribute("examresult","Please enter a value");

RequestDispatcher rd=request.getRequestDispatcher("/Home.jsp");            

rd.include(request, response);

}

else {

try{

*** truncated ***   }

if(nodeList.getLength() > 0){

 

*** truncated ***

}

else {

request.setAttribute("examresult","No Results found for the input"+studentid);

RequestDispatcher rd=request.getRequestDispatcher("/Home.jsp");            

rd.include(request, response);

}

}

 

If you observe the piece of code highlighted in the preceding excerpt, the application takes user input, which is then stored in the variable studentid and it is echoing back the studentid when the login fails. Furthermore, there is no validation performed on the user supplied input. When this returned response is embedded into the HTML page, it will cause a reflected XSS vulnerability if it is rendered without appropriate output encoding.

When developers need to validate the user input using custom validation filters, Regular expressions can help us do it. Let us assume that the studentid must be a number. The following code shows how once can validate the user input using regular expressions allowing only whitelisted characters.

Secure source code example:

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

// TODO Auto-generated method stub

String studentid = request.getParameter("studentid");

String regex = "\\d+";

if(studentid.isEmpty()) {

 

request.setAttribute("examresult","Please enter a value");

RequestDispatcher rd=request.getRequestDispatcher("/Home.jsp");            

rd.include(request, response);

}

else {

      

     if(studentid.matches(regex)) {

//Go and get the exam results

*** truncated ***

}

    else {

    request.setAttribute("examresult","Enter input is not a valid number");

RequestDispatcher rd=request.getRequestDispatcher("/Home.jsp");            

rd.include(request, response);

    }

}

 

If you notice the highlighted code in the above excerpt, studentid entered by the user is validated against a regular expression. 

The regular expression defined using the line String regex = "\\d+"; is used to ensure that the user input is a number. 

Following are the series of steps taken place in the preceding code. 

  • First, the application receives the post parameter studentid.
  • Then, we are defining a regular expression to match numbers.
  • Before the user input is processed, it is checked against the regular expression to make sure that the user input is a number.
  • If the input is not a number, the user will be shown a generic error message.

Learn Secure Coding Fundamentals

Learn Secure Coding Fundamentals

Build your secure coding skills as you progress through 14 courses focused on discovering, exploiting and mitigating common coding vulnerabilities.

Output Encoding:

There can be scenarios, where the application requires the user input to be  put into the HTML body directly. In such scenarios, Input Validation is not useful and thus an alternative technique must be used. This is where output encoding can be used. Output encoding is another way of sanitizing the data, which ensures that the characters are properly encoded before being displayed. So that they won’t be executed as code, instead they will just remain as data. 

IBM developer works portal has a library called EscapeUtils, which provides output encoding features for Java web applications. It can be found at the following URL.

https://www.ibm.com/developerworks/library/se-prevent/

The following code snippet shows how we can use this EscapeUtils library to implement output encoding in the code snippet shown earlier.

Following is the code within the library EscapeUtils.

import java.io.IOException;

import java.io.StringWriter;

import java.io.Writer;

import java.util.HashMap;

public class EscapeUtils {

 

    public static final HashMap m = new HashMap();

    static {

        m.put(34, "&quot;"); // < - quote

        m.put(60, "&lt;");   // < - less-than

        m.put(62, "&gt;");   // > - greater-than

    //User needs to map all html entities with their corresponding decimal values. 

     //Please refer to below table for mapping of entities and integer value of a char

              }

 

    public static String escapeHtml(String input) {

        String str = input;

        try {

            StringWriter writer = new StringWriter((int) 

                           (str.length() * 1.5));

            escape(writer, str);

            System.out.println("encoded string is " + writer.toString() );

            return writer.toString();

           } catch (IOException ioe) {

            ioe.printStackTrace();

            return null;

                                                    }

                                                     }

 

    public static void escape(Writer writer, String str) throws IOException {

        int len = str.length();

        for (int i = 0; i < len; i++) {

            char c = str.charAt(i);

            int ascii = (int) c;

            String entityName = (String) m.get(ascii);

            if (entityName == null) {

                if (c > 0x7F) {

                    writer.write("&#");

                    writer.write(Integer.toString(c, 10));

                    writer.write(';');

                } else {

                    writer.write(c);

                }

            } else {

                     writer.write(entityName);

            }

        }

    }

}

 

As you can notice in the code highlighted above, the following lines are added to EscapeUtils.java.

m.put(34, "&quot;"); // < - double quote

m.put(60, "&lt;");   // < - less-than

m.put(62, "&gt;");   // > - greater-than

We are mapping html entities with their corresponding decimal values. So, whenever a defined html code is detected, it will be safely encoded. As you can see, not all the characters are listed here. So, developers need to map all html entities with their corresponding decimal values. 

Secure source code example:

String studentid = request.getParameter("studentid");

if(studentid.isEmpty()) {

 

request.setAttribute("examresult","Please enter a value");

RequestDispatcher rd=request.getRequestDispatcher("/Home.jsp");            

rd.include(request, response);

}

else {

try{

       *** truncated ***   }

if(nodeList.getLength() > 0){

  *** truncated ***

  }

else {

studentid = EscapeUtils.escapeHtml(studentid);

     request.setAttribute("examresult","No Results found for the input"+studentid);

     RequestDispatcher          rd=request.getRequestDispatcher("/Home.jsp");            

rd.include(request, response);

}

}

 

As highlighted in the preceding excerpt, the data received by the application is passed to EscapeUtils.escapeHtml() function before it is used by the application. Any special characters that go through EscapeUtils.escapeHtml() will be encoded and the characters are displayed back on the page.

If the payload <script>alert(1);</script> goes through this code, it will be encoded as highlighted below.

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">

<title>Exam Results</title>

*** truncated ***

</head>

<body>

    <!--  Check if a valid session exists  -->

    

    

    <div class="formclass">

    

    <form action="Logout" method="post">

    <input type="submit" name="btnLogout" class="input" value="Logout" style="width: 60px;margin-left: 300px;"/></input><br />

    </form>

    

    <form action="GetResults" method="post">

        <h2><label for="txtout" class="input">welcome bob</label></h2>  

        <input type="text" name="studentid" class="input" placeholder="Enter your student ID Here" style="width: 275px"></input><br /><br />

        

        <input type="submit" name="btnLogin" class="input" value="Get Re-sults"/></input><br /><br />

        

      

        <h3><label for="txtout" class="input"><font color=white size=4px>No Results found for the input &lt;script&gt;alert(1);&lt;/script&gt;</font>

</label></h3>  

   

    </form>

     </div>

</body>

</html>

Learn Secure Coding Fundamentals

Learn Secure Coding Fundamentals

Build your secure coding skills as you progress through 14 courses focused on discovering, exploiting and mitigating common coding vulnerabilities.

Conclusion:

Cross Site Scripting vulnerabilities are often taken for granted with an assumption that they are not dangerous. Developers must be aware of the causes and ways to mitigate them. This article has provided practical examples of how Cross Site Scripting vulnerabilities can be mitigated by using Input Validation and Output Encoding. 

 

Sources:

  1. https://owasp.org/www-community/attacks/xss/
  2. https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html
  3. https://owasp.org/www-project-top-ten/
Srinivas
Srinivas

Srinivas is an Information Security professional with 4 years of industry experience in Web, Mobile and Infrastructure Penetration Testing. He is currently a security researcher at Infosec Institute Inc. He holds Offensive Security Certified Professional(OSCP) Certification. He blogs atwww.androidpentesting.com. Email: srini0x00@gmail.com