-
Notifications
You must be signed in to change notification settings - Fork 12
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
use a content-security-policy in development #2142
Merged
Merged
Changes from all commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
39399b7
use a content-security-policy in development
iliana f93d616
cram things in a bit
david-crespo 36353d8
playwright test for dev mode headers
david-crespo d2706f5
fix license, add draft docs/csp-headers.md
david-crespo 40eff1f
add preview script to package.json
david-crespo a30b5f6
comment explaining why we use the nonce thing, add justification to doc
david-crespo cf0ea53
Merge remote-tracking branch 'origin/main' into iliana/csp
iliana 22f40bb
remove style-src 'unsafe-inline' :)
iliana 06e13cd
fix the docs and test
iliana b762520
apply patch for react-focus-guards
iliana e04e987
patch global styles out of react-remove-scroll
iliana 673ff39
`patch-package --reverse` before vercel caches it
iliana eb67e2c
patch out the other react-remove-scroll-bar reference
iliana a48a0cc
save another 31 bytes, why not
iliana 558ac71
Merge remote-tracking branch 'origin/main' into iliana/csp
iliana 5d0e6fb
Revert "remove style-src 'unsafe-inline' :)"
iliana 21b5ca3
Revert "fix the docs and test"
iliana 273514d
update docs
iliana 7c9e07c
Merge branch 'main' into iliana/csp
david-crespo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# CSP headers in local dev and on Vercel | ||
|
||
## Why | ||
|
||
Production CSP headers are set server-side in Nexus, so why should we set the headers on Vercel and the Vite dev server too? We are not _that_ concerned about security in those environments. The main reason is so we can know as early as possible in the development process whether a given CSP directive breaks something the web console. | ||
|
||
## What | ||
|
||
The base headers are defined in `vercel.json` and imported into `vite.config.ts` to avoid repeating them. | ||
|
||
The `content-security-policy` is based on the recommendation by the [OWASP Secure Headers Project](https://owasp.org/www-project-secure-headers/index.html) (click the "Best Practices" tab). The directives: | ||
|
||
- `default-src 'self'`: By default, restrict all resources to same-origin. | ||
- `style-src 'unsafe-inline' 'self'`: Restrict CSS to same-origin and inline use. See #2183 for eventually removing `'unsafe-inline'` | ||
- `frame-src 'none'`: Disallow nested browsing contexts (`<frame>` and `<iframe>`). | ||
- `object-src 'none'`: Disallow `<object>` and `<embed>`. | ||
- `form-action 'none'`: Disallow submitting any forms with an `action` attribute (none of our forms are the traditional kind and instead post to the server in JS). | ||
- `frame-ancestors 'none'`: Disallow embedding this site with things like `<iframe>`; used to prevent click-jacking attacks. | ||
|
||
In development mode, an additional `script-src` CSP directive is added which references a randomly-generated nonce. [Vite injects this in the generated index.html](https://vitejs.dev/guide/features.html#content-security-policy-csp) so that the dev-mode scripts can load. We do this instead of allowing `'unsafe-inline'` because I'm not sure whether tests run against dev bits or not, and this helps get dev builds much closer to production. | ||
|
||
Also set are `x-content-type-options: nosniff` and `x-frame-options: DENY`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
Upstream PR: https://github.com/radix-ui/primitives/pull/2840 | ||
|
||
diff --git a/node_modules/@radix-ui/react-focus-guards/dist/index.mjs b/node_modules/@radix-ui/react-focus-guards/dist/index.mjs | ||
index cb0f892..4e56fb8 100644 | ||
--- a/node_modules/@radix-ui/react-focus-guards/dist/index.mjs | ||
+++ b/node_modules/@radix-ui/react-focus-guards/dist/index.mjs | ||
@@ -27,7 +27,10 @@ function $3db38b7d1fb3fe6a$var$createFocusGuard() { | ||
const element = document.createElement('span'); | ||
element.setAttribute('data-radix-focus-guard', ''); | ||
element.tabIndex = 0; | ||
- element.style.cssText = 'outline: none; opacity: 0; position: fixed; pointer-events: none'; | ||
+ element.style.outline = 'none'; | ||
+ element.style.opacity = '0'; | ||
+ element.style.position = 'fixed'; | ||
+ element.style.pointerEvents = 'none'; | ||
return element; | ||
} | ||
const $3db38b7d1fb3fe6a$export$be92b6f5f03c0fe9 = $3db38b7d1fb3fe6a$export$ac5b58043b79449b; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
diff --git a/node_modules/react-remove-scroll/dist/es2015/SideEffect.js b/node_modules/react-remove-scroll/dist/es2015/SideEffect.js | ||
index 08eda83..e48ccd6 100644 | ||
--- a/node_modules/react-remove-scroll/dist/es2015/SideEffect.js | ||
+++ b/node_modules/react-remove-scroll/dist/es2015/SideEffect.js | ||
@@ -1,7 +1,4 @@ | ||
-import { __spreadArray } from "tslib"; | ||
import * as React from 'react'; | ||
-import { RemoveScrollBar } from 'react-remove-scroll-bar'; | ||
-import { styleSingleton } from 'react-style-singleton'; | ||
import { nonPassive } from './aggresiveCapture'; | ||
import { handleScroll, locationCouldBeScrolled } from './handleScroll'; | ||
export var getTouchXY = function (event) { | ||
@@ -19,24 +16,11 @@ export function RemoveScrollSideCar(props) { | ||
var shouldPreventQueue = React.useRef([]); | ||
var touchStartRef = React.useRef([0, 0]); | ||
var activeAxis = React.useRef(); | ||
- var id = React.useState(idCounter++)[0]; | ||
- var Style = React.useState(function () { return styleSingleton(); })[0]; | ||
+ var Style = React.useState({})[0]; | ||
var lastProps = React.useRef(props); | ||
React.useEffect(function () { | ||
lastProps.current = props; | ||
}, [props]); | ||
- React.useEffect(function () { | ||
- if (props.inert) { | ||
- document.body.classList.add("block-interactivity-".concat(id)); | ||
- var allow_1 = __spreadArray([props.lockRef.current], (props.shards || []).map(extractRef), true).filter(Boolean); | ||
- allow_1.forEach(function (el) { return el.classList.add("allow-interactivity-".concat(id)); }); | ||
- return function () { | ||
- document.body.classList.remove("block-interactivity-".concat(id)); | ||
- allow_1.forEach(function (el) { return el.classList.remove("allow-interactivity-".concat(id)); }); | ||
- }; | ||
- } | ||
- return; | ||
- }, [props.inert, props.lockRef.current, props.shards]); | ||
var shouldCancelEvent = React.useCallback(function (event, parent) { | ||
if ('touches' in event && event.touches.length === 2) { | ||
return !lastProps.current.allowPinchZoom; | ||
@@ -139,8 +123,5 @@ export function RemoveScrollSideCar(props) { | ||
document.removeEventListener('touchstart', scrollTouchStart, nonPassive); | ||
}; | ||
}, []); | ||
- var removeScrollBar = props.removeScrollBar, inert = props.inert; | ||
- return (React.createElement(React.Fragment, null, | ||
- inert ? React.createElement(Style, { styles: generateStyle(id) }) : null, | ||
- removeScrollBar ? React.createElement(RemoveScrollBar, { gapMode: "margin" }) : null)); | ||
+ return (React.createElement(React.Fragment, null)); | ||
} | ||
diff --git a/node_modules/react-remove-scroll/dist/es2015/UI.js b/node_modules/react-remove-scroll/dist/es2015/UI.js | ||
index 26c94a8..75d91ae 100644 | ||
--- a/node_modules/react-remove-scroll/dist/es2015/UI.js | ||
+++ b/node_modules/react-remove-scroll/dist/es2015/UI.js | ||
@@ -1,6 +1,5 @@ | ||
import { __assign, __rest } from "tslib"; | ||
import * as React from 'react'; | ||
-import { fullWidthClassName, zeroRightClassName } from 'react-remove-scroll-bar/constants'; | ||
import { useMergeRefs } from 'use-callback-ref'; | ||
import { effectCar } from './medium'; | ||
var nothing = function () { | ||
@@ -29,8 +28,4 @@ RemoveScroll.defaultProps = { | ||
removeScrollBar: true, | ||
inert: false, | ||
}; | ||
-RemoveScroll.classNames = { | ||
- fullWidth: fullWidthClassName, | ||
- zeroRight: zeroRightClassName, | ||
-}; | ||
export { RemoveScroll }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
/* | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, you can obtain one at https://mozilla.org/MPL/2.0/. | ||
* | ||
* Copyright Oxide Computer Company | ||
*/ | ||
import { expect, test } from '@playwright/test' | ||
|
||
test('CSP headers', async ({ page }) => { | ||
// doesn't matter what page we go to | ||
const response = await page.goto('/') | ||
expect(response?.headers()).toMatchObject({ | ||
// note nonce is represented as [0-9a-f]+ | ||
'content-security-policy': expect.stringMatching( | ||
/^default-src 'self'; style-src 'unsafe-inline' 'self'; frame-src 'none'; object-src 'none'; form-action 'none'; frame-ancestors 'none'; script-src 'nonce-[0-9a-f]+' 'self'$/ | ||
), | ||
'x-content-type-options': 'nosniff', | ||
'x-frame-options': 'DENY', | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added this because I added more content to an existing patch in a commit, which made Vercel break. Turns out it caches your
node_modules
at the end of the run, andpatch-package
only knows not to apply a patch if it's entirely applied.ds300/patch-package#37 has some related chatter.