HelloWorld
HelloWorld

Reputation: 2330

render pre-escaped html from wordpress api with react

I am using the wordpress api to output stored data, and react to render the data in the view.

It looks like wordpress api outputs posts as pre-escaped HTML strings like so:

content {
    rendered: "<p>This is a post</p><p>This is some more text</p>"
}

It looks like react is rendering the full html including the tags as a string. I could do this I guess:

render() {
    const post = content.rendered ? content.rendered : "";
    return <div dangerouslySetInnerHTML={{__html: post}}></div>;
}

But by the name I can see that this is maybe not the best solution, and I really don't want to do this every time I render data from the rest api. Is there some way to get these html strings to be viewed as html other than this?

Upvotes: 1

Views: 1603

Answers (1)

Joni H.
Joni H.

Reputation: 166

As far as I can tell from https://reactjs.org/docs/dom-elements.html, the attribute is so named to save yourself from yourself. It is theoretically possible that someone put something malicious in the HTML output that you are trying to render. There is no other attribute that you can use.

The only safe solution I can think of is to manually strip out tags - either all tags or just the potentially malicious ones. I wrote a POC of this (below, with much thanks to the answer at Removing all script tags from html with JS Regular Expression).

This still uses the dangerouslySetInnerHTML attribute, but it's less dangerous because I am stripping out all <script> and <style> tags. You can edit this to strip out whatever else you need (or strip out everything with the * selector).

// Function that takes the original content and strips out all <script> and <style> tags. 

cleanHtml(content) {
  let div = document.createElement('div');
  div.innerHTML = content;

  let scripts = div.querySelectorAll('style, scripts');
  let i = scripts.length;

  while (i--) {
    scripts[i].parentNode.removeChild(scripts[i]);
  }

  return div.innerHTML;
}

render() {
  let content = this.cleanHtml(content.rendered);

  return (
    <div dangerouslySetInnerHTML={{ __html: content}} />
  )
}

Upvotes: 4

Related Questions