Open nibtime opened 2 years ago
I'd recommend looking into html-react-parser. I've used it in combination with dompurify before. Browser support for trusted-types
really isn't there, yet.
Hi @aheimlich
thanks for the recommendation! I will have a look into it when I find time to tackle and experiment with this.
trusted-types
seems a Chromium/Google exclusive thing. If I find a way to integrate with trusted-types
without too much hassle, I'll do it, so it is just gonna be an additional layer of security for supported browsers and those without support will simply ignore it.
strict-dynamic
support as a whole also isn't as good in reality as caniuse.com says, as Firefox and Safari don't fully conform to CSP-3 spec, e.g. they mess up SRI validation on scripts with src
attribute in conjunction with strict-dynamic
, so they don't really support Hash-based strict CSP etc., whereas all Chromium-based browsers (Chrome, Opera, Edge) do.
Also, a (strict) CSP can never provide uniform protection for all visitors (the IE 11 people won't have it) that's why sanitization is still very important, and making that really convenient and easy and play together with CSP would be a good complement I thought.
A good help for me to think the right way about what CSPs can and can't provide is the comparison with 2FA and passwords. Users that opt into it (use a browser that supports strict CSP) dramatically decrease the chance of getting their account compromised (becoming a victim of XSS), users that don't set it up (use a browser that doesn't support strict CSP) don't have the additional layer of security. Also 2FA doesn't mean you should use weak passwords (don't sanitize dynamic user data).
Then there can also be something like enforcing 2FA on the app level, so all your users have to set up 2FA before they are able to use the app.
The CSP equivalent here would be: Redirect all visitors with an unsupported browser to a page with a prompt to download a supported browser to visit the site. This way only visitors with browsers that guarantee strict CSP support can ever visit your actual website, at the cost that a lot of users won't do it and bounce. Something that could be done very easily implemented with middleware.
To be clear, I wasn't suggesting using html-react-parser as a replacement for XSS filtering (whether it be via dompurify, santize-html, or some other library). In fact, the package specifically warns against doing exactly that. I was suggesting using it specifically as a replacement for trusted-types
. What I'm doing currently is something like:
import React from "react";
import { sanitize } from "dompurify";
import HtmlReactParser from "html-react-parser";
function MyComponent(props) {
const sanitizedHtml = sanitize(props.rawHtml);
return HtmlReactParser(sanitizedHtml);
}
html-react-parser also has a replace
option that allows you do things like adding rel="noreferrer noopener"
to all external links, or replacing all <img>
tags with the next/image
component.
@aheimlich
no worries, I didn't assume you meant it as a replacement for sanitization, I understood it as a suggestion to pair with sanitization for an isomorphic component with good DX.
This replacement option would be interesting here: https://next-safe-middleware.vercel.app/#contributors
In the MDX, it dangerously sets a string with the contributors table that gets generated by all-contributors bot/cli. I wondered how you could replace the image avatars with optimized next/image
and html-react-parser
seems to be exactly the tool you need for something like that.
I have some ideas I want to try out for this, I will tackle it after #66. This would then become an extra package @strict-csp/trusted-html
or something like that.
Also a note on this: The SSR sanitization in terms of strict CSP will only be required if you process plain HTML for sources, like style elements and style attributes, as they will be trusted during SSR. Processing plain HTML is configurable in getCspInitialProps
, so you can always opt out from it in case of security concerns. This could lead to SSR injections of malicious stuff from data fetching methods, but CSR injections would still be blocked.
For scripts, however, this lib hooks into Next SSR in way, that it observes scripts from the perspective of the framework, so malicious scripts injected in HTML during SSR will never become trusted. A huge advantage over generic post-build processing of <script>
tags in HTML. There also isn't an option to change that, the lib follows the assumption that you idiomatically use next/script
and then everything will work and be automatic.
The effect of this: even if you dangerously set HTML from data fetching (getStaticProps, getServerSideProps, getInitialProps) and it include malicious scripts, they will be blocked, so scripts are always safe via strict-dynamic
, both for SSR and CSR, even without sanitization.
However, browsers without strict-dynamic
support don't have this protection, why sanitization is still important, both for CSR (dom-purify) and SSR (sanitize-html ...). trusted-types would just be a complement for new supported browsers as the intersection of browsers that support trusted-types but don't support strict-dynamic is empty.
With Safari supporting strict-dynamic
now and the fast auto-updating of Apple, there is a whopping + ~15% of browsers that benefit from Strict CSP protection, that is why I also put a lot of effort in making #63 work.
Motivation
Where is the isomorphic
<SafelySetInnerHtml>
component? I think this package is a good context to provide this component and pair it with CSPIdea
HTML Sanitization has two sides: The client-side, that prevents XSS DOM -> Database, and the server-side, that prevents Database -> XSS DOM. The client-side could be implemented with DOMPurify and paired with
trusted-types
spec, the server-side withsanitize-html
and paired with HTML preprocessing ofgetCspInitialProps
(#40).Resources
https://www.npmjs.com/package/dompurify https://www.npmjs.com/package/sanitize-html https://github.com/cure53/DOMPurify#what-about-dompurify-and-trusted-types