Secure Coding Practices – Cross-Site Scripting (XSS)

Overview

Cross-Site Scripting (XSS) is a type of injection attack. This attack targets end users by running malicious script on user’s browser and steal active session id to gain unauthorized access to user’s account. JavaScript is used to develop malicious scripts which executes in all web browsers. There are 3 variations of cross-site scripting –

  1. Reflected Cross-Site Scripting
  2. Stored Cross-Site Scripting
  3. DOM-based Cross-Site Scripting

Reflected Cross-Site Scripting Reflected XSS is the type where the malicious script is sent to web server and then reflected to end user. The different application functionalities used in this type of XSS are error message, search result, or any application page/message shown to user that includes all or part of user input. Reflected XSS malicious script is delivered to victim via email or chat messages or through another website such as – discussion forum, blog etc.

Stored Cross-Site Scripting In stored XSS, malicious script is stored in the database and delivered to victim user as a search result. A scenario to understand stored XSS is maker checker implementation. A maker creates a malicious entry in the vulnerable application which is stored in the application database and then sent to checker user for approval. When checker user checks its approval queue and clicks on malicious entry, the malicious script in that entry executed in checker user’s browser and session id of checker user is sent to maker user who uses the active session id to access checker user’s account and programs malicious actions on checker user’s behalf.

DOM based Cross -Site Scripting – DOM based XSS is different from the other 2 types of XSS in the way malicious script is executed in victim user’s browser. In this type of XSS, malicious script provided in the application by an attacker never hits the web server. The malicious script resides in the user side and modifies DOM of the target application. An attacker can create a new or modify an existing DOM object in the target application and steal session id.

Further in this post, we are going to discuss how developers can fix the code to prevent Cross-Site Scripting in their applications developed using different types of programming language.

How to Fix

Generic mitigation approaches for Cross-Site Scripting (XSS) vulnerability are –

  1. Implement whitelist validation of user inputs
  2. Sanitize data before presenting to end users
  3. HttpOnly cookie attribute

The challenge developers face is to find how these generic statements be enforced at code level. The next section illustrates the code level implementation for common programming languages.

Enforcement at Code Level

  1. Input Validation
  • Java/ JSP – Implement whitelist validation with help of regular expressions. A regular expression is a string whose pattern defines which characters are allowed in the data being validated. Regular expressions perform pattern matching. Java supports pattern matching via Regex API (java.util.regex package). The API consists of 3 classes – Pattern, Matcher and PatternSyntaxException.
  • Username
    ^[a-z0-9_-]{3,15}$
^ Start of the line
[a-z0-9_-] Match characters and symbols in the list, a-z, 0-9, underscore, hyphen
{3,15} Length at least 3 characters and maximum length of 15
$ End of the line
  • Password
    ((?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%]).{6,20})
( Start of group
(?=.*\d) must contains one digit from 0-9
(?=.*[a-z]) must contains one lowercase characters
(?=.*[A-Z]) must contains one uppercase characters
(?=.*[@#$%]) must contains one special symbols in the list “@#$%”
. match anything with previous condition checking
{6,20} length at least 6 characters and maximum of 20
) End of group
  • Email
    ^[_A-Za-z0-9-]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$
^ start of the line
[_A-Za-z0-9]+ must start with string in the bracket [ ], must contains one or more (+)
( start of group #1
\\.[_A-Za-z0-9-]+ follow by a dot “.” and string in the bracket [ ], must contains one or more (+)
)* end of group #1, this group is optional (*)
@ must contains a “@” symbol
[A-Za-z0-9]+ follow by string in the bracket [ ], must contains one or more (+)
( start of group #2 – first level TLD checking
\\.[A-Za-z0-9]+ follow by a dot “.” and string in the bracket [ ], must contains one or more (+)
)* end of group #2, this group is optional (*)
( start of group #3 – second level TLD checking
\\.[A-Za-z]{2,} follow by a dot “.” and string in the bracket [ ], with minimum length of 2
) end of group #3
$ end of the line
  • IP Address
    ^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])$
^ start of the line
( start of group #1
[01]?\\d\\d? Can be one or two digits. If three digits appear, it must start either 0 or 1
| Or
2[0-4]\\d start with 2, follow by 0-4 and end with any digit (2[0-4][0-9])

 

| Or
25[0-5] start with 2, follow by 5 and end with 0-5 (25[0-5])
) end of group #2
\. follow by a dot “.”
Repeat above steps 3 times
$ end of the line
  • Time in 12-Hour Format
    (1[012]|[1-9]):[0-5][0-9](\\s)?(?i)(am|pm)
  • Time in 24-Hour Format
    ([01]?[0-9]|2[0-3]):[0-5][0-9]
  • Date
    (0?[1-9]|[12][0-9]|3[01])/(0?[1-9]|1[012])/((19|20)\\d\\d)
  • Phone Number
    \\d{10}
  • HTML ‘a’ Tag
    (?i)<a([^>]+)>(.+?)</a>
  • HTML Link
    \s*(?i)href\s*=\s*(\"([^"]*\")|'[^']*'|([^'">\s]+))

Sample Code –

import java.util.regex.Matcher;

import java.util.regex.Pattern;

&nbsp;

public class RegexMatches {

&nbsp;

public static void main( String args[] ) {

<em>// String to be scanned to find the pattern</em>

String line = "This order was placed for QT3000! OK?";

String pattern = "(.*)(\\d+)(.*)";

&nbsp;

<em>// Create a Pattern object</em>

Pattern r = Pattern.compile(pattern);

&nbsp;

<em>// Now create matcher object</em>

Matcher m = r.matcher(line);

if (m.find( )) {

System.out.println("Found value: " + m.group(0) );

System.out.println("Found value: " + m.group(1) );

System.out.println("Found value: " + m.group(2) );

}else {

System.out.println("NO MATCH");

}

}

}

Output –

Found value: This order was placed for QT3000! OK?

Found value: This order was placed for QT300

Found value: 0

 

  • .Net – ‘validateRequest’ is a feature in .Net framework which analyzes HTTP requests and determines if HTTP requests contain any malicious content. This feature protects from malicious contents in HTTP request body, URL and cookie. Request validation is enabled by default in ASP.NET, validateRequest status can be checked in web.config file –

 

<pages validateRequest="true" />

 

Though validateRequest provides a very simple way to protect applications from XSS attacks, there are methods to bypass (JSON requests, file upload, Unicode encoding etc.) this check. Therefore, developers should not rely on validateRequest alone for XSS protection. ASP.NET also provides the following validation controls –

  • RequiredFieldValidator
  • RangeValidator
  • CompareValidator
  • RegularExpressionValidator
  • CustomValidator
  • ValidationSummary

An example of RegularExpressionValidator to accept only Alphanumeric (Alphabets and Numbers) in TextBox using RegularExpression Validator –

<asp:TextBox ID="TextBox1" runat="server" />

<br />

<asp:RegularExpressionValidator ID="RegularExpressionValidator1" runat="server" ControlToValidate="TextBox1" ForeColor = "Red" ValidationExpression="[a-zA-Z0-9]*$" ErrorMessage="*Valid characters: Alphabets and Numbers." />

<br />

<asp:Button ID="Button1" Text="Validate" runat="server" />

 

  • PHP – PHP has built in functions that allows developers to implement regular expressions in PHP applications. Below are the commonly used regular expression functions in PHP –
  • preg_match – this function is used to perform a pattern match on a string. It returns true if a match is found and false if a match is not found.
  • preg_split – this function is used to perform a pattern match on a string and then split the results into a numeric array.
  • preg_replace – this function is used to perform a pattern match on a string and then replace the match with the specified text.

Sample code –

<?php

$my_email = "contact@affluxconsulting.com";

if (preg_match("/^[a-zA-Z0-9._-]+@[a-zA-Z0-9-]+.[a-zA-Z.]{2,5}$/", $my_email)) {

echo "$my_email is a valid email address";

}

else

{

echo "$my_email is NOT a valid email address";

}

?>

Sample regular expression patterns –

  • Password complexity (at least one upper case letter, one lower case letter and one digit)
    A(?=[-_a-zA-Z0-9]*?[A-Z])(?=[-_a-zA-Z0-9]*?[a-z])(?=[-_a-zA-Z0-9]*?[0-9])[-_a-zA-Z0-9]{6,}z
  • Domain name
    /^(http|https|)://([A-Z0-9][A-Z0-9_-]*(?:.[A-Z0-9][A-Z0-9_-]*)+):?(d+)?/?/i
  • Email
    /^[a-zA-Z0-9._-]+@[a-zA-Z0-9-]+.[a-zA-Z.]{2,5}$/

 

  1. Output Encoding
  • Java/ JSP – OWASP Java Encoder is a simple-to-use Java encoder class which can perform output encoding and prevent application against all types of XSS attacks.

Sample Code –

PrintWriter out = ....;

out.println("<textarea>"+Encode.forHtml(userData)+"</textarea>");

The OWASP Java Encoder documentation is available at https://www.owasp.org/index.php/OWASP_Java_Encoder_Project#tab=Use_the_Java_Encoder_Project

  • .Net – Use the HttpUtility.HtmlEncode method to encode output if it contains input from the user or from other sources such as databases. HtmlEncode replaces characters that have special meaning in HTML-to-HTML variables that represent those characters. For example, < is replaced with &lt; and ” is replaced with &quot;. Encoded data does not cause the browser to execute code. Instead, the data is rendered as harmless HTML. Similarly, use HttpUtility.UrlEncode to encode output URLs if they are constructed from input.

Sample Code –

<%@ Page Language="C#" AutoEventWireup="true"%>

<html>

<form id="form1" runat="server">

<div>

Color:&nbsp;<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox><br />

<asp:Button ID="Button1" runat="server" Text="Show color"

OnClick="Button1_Click" /><br />

<asp:Literal ID="Literal1" runat="server"></asp:Literal>

</div>

</form>

</html>

<script runat="server">

private void Page_Load(Object Src, EventArgs e)

{

protected void Button1_Click(object sender, EventArgs e)

{

Literal1.Text = @"<span style=""color:"

+ Server.HtmlEncode(TextBox1.Text)

+ @""">Color example</span>";

}

}

</Script>

 

  • PHP – PHP provides multiple methods to escape output. These methods can be used in conjunction. For example – names doesn’t need to contain HTML tags, so just use the default FILTER_SANITIZE_STRING filter, and it will remove HTML and PHP tags. The second thing to do is to escape your output using the htmlspecialchars() function. Either approach will help on its own, but both should be used in the application.
<?php

$name = filter_input(INPUT_GET, 'name', FILTER_SANITIZE_STRING);

echo 'Hi '. htmlspecialchars($name, ENT_COMPAT, 'UTF-8');

 

  1. HttpOnly Cookie Attribute

HttpOnly is an additional flag included in a Set-Cookie HTTP response header. HttpOnly flag in cookie helps mitigating the risk of XSS attack by preventing client-side script (JavaScript) accessing the cookie parameters (if the browser supports it). If a browser does not support HttpOnly and a website attempts to set an HttpOnly cookie, the HttpOnly flag will be ignored by the browser, thus creating a traditional, script accessible cookie. As a result, the cookie (typically your session cookie) becomes vulnerable to theft of modification by malicious script.

  • Java/ JSP – Since Java Enterprise Edition 6 (JEE 6), which adopted Java Servlet 3.0 technology, it’s programmatically easy to set the HttpOnly flag on a cookie.
Cookie cookie = getMyCookie("myCookieName");

cookie.setHttpOnly(true);

Since JEE 6 it is easy setting HttpOnly flag in a session cookie by applying the following configuration in the WEB-INF/web.xml –

<session-config>

<cookie-config>

<http-only>true</http-only>

</cookie-config>

</session-config>
  • .Net – The following code example demonstrates how to set HttpOnly flag –
<%@ Page Language="C#" %>

&nbsp;

<script runat="server">

void Page_Load(object sender, EventArgs e)

{

<em>        // Create a new HttpCookie.</em>

HttpCookie myHttpCookie = new HttpCookie("LastVisit", DateTime.Now.ToString());

&nbsp;

<em>        // By default, the HttpOnly property is set to false unless specified otherwise in configuration.</em>

myHttpCookie.Name = "MyHttpCookie";

Response.AppendCookie(myHttpCookie);

&nbsp;

<em>        // Show the name of the cookie.</em>

Response.Write(myHttpCookie.Name);

&nbsp;

<em>        // Create an HttpOnly cookie.</em>

HttpCookie myHttpOnlyCookie = new HttpCookie("LastVisit", DateTime.Now.ToString());

&nbsp;

<em>        // Setting the HttpOnly value to true, makes this cookie accessible only to ASP.NET.</em>

myHttpOnlyCookie.HttpOnly = true;

&nbsp;

myHttpOnlyCookie.Name = "MyHttpOnlyCookie";

Response.AppendCookie(myHttpOnlyCookie);

&nbsp;

<em>        // Show the name of the HttpOnly cookie.</em>

Response.Write(myHttpOnlyCookie.Name);

}

</script>

 

  • PHP – PHP supports setting the HttpOnly flag since version 5.2.0. For session cookies managed by PHP, the flag is set permanently in php.ini PHP manual on HttpOnly through the parameter –
session.cookie_httponly = True

 

We offer training on secure coding practices customized as per developers’ skillsets and development methodologies. Also, our services include development of secure coding guidelines. Please visit Application Security section in Service Offerings or Contact Us to hear more from us.