When using components that have set the escape attribute to false, or when
including formulas outside of a Visualforce component, output is unfiltered and must be validated for security.
This is especially important when using formula expressions.
Formula expressions can be function calls or include information about platform objects, a user's
environment, system environment, and the request environment. It’s important to be aware that
the output that’s generated by expressions isn’t escaped during rendering. Since expressions
are rendered on the server, it’s not possible to escape rendered data on the client using
JavaScript or other client-side technology. This can lead to potentially dangerous situations
if the formula expression references non-system data (that is, potentially hostile or editable
data) and the expression itself is not wrapped in a function to escape the output during
rendering.
A common vulnerability is created by rerendering user input on a page. For example,
<apex:page standardController="Account">
<apex:form>
<apex:commandButton rerender="outputIt" value="Update It"/>
<apex:inputText value="{!myTextField}"/>
</apex:form>
<apex:outputPanel id="outputIt">
Value of myTextField is <apex:outputText value="{!myTextField}" escape="false"/>
</apex:outputPanel>
</apex:page>
The unescaped
{!myTextField} results in a cross-site scripting vulnerability. For example, if
the user enters :
and clicks
Update It, the JavaScript is executed.
In this case, an alert dialog is displayed, but more malicious uses
could be designed.
There are several functions that you can use for escaping potentially
insecure strings.
- HTMLENCODE
- Encodes text and merge field values for use in HTML by
replacing characters that are reserved in HTML, such as the greater-than sign (>),
with HTML entity equivalents, such as >.
- JSENCODE
- Encodes text and merge field values for use in JavaScript
by inserting escape characters, such as a backslash (\), before unsafe JavaScript
characters, such as the apostrophe (').
- JSINHTMLENCODE
- Encodes text and merge field values for use in
JavaScript inside HTML tags by replacing characters that are reserved in HTML with
HTML entity equivalents and inserting escape characters before unsafe JavaScript
characters. JSINHTMLENCODE(someValue) is a convenience
function that is equivalent to JSENCODE(HTMLENCODE((someValue)). That is,
JSINHTMLENCODE first encodes
someValue with HTMLENCODE, and then encodes the result with JSENCODE.
- URLENCODE
- Encodes text and merge field values for use in URLs by
replacing characters that are illegal in URLs, such as blank spaces, with the code
that represent those characters as defined in RFC 3986, Uniform Resource
Identifier (URI): Generic Syntax. For example, blank spaces are replaced
with %20, and exclamation points are
replaced with %21.
To use
HTMLENCODE to secure
the previous example, change the
<apex:outputText> to the following:
<apex:outputText value=" {!HTMLENCODE(myTextField)}" escape="false"/>
If a user enters
<script>alert('xss') and clicks
Update It, the JavaScript is not
be executed. Instead, the string is encoded and the page displays
Value of myTextField is <script>alert('xss').
Depending on the placement of the tag and usage of the data, both the characters needing escaping
as well as their escaped counterparts may vary. For instance, this statement, which copies a
Visualforce request parameter into a
JavaScript
variable:
<script>var ret = "{!$CurrentPage.parameters.retURL}";</script>
requires
that any double quote characters in the request parameter be escaped with the URL encoded
equivalent of
%22 instead of the HTML escaped
". Otherwise, the
request:
http://example.com/demo/redirect.html?retURL=%22foo%22%3Balert('xss')%3B%2F%2F
results
in:
<script>var ret = "foo";alert('xss');//";</script>
When
the page loads the JavaScript executes, and the alert is displayed.
In this case, to prevent JavaScript from being executed, use the
JSENCODE function. For
example
<script>var ret = "{!JSENCODE($CurrentPage.parameters.retURL)}";</script>
Formula tags can also be used to include platform object data. Although the data is taken
directly from the user's organization, it must still be escaped before use to prevent users
from executing code in the context of other users (potentially those with higher privilege
levels). While these types of attacks must be performed by users within the same organization,
they undermine the organization's user roles and reduce the integrity of auditing records.
Additionally, many organizations contain data which has been imported from external sources
and might not have been screened for malicious content.