Best practices to avoid cross-site scripting (XSS) vulnerabilities
- Hijacking the user session
- Defacing websites
- Introducing worms, bots, or viruses
- Sending spam email
Pega Platform includes features and facilities that prevent many security vulnerabilities, and Pegasystems routinely tests for and analyzes potential security issues. However, the many software layers in use (network, email, application server, database, firewalls, and so on) make security an ongoing challenge. The practices described in this article address only one dimension of security, but one that has been heavily exploited when ignored.
Pega recommends using the following best practices to protect against the most common ways that cross-site scripting (XSS) attacks gain access to a client browser:
- Follow the Guardrails
- Filter all inputs
- Filter HTML and XML outputs
- PublicAPI methods for XSS filtering
These practices are always important whether or not your application:
- Is used by unauthenticated users
- Is exposed to a large community or embedded as a web mashup in other applications
- Runs in a less-secure network
- Runs in a less-secure physical environment
- Includes stream rules that are not autogenerated
The best practices and the built-in features of Pega Platform are intended to help you build more secure applications by avoiding specific, well-known vulnerabilities.
Follow the design and implementation guardrails described in Ten Guardrails to Success.
In a guardrail-compliant application, application rulesets contain only autogenerated flow actions, autogenerated sections, and autogenerated harness rules. The application might use standard rules that are not autogenerated.
Prevent invalid data from entering a work object or a work object attachment. Filter and validate input data as thoroughly as possible, including input that is submitted from browser forms, input from service requests (such as email), and input from connector responses. Do not rely on client-side editing, which is in the browser, because a hacker can easily bypass it. Perform validation in your server-side application logic.
Use the following features to validate individual values:
- Alllow lists – Several features let you constrain a property value to one of a fixed list or pattern of values, including the property table edits (local list, field values, class key values) on the General tab in Pega Platform 5.5 and later versions, or the Table Edit tab in earlier releases.
- Special properties – Select the Cannot be included as an input field check box if the property is always computed from other values.
- Validation – Identify an edit input rule and an edit validate rule when possible. Do not accept angle brackets, quotation marks, ampersands, or other special characters in fields unless necessary for a sound business reason. For example, the standard validation rule LetterorDigit limits values to only letters and digits. On the PRPC 5.5 property form, the Max Length and Validate fields are displayed on the Advanced tab.
- Use map value rules, validation rules, and constraints rules to validate inputs.
- Ensure that files that are uploaded from application user workstations and text files processed by a file listener are checked against viruses.
Output from autogenerated harness, section, and flow action rules is automatically output-filtered. Application developers do not need a special approach for such rules. (This is applicable to Pega Platform 5.3 SP1 or later versions.)
In any non-autogenerated (manually created) stream rules (correspondence, paragraph rules, XML, HTML, flow actions, harness, or sections), use only Pega Platform JSP tags to ensure that output filtering occurs. Note these specific cases:
- Even when you manually create only a portion of a full HTML or XML document, make the HTML code that your rules produce well-formed in terms of matching begin-end tags, matched quotation marks, use of only legitimate HTML tags, and correct nesting of tags. Various browser versions render malformed HTML in unpredictable ways, and some browsers become vulnerable to bugs and quirks after rendering malformed HTML code.
- For the
<p:r>tag, omit the mode attribute to provide complete XSS filtering. This is the default when your tag omits the mode attribute. Avoid
mode=literal, which disables XSS filtering. Use
- For the
<pega:lookup>tag in PRPC 5.5 applications, avoid
mode=literal. In versions prior to PRPC 5.5, the mode attribute is not available, and all uses of the
<pega:lookup>tag provide XSS filtering.
- Filter any potential-risk text value for XSS vulnerability using a Java scriptlet that calls one of two PublicAPI methods.
Output filtering involves replacing sensitive characters in the source HTML code such as angle brackets (
< and >), single and double quotation marks, ampersands, and others by the equivalent HTML character entities, such as < for < or ' for an apostrophe. If the source text is legitimate, output filtering does not prevent correct HTML rendering by the browser.
Use these two Java methods to provide output filtering:
- StringUtils.crossScriptingFilter(aValue) – Filters the contents of aValue and returns a filtered (encoded) version. Available in PRPC 5.3 SP1 and later versions.
- StringUtils.reversibleCrossScriptingFilter(aValue) – Filters the contents of aValue and reverse-filters the value in the server if the same value is resubmitted in subsequent requests. This method ensures that the friendly user’s intent is preserved. It was introduced in Pega Platform 5.5, and available in Pega Platform 5.3 SP1 and later versions through on-request hotfixes.
Use reversibleCrossScripting() when the internal clipboard value is not to be modified, but the value sent to the browser is to be filtered. For example, if an application user needs to search a customer master file for a customer named Molly O'Brian, the SQL statement (on the server) needs to process using the apostrophe (single quotation mark) character ('), but the browser display uses the HTML entity ' or an equivalent. In this case, a separate escape mechanism for SQL also applies, converting the name O'Brian to O\'Brian.
The following examples are portions of manually created stream rules that are modified to filter a value using these two PublicAPI functions in an inline Java scriptlet.
<pega:reference name=$save(savename) />
<% tools.appendString(StringUtils.reversibleCrossScriptingFilter(tools.getParamValue("paramname"))); %>