Best Practices - Cross Site Scripting (XSS)

Cross Site Scripting (XSS)

Vulnerability Overview

Cross-Site Scripting (XSS) (CWE-79) attacks are a type of injection, in which malicious scripts are injected into otherwise benign and trusted websites. XSS attacks occur when an attacker uses a web application to send malicious code, generally in the form of a browser side script, to a different end user.

The XSS flaw occurs when:

  • Data enters a Web application through an untrusted source, most frequently a web request.

  • The data is included in dynamic content that is sent to a web user without being validated for malicious content.

There are 2 main types of XSS vulnerabilities:

  1. Reflected XSS attacks are those where the injected script is reflected off the web server, such as in an error message, search result, or any other response that includes some or all of the input sent to the server as part of the HTTP request.

  2. Stored XSS attacks are those where the injected script is permanently stored on the target servers, such as in a database.

Recommended Security Controls

According to the OWASP​ and ​MITRE​ recommendations, to be protected against XSS applications must:

  1. Understand the context in which the untrusted data will be used and the encoding that will be expected.

  2. Use structured mechanisms that automatically enforce the separation between data and code. These mechanisms may be able to provide the relevant quoting, encoding, and validation automatically, instead of relying on the developer to provide this capability at every point where output is generated.

How Waratek’s Protection Works

Waratek offers protection against XSS attacks via the xss feature in the ARMR HTTP rule. This rule uses the tainting engine to track all user input, hooks into the web application's Servlet API and monitors all the write operations to the HTTP response. When a servlet write operation occurs, the Waratek agent uses a streaming tainted HTML 5.0 lexer and checks if any sequence of user-controllable (tainted) characters mutate the HTML syntax.

By default, the XSS rule will:

  1. protect only against reflected XSS attacks (i.e. payloads coming from HTTP requests)

  2. protect the HTTP responses of all HTTP endpoints that produce HTML responses

To enable protection against stored XSS attacks then the input declaration in the ARMR HTTP rule must be configured with the value “database”. For example: input(database)

To enable protection against both reflected and stored XSS attacks then the input declaration in the ARMR HTTP rule must be configured with the values “http” and “database”. For example: input(http, database)

In most cases, defining the above XSS rule would provide the required level of protection.

In addition, Waratek can also protect against attacks coming from deserialized data. For example, from protocols such as RMI, JMX and the XMLReader that are based on Java or XML deserialization. To enable protection against deserialized payloads, add the “deserialization“ value to the input declaration in the ARMR HTTP rule. For example: input(http, database, deserialization)

To enable XSS security control, the default XSS rule can be specified. In some rare cases, users might need to specify additional XSS rules. There are 2 main reasons for this:

  • an application might produce HTTP responses whose output is HTML but the content-type is incorrectly set by the application. For example, the HTTP endpoint generates HTML but its content-type is XML.

  • different HTTP endpoints might require different taint sources to be configured.

In such cases, users can define additional XSS rules and specify in each additional XSS rule the relative path of the HTTP endpoint for which XSS protection must be enforced and optionally the source of tainted data. For example:

 

app("XSS"):
  requires(version: ARMR/2.8)
  http("XSS Protection"):
    xss(html)
    response(paths: "/pathOne")
    input(database, deserialization)
    protect(message: "XSS attacked identified and blocked", severity: 7)
  endhttp
endapp

 

Finally, it is important to note that by default the XSS rule is enabled in a non-strict lexing mode. This means that the XSS rule will allow certain user inputs to be injected (i.e. to mutate the HTML syntax). These certain inputs have been vetted as non-malicious and are only formatting. This allows common WYSIWYG editors and markup languages such as markdown to be used. This feature is also called Safe XSS Injection. To disable the safe injection feature and enable the strict lexing mode, use the policy option in the xss declaration. For example: xss(html, options: {policy: strict})

Protective Action

When the XSS rule is enabled in deny mode and an XSS attack is identified then the malicious HTTP output operation is terminated and no further writing to the HTTP response is allowed.

Rule Applicability

The XSS rule is applicable and can be safely enabled for web applications that use the Servlet API to handle HTTP requests and responses.

Only reflected XSS and stored XSS for HTML is currently supported. Protection against pure JavaScript or CSS (Cascading Style Sheets) payloads are not yet supported.

Best Practices

In most cases, defining the following XSS rule would provide the required level of protection.

 

app("XSS"):
  requires(version: ARMR/2.8)
  http("XSS Protection"):
    response()
    xss(html)
    input(http, database)
    protect(message: "XSS attacked identified and blocked", severity: Very-High)
  endhttp
endapp

References

https://cwe.mitre.org/data/definitions/79.html

https://owasp.org/www-community/attacks/xss/

https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html