6

I'm following the Injection Vulnerability Prevention module on Salesforce Trailhead, and I'm reading about the Visualforce functions to encode data to prevent XSS attacks.

To quote from the module:

In Visualforce, the platform has three main encoding functions that developers can use to neutralize potential XSS threats: HTMLENCODE, JSENCODE, and JSINHTMLENCODE. To choose which encoding to use, consider how your browser is parsing the output.

If the value is going to be parsed by the JavaScript parser, use JSENCODE().

If the value is going to be parsed by the HTML parser, use HTMLENCODE().

If it’s a combination of both use:

JSENCODE(HTMLENCODE())

-Or-

JSINHTMLENCODE()

My question is, why is there not a universal ENCODE() function which encapsulates all three? Is there a performance difference? Is the encoding succintly different to warrant 3 seperate functions? Why should I not just use JSINHTMLENCODE() for all my encoding needs?

3
  • 3
    This is more a conceptual question than a Visualforce question. I suspect that the reason for 3 different encoders is because you're encoding in different contexts. HTML encoding is very different from Javascript encoding, which is very different to encoding strings in Apex, etc. Each language has its own encoding rules. I did not dare to post this as an answer as I have never used the functions above.
    – mkorman
    Jan 10, 2017 at 15:05
  • Thank you @mkorman, I'm wondering why JSINHTMLENCODE does not cover the other functions. While they might all encode to different results, would JSINHTMLENCODE not cover all bases?
    – user24634
    Jan 10, 2017 at 15:13
  • 1
    Yes but it might screw you up to have it html encoded when you only need js, or vice versa.
    – Adrian Larson
    Jan 10, 2017 at 15:15

1 Answer 1

6

Note that there are four encoding functions, not three. You forgot about URLENCODE. Here's an article that would really help you to read: Unescaped Output and Formulas in Visualforce Pages.

If you play around with the demo page provided there, you may better understand why you wouldn't want to encode for both JS and HTML when you only need one or the other. If you're just pulling a page parameter into your script and want to build logic around it, encoding the data for html may break your logic or add extra unnecessary work for yourself. Same goes for markup, if you just need it in your markup and you encode it for JS, you'll get some wonky results.

The key passage is here:

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.

More extensively quoted (emphasis added):

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>
2
  • 1
    This is the reason why I posted my very brief answer as a comment instead :)
    – mkorman
    Jan 10, 2017 at 15:37
  • 1
    @mkorman Although you basically had the key passage down! Anyway good to see you back on the exchange! Hadn't seen your name pop up in a while.
    – Adrian Larson
    Jan 10, 2017 at 15:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy