Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mitigate risk of using dangerouslySetInnerHTML #1612

Closed
wants to merge 5 commits into from
Closed

Conversation

joebuono
Copy link
Contributor

@joebuono joebuono commented Apr 1, 2022

Description of changes

Potential Security Risk

Within the React package of the Amplify UI codebase, we are using React’s dangerouslySetInnerHTML to insert CSS into a <style> tag and then inject it into the DOM:

<style
  id={`amplify-theme-${name}`}
  dangerouslySetInnerHTML={{ __html: cssText }}
/>

We are doing this because we need to dynamically insert CSS into the page.

The reason this is potential security risk is because a developer could dynamically set a theme based on user input. This could allow an attacker to execute malicious code on the webpage since React’s dangerouslySetInnerHTML does not sanitize the HTML.

However, as mentioned in the internal T Corp ticket: “the risk of an unknown attacker being able to exploit this condition would be highly unlikely because the React DOM escapes everything in JSX before rendering, making XSS almost impossible. The CSS that's being set is in control of the Amplify UI team.”

Additionally, the internal createTheme function escapes all input to strings and does not execute any of the passed-in code.

Solution

To mitigate this risk, we are using the DOMPurify to sanitize the HTML and prevent XSS attacks. DOMPurify is the library that OWASP recommends. Specifically, we are using isomorphic-dompurify in order to get the e2e and docs tests to pass (by rendering on both the client and server side).

import DOMPurify from 'isomorphic-dompurify';

<style
  id={`amplify-theme-${name}`}
  dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(cssText) }}
/>

Tradeoffs to using DOMPurify

  • Adding DOMPurify as a dependency means that we will have to regularly patch it since browsers change functionality and bypasses are being discovered regularly (see OWASP)
  • It will also slightly increase our bundle size by up to 19.6kB

*** Note: I am still writing tests to confirm that the sanitization works as expected.

Issue #, if available

Description of how you validated changes

Checklist

  • PR description included
  • yarn test passes
  • Tests are updated

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

@changeset-bot
Copy link

changeset-bot bot commented Apr 1, 2022

🦋 Changeset detected

Latest commit: ee76a6f

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@aws-amplify/ui-react Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@joebuono joebuono temporarily deployed to ci April 4, 2022 17:22 Inactive
@joebuono joebuono temporarily deployed to ci April 4, 2022 17:22 Inactive
@joebuono joebuono temporarily deployed to ci April 4, 2022 17:22 Inactive
@joebuono joebuono temporarily deployed to ci April 4, 2022 17:22 Inactive
import { TextDecoder, TextEncoder } from 'util';

global.TextEncoder = TextEncoder;
global.TextDecoder = TextDecoder;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is necessary in order to use isomorphic dompurify: kkomelin/isomorphic-dompurify#91 (comment)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please put this comment in the actual jest.setup file

@@ -64,9 +64,11 @@
"@radix-ui/react-dropdown-menu": "0.1.6",
"@radix-ui/react-slider": "0.1.4",
"@radix-ui/react-tabs": "0.1.5",
"@types/dompurify": "2.3.3",
Copy link
Contributor Author

@joebuono joebuono Apr 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This import fixed the following rollup error: rollup/rollup-plugin-commonjs#361

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be in devDependencies since it's not a runtime dependency, just a build-time dependency.

"@xstate/react": "1.6.3",
"classnames": "2.3.1",
"deepmerge": "4.2.2",
"isomorphic-dompurify": "0.18.0",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Importing the isomorphic version of dompurify in order to get the e2e and docs tests to pass. Isomorphic dompurify is basically a wrapper around dompurify that allows it to run on the server side as well as the client.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm nervous about depending on this package which hasn't been battle tested as much as the original. I'd prefer that we create our own universal isomorphic wrapper around DOMPurify.

@joebuono
Copy link
Contributor Author

joebuono commented Apr 5, 2022

Closing this PR because we've found a better solution: #1622

@joebuono joebuono closed this Apr 5, 2022
@joebuono joebuono deleted the dom-purify branch April 5, 2022 17:33
@calebpollman
Copy link
Contributor

calebpollman commented Apr 5, 2022 via email

@calebpollman
Copy link
Contributor

calebpollman commented Apr 27, 2022 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants