htmlspringlocalizationxsshtml-escape

html markup in messages properties with placeholders - XSS potential


Given the message in a messages properties file:

message = Change relation <strong>{0}</strong> -> <strong>{1}</strong> to <strong>{2}</strong> -> <strong>{3}</strong>?

if the content of any of the placeholders is a user-influenced string, I need to html escape the message in order to prevent a potential XSS (I do that by using the c:out tag in my JSP templates, I guess I could use the htmlEscape-attribute of the spring:message tag as well, but I think there's no difference).

However by doing so, I corrupt the markup in the message, <strong> etc. which leads to the output:

Change relation <strong>Peter</strong> -> <strong>Car</strong> to <strong>Carl</strong> -> <strong>Bus</strong>?

I've already read the thread here on stackoverflow but it does not address XSS.

I am thinking about these options:

1) Simply replace all <strong> tags from the messages properties files with single quotes. Then there's no problem html escaping the entire message, with the drawback of a little less highlighting of the specific parts of the message.

2) Split the message into parts which allow for separate markup in the (JSP) template. This feels like much work just to get the markup right.

Am I missing something here? Which is the better option, or is there another option?

Edit: Without html-escaping the message is, like I want it to be, like this:

Change relation Peter -> Car to Carl -> Bus?

So the html-markup as in the messages.properties file is being rendered when displayed in the template.

When escaping, the message is like above, showing me the <strong> tags instead of rendering them.


Solution

  • Going under the assumption that you are getting the following output:

    Change relation &lt;strong&gt;Peter&lt;/strong&gt; -&gt; &lt;strong&gt;Car&lt;/strong&gt; to &lt;strong&gt;Carl&lt;/strong&gt; -&gt; &lt;strong&gt;Bus&lt;/strong&gt;

    It looks like you are escaping your entire HTML string rather than just the part that needs to be escaped.

    You should escape each {#} value on its own, and then place it into the HTML. The general values you need to escape are: <, >, ', ", and &, but use an anti-xss library and templating system if you can.

    Once you've escaped all the potentially dangerous parts, you can use something like <c:out value="${msg}" escapeXml="false"/>. This is not a language/framework I know, but you need some way to output the actual HTML vs the escaped version. Whatever way you prefer should be fine as long as you properly escape the untrusted part.