As the react documentation says, dangerouslySetInnerHTML
is React’s replacement for using innerHTML
in the browser DOM. In general, setting HTML from code is risky because it’s easy to inadvertently expose your users to a cross-site scripting (XSS) attack.
In fewer words, dangerouslySetInnerHTML
isn’t safe.
let’s say that you have a database with a bunch of article in HTML format that you want to display in your React app. Using dangerouslySetInnerHTML that would be quite easy to achieve:
function MyArticle({ articleId }) {
return <div dangerouslySetInnerHTML={getArticleFromDB(articleId)} />
}
The problem with this is that the HTML you are injecting to your app could be malformed, it could have CSS/JS that breaks your app, or even worse, JS that steals data from your app.
In order to make the iframe really safe, you need to add extra restrictions to the content inside of it. To do that, you should use the sandbox attribute.
<iframe id={IFRAME_ID} name={IFRAME_ID} sandbox="allow-same-origin" />
You should avoid using both allow-scripts and allow-same-origin, as that lets the embedded document remove the sandbox attribute — making it no more secure than not using the sandbox attribute at all.
Here you have two options:
the srcdoc property allows you to specify the content of the iframe, so using it is quite simple:
<iframe
id={IFRAME_ID}
name={IFRAME_ID}
sandbox="allow-same-origin"
srcDoc={iframeContent}
/>
Unfortunately srcdoc isn’t supported in IE and Edge. There is a polyfill but it isn’t useful in this case because it requires allow-scripts (and remember that’s not safe)
This method is not straightforward as using srcdoc, but it works the good thing is that works in all browsers.
const IFRAME_ID = 'my-iframe'
const IFRAME_CONTAINER_ID = 'my-iframe-container'
export const ArticleBody = (props: Props) => {
useEffect(() => {
const setIframeContent = (body) => {
const currentIframe = document.getElementById(IFRAME_ID)
const iframeContainer = document.getElementById(IFRAME_CONTAINER_ID)
if (iframeContainer) {
const newIframe = frames[IFRAME_ID]
if (newIframe !== null) {
const iframeDocument = newIframe.document
iframeDocument.open()
iframeDocument.write(`${body}`)
iframeDocument.close()
}
}
}
setIframeContent(props.body)
}, [props.body])
}
I hope you’ve found this article useful! Start a conversation with the author in Twitter on what you think about this article.
article
· 11 min readarticle
· 16 min readarticle
· 12 min readarticle
·talk
screencast
Have a chat with one of our co-founders, Jed or Boris, about how Thinkmill can support your organisation’s software ambitions.
Contact us