Skip to content

Commit b4a6e11

Browse files
committed
docs: update README for 0.8.0 release
update infos in package.json
1 parent be1c950 commit b4a6e11

File tree

3 files changed

+109
-75
lines changed

3 files changed

+109
-75
lines changed

apps/e2e/package.json

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,7 @@
44
"private": true,
55
"yarn.build": {
66
"input": [
7-
"pages",
8-
"components",
9-
"styles",
10-
"next.config.js",
11-
".babelrc.js",
12-
"stitches.config.ts",
13-
"tailwind.config.js"
7+
"."
148
],
159
"output": ".next"
1610
},

packages/next-safe-middleware/README.md

Lines changed: 104 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
11

22

33
<div align="center">
4-
4+
<br />
55
<img src=https://user-images.githubusercontent.com/52962482/177227813-b15198ca-2c36-4ba3-afec-efeb581a19a1.png height=75 width=75 />
66
<h1><code>@next-safe/middleware</code></h1>
77
<p><strong>Strict Content-Security-Policy (CSP) for Next.js</strong></p>
88
<p>Works for hybrid apps and supports pages with any data fetching method.</p>
99
<p>Always sets CSP by HTTP Response header and enables easy setup of reporting.</p>
1010
<p>I want this: <a href="#getting-started">How can I get started?</a></p>
1111

12-
<br>
13-
1412
[![Version][version-badge]][package]
1513
[![Downloads][downloads-badge]][npmtrends]
1614
[![MIT][license-badge]][license]
@@ -23,6 +21,8 @@
2321

2422
</div>
2523

24+
<br />
25+
2626
[downloads-badge]: https://img.shields.io/npm/dm/next-safe.svg?style=flat-square
2727
[github-watch]: https://github.com/nibtime/next-safe-middleware/watchers
2828
[github-watch-badge]: https://img.shields.io/github/watchers/nibtime/next-safe-middleware.svg?style=social
@@ -48,7 +48,7 @@ This package handles all strict CSP conundrums for you and works for:
4848

4949
* pages with [`getServerSideProps`](https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props) - **Nonce-based**
5050

51-
* pages with [`getStaticProps` + `revalidate` (ISR)]((https://vercel.com/docs/concepts/next.js/incremental-static-regeneration)) - **Hash-based**
51+
* pages with [`getStaticProps` + `revalidate` (ISR)](https://vercel.com/docs/concepts/next.js/incremental-static-regeneration) - **Hash-based**
5252

5353

5454
**This package always sets CSP as HTTP response header**. That enables violation reporting and report-only mode even for static pages. Plus, it provides a middleware and API handlers that make the setup of CSP violation reporting very easy.
@@ -92,27 +92,21 @@ create a file `middleware.js` in your Next.js project folder (or `pages/_middlew
9292

9393
```js
9494
// middleware.js
95-
import {
96-
chain,
97-
csp,
98-
strictDynamic,
99-
} from '@next-safe/middleware';
95+
import { chainMatch, isPageRequest, csp, strictDynamic } from '@next-safe/middleware';
96+
97+
const securityMiddleware = [
98+
csp({
99+
// your CSP base configuration with IntelliSense
100+
// single quotes for values like 'self' are automatic
101+
directives: {
102+
'img-src': ['self', 'data:', 'https://images.unsplash.com'],
103+
'font-src': ['self', 'https://fonts.gstatic.com'],
104+
},
105+
}),
106+
strictDynamic(),
107+
];
100108

101-
const securityMiddleware = [
102-
csp({
103-
// Your CSP base configuration.
104-
// You have full IntelliSense here and don't need to pay attention
105-
// to single quotes for values like 'self'
106-
directives: {
107-
'frame-src': ['self'],
108-
'img-src': ['self', 'data:', 'https://images.unsplash.com'],
109-
'font-src': ['self', 'https://fonts.gstatic.com'],
110-
}
111-
}),
112-
strictDynamic()
113-
];
114-
115-
export default chain(...securityMiddleware);
109+
export default chainMatch(isPageRequest)(...securityMiddleware);
116110
```
117111

118112
create a file `pages/_document.js` in your Next.js project folder:
@@ -147,8 +141,34 @@ export default class MyDocument extends Document {
147141

148142
Thats it. You should be all set now with a strict CSP for your Next.js app!
149143

144+
### Default CSP directives
145+
I found this to be the most minimal yet sensible defaults
146+
as base for a strict CSP:
147+
148+
```js
149+
const defaults = {
150+
directives: {
151+
'default-src': ['self'],
152+
'object-src': ['none'],
153+
'base-uri': ['none'],
154+
},
155+
isDev: process.env.NODE_ENV === 'development',
156+
reportOnly: !!process.env.CSP_REPORT_ONLY,
157+
};
158+
```
159+
160+
You can override a directive's default by setting values or unset it with an empty array:
161+
162+
```js
163+
const cspMiddleware = csp({
164+
directives: {
165+
'default-src': [],
166+
},
167+
});
168+
```
169+
150170
### Hash-based strict CSP for pages with Incremental Static Regeneration (ISR)
151-
Add the following code to the top of every route with `getStaticProps` that uses `revalidate` (including the new `res.unstable_revalidate`/`res.revalidate` of on-demand ISR, available since Next 12.1):
171+
Add the following code to the top of every route with `getStaticProps` that uses `revalidate` (including `res.revalidate` or `res.unstable_revalidate` (< 12.2) of on-demand ISR, available since Next 12.1):
152172

153173
```js
154174
export const config = {
@@ -166,8 +186,10 @@ Furthermore, most middlewares, functions, parameters and types have JSDoc that i
166186
add the `reporting` middleware to your middleware chain in `middleware.js` or `pages/_middleware.js`:
167187

168188
```js
189+
// middleware.js
169190
import {
170-
chain,
191+
chainMatch,
192+
isPageRequest
171193
csp,
172194
reporting,
173195
strictDynamic,
@@ -192,7 +214,7 @@ const securityMiddleware = [
192214
}),
193215
];
194216

195-
export default chain(...securityMiddleware);
217+
export default chainMatch(isPageRequest)(...securityMiddleware);
196218
```
197219

198220
then, set up the reporting endpoint in `pages/api/reporting.js`:
@@ -201,7 +223,8 @@ then, set up the reporting endpoint in `pages/api/reporting.js`:
201223
import { reporting } from '@next-safe/middleware/dist/api';
202224

203225
/** @type {import('@next-safe/middleware/dist/api').Reporter} */
204-
const consoleLogReporter = (data) => console.log(JSON.stringify(data));
226+
const consoleLogReporter = (data) =>
227+
console.log(JSON.stringify(data, undefined, 2));
205228

206229
export default reporting(consoleLogReporter);
207230
```
@@ -213,7 +236,10 @@ If you use Sentry, there is a convenient helper `sentryCspReporterForEndpoint` t
213236

214237
```js
215238
// pages/api/reporting.js
216-
import { reporting, buildSentryCspReporter } from '@next-safe/middleware/dist/api';
239+
import {
240+
reporting,
241+
sentryCspReporterForEndpoint,
242+
} from '@next-safe/middleware/dist/api';
217243

218244
// lookup at https://docs.sentry.io/product/security-policy-reporting/
219245
const sentryCspEndpoint = process.env.SENTRY_CSP_ENDPOINT;
@@ -225,20 +251,26 @@ export default reporting(sentryCspReporter);
225251
Sentry only supports the data format of the `report-uri` directive. It can't receive violation reports in `report-to` format (Google Chrome only serves `report-to`). `sentryCspReporterForEndpoint` does the necessary conversion, so you will receive violation reports from all major browsers in Sentry.
226252

227253
## How to add custom (inline) scripts that work with strict CSP?
228-
Just add them with `next/script` on the pages where you need them. If you want to include a script in all pages, add them to your `pages/app.js`. For examples, have a look at [`apps/e2e/pages/_app.tsx`](https://github.com/nibtime/next-safe-middleware/blob/main/apps/e2e/pages/_document.tsx).
254+
Just add them with `next/script` on the pages where you need them. If you want to include a script in all pages, add them to your `pages/app.js`.
255+
256+
The following files serve as examples for script usage:
257+
258+
* [`apps/e2e/pages/_document.tsx`](https://github.com/nibtime/next-safe-middleware/blob/main/apps/e2e/pages/_document.tsx)
259+
260+
* [`apps/e2e/pages/_app.tsx`](https://github.com/nibtime/next-safe-middleware/blob/main/apps/e2e/pages/_app.tsx)
229261

230262
### How this behaves behind the scenes
231-
Scripts with strategies `afterInteractive` and `lazyOnLoad` will become trusted by transitive trust propagation of `strict-dynamic` and so will be all scripts that they load dynamically, etc. That should cover the majority of use cases.
263+
`<Script>`'s with strategies `afterInteractive` and `lazyOnLoad` will become trusted by transitive trust propagation of `strict-dynamic` and so will be all scripts that they load dynamically, etc. That should cover the majority of use cases.
232264

233-
Scripts with strategy `beforeInteractive` and scripts that are placed as children of `<Head>` in `_document.js` are picked up for CSP by this package.
265+
`<Script>`'s with strategy `beforeInteractive` you place in `_document.js`and inline `<script>`'s you place as children of `<Head>` in `_document.js` are automatically picked up for strict CSP by this package.
234266

235267
What this package will do with such scripts, depends:
236268

237269
#### Pages with getServerSideProps (Nonce-based)
238-
the script element will eventually receive the nonce.
270+
the script will eventually receive the nonce.
239271

240272
#### Pages with getStaticProps (Hash-based)
241-
1. The script loads from `src` has an integrity attribute: The integrity attribute/hash will be picked up for CSP.
273+
1. The script loads from `src` and has an integrity attribute: The integrity attribute/hash will be picked up for CSP. Don't forget to set `{crossOrigin: "anonymous"}` in `next.config.js`, else the [SRI](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity) validation will fail.
242274

243275
2. The script loads from `src` and doesn't have an integrity attribute: The script will be replaced by an inline proxy script that loads the script. The hash of this proxy script will be picked up for CSP. The actual script eventually becomes trusted by transitive trust propagation of `strict-dynamic`.
244276

@@ -261,19 +293,20 @@ For this you can use the `nextSafe` middleware that wraps the [`next-safe`](http
261293
```js
262294
// middleware.js
263295
import {
264-
chain,
296+
chainMatch,
297+
isPageRequest,
265298
csp,
266299
nextSafe,
267300
strictDynamic,
268301
} from '@next-safe/middleware';
269302

270-
const securityMiddleware = [
271-
nextSafe({ disableCsp: true })
272-
csp(),
273-
strictDynamic(),
274-
];
303+
const securityMiddleware = [
304+
nextSafe({ disableCsp: true }),
305+
csp(),
306+
strictDynamic(),
307+
];
275308

276-
export default chain(...securityMiddleware);
309+
export default chainMatch(isPageRequest)(...securityMiddleware);
277310
```
278311

279312
The configuration options of the `nextSafe` middleware are the same as documented at https://trezy.gitbook.io/next-safe/usage/configuration
@@ -324,7 +357,13 @@ Here's an example to show how you can combine security middleware from this pack
324357

325358
```js
326359
// middleware.js
327-
import { chain, csp, strictDynamic } from '@next-safe/middleware';
360+
import {
361+
chain,
362+
chainMatch,
363+
isPageRequest,
364+
csp,
365+
strictDynamic,
366+
} from '@next-safe/middleware';
328367

329368
/** @type {import('@next-safe/middleware').ChainableMiddleware} */
330369
const geoBlockMiddleware = (req) => {
@@ -334,45 +373,47 @@ const geoBlockMiddleware = (req) => {
334373
if (country === BLOCKED_COUNTRY) {
335374
const response = new Response('Blocked for legal reasons', { status: 451 });
336375
// returning response terminates the chain
337-
return response
376+
return response;
338377
}
339-
}
378+
};
340379

341-
const securityMiddleware = [
342-
csp(),
343-
strictDynamic(),
344-
]
380+
const securityMiddleware = [csp(), strictDynamic()];
345381

346-
// security middleware will only run on requests that didn't get geo-blocked
347-
export default chain(geoBlockMiddleware, ...securityMiddleware)
382+
// geoBlockMiddleware will run on all requests
383+
// securityMiddleware will only run on requests
384+
// that didn't get geo-blocked and only on requests for pages
385+
export default chain(
386+
geoBlockMiddleware,
387+
chainMatch(isPageRequest)(...securityMiddleware)
388+
);
348389
```
349390

350391
### Can CSP/middleware configuration depend on request data?
351392
Yes. In fact every middleware of this package supports configuration with an (async) initializer function, that receives the request as 1st param (in `req`), the currently set response of the middleware chain as 2nd (in `res`) and for convenience, a `uaParser` instance prepared with the user agent of the request as 3rd (from [`ua-parser-js`](https://www.npmjs.com/package/ua-parser-js), prebundled and minified with this package, for IntelliSense install `@types/ua-parser-js` in your project.
352393

353394
For example, you can use this capability to select different CSP configurations for different user agents:
395+
354396
```js
355397
// middleware.js
356398
import {
357-
chain,
399+
chainMatch,
400+
isPageRequest,
358401
csp,
359402
strictDynamic,
360-
} from '@next-safe/middleware';
403+
} from "@next-safe/middleware";
361404

362-
// CSP in always in report-only mode for Firefox and by env var for other browsers
405+
// CSP in always in report-only mode for Firefox
406+
// and by env var for other browsers
363407
const cspMiddleware = csp(async (req, res, uaParser) => {
364-
const browserName = uaParser.getBrowser().name || '';
365-
const reportOnly = !!process.env.CSP_REPORT_ONLY || browserName.includes('Firefox');
408+
const browserName = uaParser.getBrowser().name || "";
409+
const reportOnly =
410+
!!process.env.CSP_REPORT_ONLY || browserName.includes("Firefox");
366411
return {
367-
reportOnly
412+
reportOnly,
368413
};
369-
}),
370-
371-
const securityMiddleware = [
372-
cspMiddleware,
373-
strictDynamic(),
374-
];
414+
});
375415

376-
export default chain(...securityMiddleware);
416+
const securityMiddleware = [cspMiddleware, strictDynamic()];
377417

418+
export default chainMatch(isPageRequest)(...securityMiddleware);;
378419
```

packages/next-safe-middleware/package.json

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,17 +66,16 @@
6666
"bugs": {
6767
"url": "https://github.com/nibtime/next-safe-middleware/issues"
6868
},
69-
"homepage": "https://github.com/nibtime/next-safe-middleware/tree/main/#readme",
69+
"homepage": "https://next-safe-middleware.vercel.app/",
7070
"description": "Strict Content-Security-Policy (CSP) for Next.js",
7171
"keywords": [
7272
"nextjs",
7373
"security",
7474
"content-security-policy",
7575
"strict-csp",
7676
"strict-dynamic",
77-
"csp",
78-
"content-security-policy-report-only",
79-
"reportingapi",
80-
"vercel"
77+
"report-uri",
78+
"report-to",
79+
"reporting-api"
8180
]
8281
}

0 commit comments

Comments
 (0)