16

In OWASP recommendations regarding escaping untrusted input for HTML element content, they list the following:

& --> &
< --> &lt;
> --> &gt;
" --> &quot;
' --> &#x27;  &apos; not recommended because its not in the HTML spec (See: section 24.4.1) &apos; is in the XML and XHTML specs.
/ --> &#x2F;  forward slash is included as it helps end an HTML entity

What is the purpose of including / in there? Indeed, / is part of the ending entity, but since we're already escaping < and AFAIK no known browser would accept / without preceding < as entity end, what is the reason to escape it?

5 Answers 5

10

Back before HTML 5 came with a standard parsing algorithm, HTML 4 was defined based on SGML. And its SGML-based syntax had features that differed in terms of browser support and differed in terms of people being aware of them.

One of the more obscure features that you'll be interested in, for the purposes of this question, is Null End Tag (NET). Have a look at the following code for an HTML page:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
  "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title/hello/
<body>
<p/hello/

If you want, try putting it through an HTML validator. NET specifies that code like <TAGNAME/text/ is parsed into the same thing you'd get from <TAGNAME>text</TAGNAME>.

From here, you may be able to see why it's a good idea to escape the / character when interpolating user-provided data into markup. A / could potentially end up in one of these NET constructions and be interpreted as the end tag, instead of a literal solidus.

Sure no browser now understands the NET syntax, but it's part of the spec, so it's prudent to account for it.

4
  • The question is regarding element content (see owasp link), where NET would be irrelevant. The attacker would need to inject into a tag to achieve this attack. Mar 15, 2018 at 20:19
  • echo "<p/$usertext/"; is a case where you would be writing element content (I checked the OWASP link just now, and I think that's what it means?) and NET would be relevant.
    – guest
    Mar 15, 2018 at 20:54
  • But if no browser understands that, why would it be an injection point? I.e. the page would never have been authored that way in the first place. Mar 15, 2018 at 20:58
  • to answer that question, let's assume that no browser understands NET (although note that that's not what I claim in the answer). there's software other than browsers that interact with the web and that do understand NET. in fact, the online HTML validator is one such piece of software (not a perfect example here though, since it doesn't execute scripts). having a way to ensure your applications are safe to use with such software is a nice thing. and having practices that don't depend on the proposition that "the page would never have been authored tat way" is also a nice thing.
    – guest
    Mar 16, 2018 at 20:07
6

Your question asks "Why /?".

However you don't seem to be concerned about >, " and '?

Technically, to ensure security within element content you only need to encode the < and & characters because HTML tags cannot start with >, ", ' or /. Note that I am only talking about HTML here (not XHTML).

To answer your question the reason is that / is an HTML character with special meaning. If you are following the OWASP guidelines it is assumed that you want your system to be secure and it is always best to err on the side of caution since there are little downsides to doing so in this case.

If you want to be minimalistic check out the OWASP XSS Experimental Minimal Encoding Rules.

3
  • 1
    Thanks for the link to minimal rules. They make much more sense, actually.
    – StasM
    Feb 4, 2014 at 19:02
  • 1
    " and ' are encoded so that the encoded string can be used as the value of an attribute (<img title="encoded username goes here" ...>).
    – Macil
    Feb 15, 2017 at 21:57
  • @age The question is regarding why to HTML Escape Before Inserting Untrusted Data into HTML Element Content, not for attributes. Feb 16, 2017 at 7:59
3

When a character has syntactical meaning in any context, you should be wary, and err on the side of escaping it.

If for instance an attacker has found a way to inject it at the end of some existing tag, they can create a tag like <br /> which does not require ending; the transformation could change the meaning of the document.

I apologize that I don't have a concrete example for you beyond that, but it costs very little to escape it, so the tradeoff is certainly in favour of doing so.

I see no particular reason for it besides a safeguard against other bugs or mistakes being rendered exploitable by this particular inclusion. It isn't an especially strong recommendation in that no PoC can be universally developed to show its necessity, but there is no harm whatsoever in following it.

4
  • Well, then they should suggest escaping pretty much any non-alphanum character, since most of them have significance in some context. They don't do it. They correctly identify the characters that may be significant in HTML, but then add / which is not. Also, you can not inject <br/> since < and > are encoded, so you could inject only &lt;br/&gt; - what's wrong with that?
    – StasM
    Feb 4, 2014 at 7:01
  • 2
    For a concrete example, phpBB used to have a bug in how it turned BBCode into HTML, with the result that [b /><script onclick=alert()>Foo<b] would become <b /><script onclick=alert()>Foo<b></b>.
    – Mark
    Feb 4, 2014 at 7:37
  • 2
    @StasM I think you might be making the mistake of thinking that the OWASP is completely infalliable and has ironclad reasons for everything they do. In security it is usually better to err on the side of caution, and looking at this closely it looks like that is precisely what is up. You could err further in that direction if you so desired, certainly. Feb 4, 2014 at 8:56
  • 1
    @FalconMomot in general, it is, but adding random characters to escape list just doesn't make sense. Why won't they then suggest to add letter Z to the list? Just to be cautious, maybe it's dangerous too. It just looks completely random, sorry.
    – StasM
    Feb 4, 2014 at 18:58
2

"as far as I know..." is the root of many bugs, failing to encode dangerous characters. It is the 'blacklist' approach to encode only the things you know are dangerous instead of not-encoding only the things you know are not dangerous.

For an example, imagine that the server sets an HTML tag attribute's value to user input...

<input value=userdata>

The above is completely legal and valid HTML. Many web pages do not encapsulate their values in quotes, and browsers interpret this correctly.

Now, assume you use the OWASP list that you included at the top of the page. Note that space is not in the list....

<input value=foo onclick=alert()>

Now we have a successful attack. We have used space to break out of the previous context, then equal sign to set a context where we can write javascript, and parenthesis to execute a function. None of these were in the (broken) blacklist you showed.

With this same attack (using space to break out) the / symbol can be used as part of javascript content as a division sign, part of a comment (// or /*) or in other ways. The OWASP filter evasion cheat sheet (https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet) has a good list of attack strings using varying characters, depending upon what is or is not encoded, and for different contexts. The dash (-) character can be used for XUL markup against mozilla.

Just because you can't see where it would be a problem is never good enough. You MUST know that it can never be a problem before you let it through. As yu can see with the above example, even OWASP failed to predict certain valid usage of user data, and thier encoding instructions were incomplete.

The safe thing is to always encode everything but that which cannot possibly be dnagerous. Generally, it is safe to encode all non-alphanumeric ASCII characters below character point 127 and let everything else go unencoded. Less than this invites errors oike the one described above.

6
  • 1
    This recommendation is specifically for content outside elements, not for attributes. For attributes they recommend completely different handling, see the next item after the one I have linked.
    – StasM
    Feb 4, 2014 at 7:02
  • If you write shitty html like that, you deserve what you get. Feb 4, 2014 at 8:56
  • 1
    @CodesInChaos If you do not protect valid html, correctly interpreted by standard interpreters, and written by a substantial population of web developers, then you doom a substantial amount of the web to insecurity. I would rather take approaches that work all of the time than approaches that work some of the time.
    – atk
    Feb 4, 2014 at 13:32
  • @StasM there are a few reasons I gave the example i did. First, an older version of esapi made the exact mistakes i point out in the attribute encoder. I don't know if it was ever fixed. Second, i didn't have an example on hand for that specific character in the specific context you were looking for, though (third) the example i provided was analogous to the question and demonstrated the same error in judgment.
    – atk
    Feb 4, 2014 at 13:37
  • 1
    No, it's not analogous, because / has meaning in that context, while in original context it does not, and that was the point of the question!
    – StasM
    Feb 4, 2014 at 18:59
1

The previous answers are now outdated. The forward slash is unneeded and does not provide any substantial protection on top of the other escaped characters. Most html-escape implementations (including the Python and Go standard libraries) do not escape forward slashes.

See this GitHub issue, which has approved by the OWASP team:

https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html#output-encoding-rules-summary

There is no proof that escaping forward slash will improve defense against XSS, if all other special characters are escaped properly, but it forces developers to use non-standard implementation of the HTML escaping, what increases the risk of the mistake and makes the implementation harder.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .