53

I've got some user generated html markup from a text area and I'd like to render it on another part of the screen. The markup is saved as a string in the props of the component.

I don't want to use dangerouslysethtml for obvious reasons. Is there a parser such as marked but for html so that it strips out script tags and other invalid html.

3 Answers 3

69

Sanitize the html using the sanitize-html module, and render the sanitized string using dangerouslySetInnerHTML.

You can create a simple wrapper component:

const defaultOptions = {
  allowedTags: [ 'b', 'i', 'em', 'strong', 'a' ],
  allowedAttributes: {
    'a': [ 'href' ]
  },
  allowedIframeHostnames: ['www.youtube.com']
};

const sanitize = (dirty, options) => ({
  __html: sanitizeHtml(
    dirty, 
    options: { ...defaultOptions, ...options }
  )
});

const SanitizeHTML = ({ html, options }) => (
  <div dangerouslySetInnerHTML={sanitize(html, options)} />
);

Usage:

<SanitizeHTML html="<img src=x onerror=alert('img') />" />

You can also use react-sanitized-html's SanitizedHTML component, which is a react wrapper around sanitize-html:

<SanitizedHTML
  allowedAttributes={{ 'a': ['href'] }}
  allowedTags={['a']}
  html={ `<a href="http://bing.com/">Bing</a>` }
/>
Sign up to request clarification or add additional context in comments.

5 Comments

I don't understand how [email protected] is just 2kb if is a wrapper of sanitize-html, when [email protected] is 157.2kB :/ !
Ok, because is needed to install both packages for separate... react-sanitized-html and sanitize-html :/
Because sanitize-html is a peer dependency, and not actual part of the package.
Hi there @ori , I'm following ur instruciton but i got error on my compiler [11:40:00] Starting 'browserify_typescript'... [11:40:04] 'browserify_typescript' errored after 4.29 s [11:40:04] Error in plugin 'gulp-browserify' module "./tagtypes" not found from "/d/myProject/web/node_modules/sanitize-html/dist/sanitize-html.js" it said ./tagtypes not found
This is a build related issue. You should open a new question.
32

An example based on the accepted answer:

import sanitizeHtml from 'sanitize-html';

const MyComponent = () => {
  dirty = '<a href="my-slug" target="_blank" onClick="evil()">click</a>';
  const clean = sanitizeHtml(dirty, {
    allowedTags: ['b', 'i', 'em', 'strong', 'a'],
    allowedAttributes: {
      a: ['href', 'target']
    }
  });
  return (
    <div 
      dangerouslySetInnerHTML={{__html: clean}}
    />
  );
};

MyComponent renders div containing the link without onClick="evil()":

<a href="my-slug" target="_blank">click</a>

Comments

18

For XSS filtering, there is a good alternative to sanitize-html written by security people, called dompurify.

Here is how the wrapper from https://stackoverflow.com/a/38663813/1762849 would look with DOMPurify:

const defaultOptions = {
  ALLOWED_TAGS: [ 'b', 'i', 'em', 'strong', 'a' ], 
  ALLOWED_ATTR: ['href']
};

const sanitize = (dirty, options) => ({
  __html: DOMPurify.sanitize(
    dirty, 
    { ...defaultOptions, ...options }
  )
});

const SanitizeHTML = ({ html, options }) => (
  <div dangerouslySetInnerHTML={sanitize(html, options)} />
);

Usage:

<SanitizeHTML html="<img src=x onerror=alert('img') />" />

Also, if you you need to sanitize HTML on client and server, consider using the isomophic-dompurify module which unifies use of DOMPurify on frontend and backend.

2 Comments

This seems like a better alternative as it gives just what's needed @15kB bundlephobia.com/[email protected]
is there any way to 'initialize the sanitizer inside the component'? for example, to lazy load it? it will not be able to lazy load with it as a global i think

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.