17

I'm making a TV guide with React. I'm pulling show information from this API: http://api.tvmaze.com/episodes/333

As you can see the summary contains html. If I render the field. then the HTML is interpreted as a string, meaning that you can see the <p> tags, etc., on the page.

I know that I could use dangerouslySetInnerHTML but it's discouraged for security reasons. What is the best practice for this? It must be fairly common to get formatted text from an API and need to render it. I'm surprised there isn't a filter which would allow <p>, <h1>, etc., but not script tags.

Jon Schneider
  • 25,758
  • 23
  • 142
  • 170
Evanss
  • 23,390
  • 94
  • 282
  • 505
  • 1
    Not a direct question to your answer but have you seen [this](https://stackoverflow.com/questions/29044518/safe-alternative-to-dangerouslysetinnerhtml)? – Hardik Modha Oct 19 '17 at 15:07

1 Answers1

24

Is dangerouslySetInnerHTML the only way to render HTML from an API in React?

Technically, no. You could do some magic with the Babel transformer if you prefer, but that approach isn't any more "safe" or recommendable. It's only a more flexible alternative. See here for more info about that.

That said, dangerouslySetInnerHTML is still the recommended approach to inserting raw markup into your component. Make no mistake, the name is frightening just to remind developers of the potential XSS risk. The fact that you use it doesn't automatically render your code "smelly" or otherwise "bad".

In other words, if you are certain that the code you fetch is not malicious it's a pretty safe bet. If you trust the API you have little to worry about. For example, this is perfectly safe:

return <div dangerouslySetInnerHTML={{__html: "<p>foo bar</p>"}} />;

and so is this:

let markup = SomeApiCallToTrustedProvider(); //"<p>foo bar</p>"
return <div dangerouslySetInnerHTML={{__html: markup}} />;

I'm no expert in this field, but my understanding is that if users cannot influence the presentation of your website for other users, you are safe from the traditional XSS attacks. An example would be if you were to fetch un-sanitized input data from a database and reflect it as raw markup in your code. That would allow a malicious user to submit code to the database, which when presented to other users, would then be executed effectively giving users the ability to manipulate your page.

I'm surprised there isn't a filter which would allow <p>, <h1> etc but not script tags.

Well, this would be some kind of sanitization. There are snippets out there of how you can implement your own, here for example...

Chris
  • 57,622
  • 19
  • 111
  • 137
  • 1
    I think the argument is "there's no way to be sure you're retrieving safe html" -- a db can always be hacked and malicious values inserted. The front-end needs to scrub what comes out of the back-end. Never trust. Always verify. Good reading: https://github.com/cure53/DOMPurify/wiki/Security-Goals-&-Threat-Model – theUtherSide Feb 14 '19 at 13:26
  • 4
    @theUtherSide that is a valid point, but that could also be said for literally every security-related question - which is: *nothing is 100% foolproof*. If you have a hacked database, you have more than just XSS to worry about. This post has some oversight for such corner-cases. – Chris Feb 14 '19 at 13:36