-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
use a content-security-policy in development (#2142)
* use a content-security-policy in development * cram things in a bit * playwright test for dev mode headers * fix license, add draft docs/csp-headers.md * add preview script to package.json * comment explaining why we use the nonce thing, add justification to doc * remove style-src 'unsafe-inline' :) * fix the docs and test * apply patch for react-focus-guards * patch global styles out of react-remove-scroll * `patch-package --reverse` before vercel caches it * patch out the other react-remove-scroll-bar reference * save another 31 bytes, why not * Revert "remove style-src 'unsafe-inline' :)" This reverts commit 22f40bb. * Revert "fix the docs and test" This reverts commit 06e13cd. * update docs --------- Co-authored-by: David Crespo <david.crespo@oxidecomputer.com>
- Loading branch information
1 parent
2b6d0f7
commit d2a9345
Showing
7 changed files
with
171 additions
and
1 deletion.
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