How to safely render html in react?
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.
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>` }
/>
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>