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

[WIP] Strong CSP Support #4943

Closed
wants to merge 85 commits into from
Closed
Show file tree
Hide file tree
Changes from 58 commits
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
386245b
WIP Fix
dav-is Aug 10, 2018
1223ded
Merge branch 'canary' into canary
dav-is Aug 10, 2018
23012bc
Generate bootstrap.js
dav-is Aug 10, 2018
e5c1a51
Syntax
dav-is Aug 10, 2018
e18b1ad
Merge branch 'canary' of github.com:dav-is/next.js into canary
dav-is Aug 10, 2018
9531f55
Merge branch 'canary' into canary
dav-is Aug 27, 2018
b840984
Copy bootstrap.js instead of loading through webpack
dav-is Aug 28, 2018
9ec8c96
Cleanup
dav-is Aug 28, 2018
709fc5c
add a htmlescaped pathname
dav-is Aug 28, 2018
7e7092f
Fix Flow Error
dav-is Aug 28, 2018
986adfb
Remove hashes and nonces
dav-is Aug 28, 2018
9e7ee16
Minor fixes
dav-is Aug 28, 2018
f3eddab
Remove mentions of nonce/hash, add CSP to README.md
dav-is Aug 28, 2018
2c76ed9
Merge branch 'canary' into canary
dav-is Aug 28, 2018
178e4fe
Add Strict CSP Support//waiting for styled-jsx PR Merge
dav-is Aug 28, 2018
6e02af3
Merge branch 'canary' of github.com:dav-is/next.js into canary
dav-is Aug 28, 2018
27488ac
Merge branch 'canary' into canary
dav-is Aug 28, 2018
ea22175
Move setHeader logic to index.js, use nanoid
dav-is Aug 28, 2018
ae54cc6
Merge branch 'canary' of github.com:dav-is/next.js into canary
dav-is Aug 28, 2018
b1ba505
Fix eTags, if no policy dont set header, seamlessly insert nonce into…
dav-is Aug 28, 2018
b06f8ba
Fix CSP test
dav-is Aug 28, 2018
87d8b40
Whoops
dav-is Aug 28, 2018
ca2fff8
Merge branch 'canary' into canary
dav-is Aug 30, 2018
1865373
Merge branch 'canary' into canary
dav-is Aug 30, 2018
1066028
Merge branch 'canary' into canary
dav-is Aug 30, 2018
5ef8249
Add unsafeCSPMeta config option, move nonce code to this.render
dav-is Aug 30, 2018
3acf7a3
Merge branch 'canary' of github.com:dav-is/next.js into canary
dav-is Aug 30, 2018
de93117
Minor textual changes to README.md
dav-is Aug 30, 2018
f34704c
Merge branch 'canary' into canary
dav-is Aug 31, 2018
3aa6580
Fix HMR (WIP), check if static or not
dav-is Aug 31, 2018
d0d0288
Merge branch 'canary' into canary
dav-is Sep 4, 2018
d4ef249
Try fixing test
dav-is Sep 4, 2018
b728131
Merge branch 'canary' into canary
dav-is Sep 4, 2018
6ae263e
Run tests
dav-is Sep 4, 2018
f3cc533
Merge branch 'canary' of github.com:dav-is/next.js into canary
dav-is Sep 4, 2018
4b7688b
Fix tests?
dav-is Sep 4, 2018
6cf5d18
Merge branch 'canary' into canary
dav-is Sep 4, 2018
fb82831
Remove module={}
dav-is Sep 4, 2018
8f6a76f
Failing because styled-jsx PR isn't merged yet
dav-is Sep 4, 2018
a83d16c
Don't use inline styles for error pages, this change didn't work...
dav-is Sep 5, 2018
fe088b2
Merge branch 'canary' into canary
dav-is Sep 5, 2018
077d5a0
Merge branch 'canary' into canary
dav-is Sep 6, 2018
5d5643a
Fix tests, add note about error page
dav-is Sep 7, 2018
e09a1e7
Merge branch 'canary' of github.com:dav-is/next.js into canary
dav-is Sep 7, 2018
8343a93
Merge branch 'canary' into canary
dav-is Sep 7, 2018
96fc0cc
Minor fix, upgrade styled-jsx version - pending release
dav-is Sep 10, 2018
75227c3
Merge branch 'canary' of github.com:dav-is/next.js into canary
dav-is Sep 10, 2018
0c67bcd
Merge branch 'canary' into canary
dav-is Sep 24, 2018
cb76f38
Minify bootstrap.js
dav-is Sep 24, 2018
657d4e0
New dataloading technique, remove bootstrap.js
dav-is Sep 25, 2018
632d0e4
Merge branch 'canary' into canary
dav-is Sep 25, 2018
6167a49
Update package.json
dav-is Sep 26, 2018
c46ec20
Merge branch 'canary' into canary
dav-is Sep 26, 2018
1b50af9
Fixes
dav-is Sep 26, 2018
8898e59
Merge branch 'canary' of github.com:dav-is/next.js into canary
dav-is Sep 26, 2018
68741ef
Linter fixes
dav-is Sep 26, 2018
4f6c8dc
Use Proxy object instead of overriding prototype
dav-is Sep 26, 2018
6d5ab37
Get webpack page plugin to work
dav-is Sep 26, 2018
2c85d20
Sync with origin
dav-is Dec 4, 2018
c584de5
Reapply changes to updated branch
dav-is Dec 5, 2018
db4b51c
Merge branch 'canary' into canary
dav-is Dec 5, 2018
4ec0e01
Use classname for error-overlay
dav-is Dec 5, 2018
8a6de18
Merge branch 'canary' of github.com:dav-is/next.js into canary
dav-is Dec 5, 2018
96c2040
Define styles in js instead of jsx
dav-is Dec 5, 2018
cd718cc
Cleanup variables
dav-is Dec 5, 2018
56bd0e5
Remove AutoDll plugin to avoid unsafe-eval, fix typo in _doc
dav-is Dec 5, 2018
0bbdd3d
Fix tests
dav-is Dec 5, 2018
d8cd11c
Fix #5674
dav-is Dec 5, 2018
ba45a21
Fix tests because NEXT_DATA doesn't need crossOrigin and nonce attrib…
dav-is Dec 5, 2018
5d2c75b
Azure failed, is it because of a trailing slash?
dav-is Dec 6, 2018
d1017f8
Merge branch 'canary' into canary
dav-is Dec 6, 2018
fd2300a
Debug why Azure is failing tests
dav-is Dec 6, 2018
dfe452c
Merge branch 'canary' into canary
dav-is Dec 6, 2018
3c42323
No more default CSP, README is more clear, all integration tests use CSP
dav-is Dec 11, 2018
5697389
Merge branch 'canary' of github.com:dav-is/next.js into canary
dav-is Dec 11, 2018
9f9d2c4
Sync with upstream
dav-is Dec 11, 2018
98509ca
Merge branch 'canary' into canary
dav-is Dec 11, 2018
15cf4f4
Fix ETags and remove unused dep
dav-is Dec 11, 2018
bbd7306
Merge branch 'canary' of github.com:dav-is/next.js into canary
dav-is Dec 11, 2018
eaa0672
Merge branch 'canary' into canary
dav-is Dec 12, 2018
8fea414
Readme edits
dav-is Dec 12, 2018
3608c1a
Merge branch 'canary' of github.com:dav-is/next.js into canary
dav-is Dec 13, 2018
abfaa78
Remove crossOrigin PR
dav-is Dec 13, 2018
247aa1d
Merge remote-tracking branch 'upstream/canary' into canary
dav-is Dec 13, 2018
cf30cb6
Remove inline styles from _error.js and error-debug.js
dav-is Dec 13, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ Next.js is a minimalistic framework for server-rendered React applications.
- [Reusing the built-in error page](#reusing-the-built-in-error-page)
- [Custom configuration](#custom-configuration)
- [Setting a custom build directory](#setting-a-custom-build-directory)
- [Content Security Policy](#content-security-policy)
- [Disabling etag generation](#disabling-etag-generation)
- [Configuring the onDemandEntries](#configuring-the-ondemandentries)
- [Configuring extensions looked for when resolving pages in `pages`](#configuring-extensions-looked-for-when-resolving-pages-in-pages)
Expand Down Expand Up @@ -1196,6 +1197,21 @@ module.exports = {
}
```

#### Content Security Policy

Next.js supports [CSP](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP). You can set your CSP Poliy in your Next.js configuration.
Copy link
Contributor

Choose a reason for hiding this comment

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

I think there's no need to Policy after CSP.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You’re right. That’s left over from before when there were more variables set on the key “CSP” so there was CSP.policy, and CSP.nonce, etc

I need to go through and rewrite the README too I just haven’t had much time lately


```js
// next.config.js
module.exports = {
contentSecurityPolicy: "default-src 'self';"
}
```

Interestingly, due to the way error handling works in Next.js, you will have to use [custom error handling](#custom-error-handling) to avoid an inline style violation, but this is very easy to do.

Note: In order to support dynamic styles Next.js uses a `nonce` for `style-src`. This is done automatically. If you use a different CSS-in-JS library, you can use the `csp.nonce` document parameter to get the nonce set in the header. `csp.policy` is the CSP policy before nonce is added. `csp.isDisabled` is what you can use to see if CSP is enabled.

#### Disabling etag generation

You can disable etag generation for HTML pages depending on your cache strategy. If no configuration is specified then Next will generate etags for every page.
Expand Down
8 changes: 4 additions & 4 deletions build/webpack/plugins/pages-plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default class PagesPlugin {
compiler.hooks.compilation.tap('PagesPlugin', (compilation) => {
// This hook is triggered right before a module gets wrapped into it's initializing function,
// For example when you look at the source of a bundle you'll see an object holding `'pages/_app.js': function(module, etc, etc)`
// This hook triggers right before that code is added and wraps the module into `__NEXT_REGISTER_PAGE` when the module is a page
// This hook triggers right before that code is added and wraps the module into `window._routes.push` when the module is a page
// The reason we're doing this is that we don't want to execute the page code which has potential side effects before switching to a route
compilation.moduleTemplates.javascript.hooks.render.tap('PagesPluginRenderPageRegister', (moduleSourcePostModule, module, options) => {
const {chunk} = options
Expand Down Expand Up @@ -41,10 +41,10 @@ export default class PagesPlugin {
routeName = `/${routeName.replace(/(^|\/)index$/, '')}`

const source = new ConcatSource(
`__NEXT_REGISTER_PAGE('${routeName}', function() {\n`,
`( window._routes || (window._routes = {}) )["${routeName}"] = function () {\n`,
moduleSourcePostModule,
'\nreturn { page: module.exports.default }',
'});'
'\nreturn { page: module.exports.default }\n',
'};'
)

return source
Expand Down
55 changes: 37 additions & 18 deletions client/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import React from 'react'
import ReactDOM from 'react-dom'
import htmlescape from 'htmlescape'
import HeadManager from './head-manager'
import { createRouter } from '../lib/router'
import EventEmitter from '../lib/EventEmitter'
import { loadGetInitialProps, getURL } from '../lib/utils'
import { loadGetInitialProps, getURL, getNextData } from '../lib/utils'
import PageLoader from '../lib/page-loader'
import * as asset from '../lib/asset'
import * as envConfig from '../lib/runtime-config'
Expand All @@ -20,19 +21,17 @@ if (!window.Promise) {
}

const {
__NEXT_DATA__: {
props,
err,
page,
pathname,
query,
buildId,
assetPrefix,
runtimeConfig,
dynamicIds
},
location
} = window
props,
err,
page,
pathname,
query,
buildId,
assetPrefix,
runtimeConfig,
dynamicIds
} = getNextData()
const { location } = window

const prefix = assetPrefix || ''

Expand All @@ -50,11 +49,31 @@ envConfig.setConfig({
const asPath = getURL()

const pageLoader = new PageLoader(buildId, prefix)
window.__NEXT_LOADED_PAGES__.forEach(([r, f]) => {
pageLoader.registerPage(r, f)
if (page === '_error') {
pageLoader.registerPage(htmlescape(pathname), () => {
const e = new Error(`Page does not exist: ${htmlescape(pathname)}`)
e.statusCode = 404
return { error: e }
})
}

window._routes = new Proxy(window._routes, {
Copy link
Contributor

Choose a reason for hiding this comment

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

There's no polyfill for Proxy and this won't work on IE11.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

set: (obj, prop, value) => {
if (prop !== 'string' || value !== 'function') return

pageLoader.registerPage(prop, value)
delete obj[prop]

return false
}
})
delete window.__NEXT_LOADED_PAGES__
window.__NEXT_REGISTER_PAGE = pageLoader.registerPage.bind(pageLoader)

const deleteIndexes = []
for (let [name, fn] of Object.entries(window._routes)) {
pageLoader.registerPage(name, fn)
deleteIndexes.push(name)
}
deleteIndexes.forEach(name => delete window._routes[name])

const headManager = new HeadManager()
const appContainer = document.getElementById('__next')
Expand Down
7 changes: 3 additions & 4 deletions client/next-dev.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import initNext, * as next from './'
import initOnDemandEntries from './on-demand-entries-client'
import initWebpackHMR from './webpack-hot-middleware-client'
import { getNextData } from '../lib/utils'

// Temporary workaround for the issue described here:
// https://github.com/zeit/next.js/issues/3775#issuecomment-407438123
Expand All @@ -9,10 +10,8 @@ import initWebpackHMR from './webpack-hot-middleware-client'
import('./noop')

const {
__NEXT_DATA__: {
assetPrefix
}
} = window
assetPrefix
} = getNextData()

const prefix = assetPrefix || ''
const webpackHMR = initWebpackHMR({assetPrefix: prefix})
Expand Down
48 changes: 0 additions & 48 deletions examples/with-strict-csp-hash/README.md

This file was deleted.

15 changes: 0 additions & 15 deletions examples/with-strict-csp-hash/package.json

This file was deleted.

26 changes: 0 additions & 26 deletions examples/with-strict-csp-hash/pages/_document.js

This file was deleted.

3 changes: 0 additions & 3 deletions examples/with-strict-csp-hash/pages/index.js

This file was deleted.

46 changes: 0 additions & 46 deletions examples/with-strict-csp/README.md

This file was deleted.

31 changes: 0 additions & 31 deletions examples/with-strict-csp/csp.js

This file was deleted.

17 changes: 0 additions & 17 deletions examples/with-strict-csp/package.json

This file was deleted.

28 changes: 0 additions & 28 deletions examples/with-strict-csp/pages/_document.js

This file was deleted.

3 changes: 0 additions & 3 deletions examples/with-strict-csp/pages/index.js

This file was deleted.

Loading