0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2025-02-17 22:44:24 -05:00

feat: make CSRF protection stable (#11021)

* feat: make CSRF protection stable

* revert change

* Apply suggestions from code review

Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>

* Update packages/astro/src/@types/astro.ts

Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>

* Update packages/astro/src/@types/astro.ts

Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>

* beef up changeset

* Update .changeset/chatty-experts-smell.md

Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>

* Update .changeset/chatty-experts-smell.md

Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>

* move section

* Apply suggestions from code review

Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>

---------

Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>
This commit is contained in:
Emanuele Stoppa 2024-05-22 12:10:30 +01:00 committed by GitHub
parent c30a415986
commit 2d4c8faa56
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 84 additions and 78 deletions

View file

@ -0,0 +1,30 @@
---
"astro": minor
---
The CSRF protection feature that was introduced behind a flag in [v4.6.0](https://github.com/withastro/astro/blob/main/packages/astro/CHANGELOG.md#460) is no longer experimental and is available for general use.
To enable the stable version, add the new top-level `security` option in `astro.config.mjs`. If you were previously using the experimental version of this feature, also delete the experimental flag:
```diff
export default defineConfig({
- experimental: {
- security: {
- csrfProtection: {
- origin: true
- }
- }
- },
+ security: {
+ checkOrigin: true
+ }
})
```
Enabling this setting performs a check that the `"origin"` header, automatically passed by all modern browsers, matches the URL sent by each Request.
This check is executed only for pages rendered on demand, and only for the requests `POST`, `PATCH`, `DELETE` and `PUT` with one of the following `"content-type"` headers: `'application/x-www-form-urlencoded'`, `'multipart/form-data'`, `'text/plain'`.
If the `"origin"` header doesn't match the pathname of the request, Astro will return a 403 status code and won't render the page.
For more information, see the [`security` configuration docs](https://docs.astro.build/en/reference/configuration-reference/#security).

View file

@ -779,6 +779,47 @@ export interface AstroUserConfig {
*/
scopedStyleStrategy?: 'where' | 'class' | 'attribute';
/**
* @docs
* @name security
* @type {boolean}
* @default `{}`
* @version 4.9.0
* @description
*
* Enables security measures for an Astro website.
*
* These features only exist for pages rendered on demand (SSR) using `server` mode or pages that opt out of prerendering in `hybrid` mode.
*
* ```js
* // astro.config.mjs
* export default defineConfig({
* output: "server",
* security: {
* checkOrigin: true
* }
* })
* ```
*/
security?: {
/**
* @name security.checkOrigin
* @type {boolean}
* @default 'false'
* @version 4.6.0
* @description
*
* When enabled, performs a check that the "origin" header, automatically passed by all modern browsers, matches the URL sent by each `Request`. This is used to provide Cross-Site Request Forgery (CSRF) protection.
*
* The "origin" check is executed only for pages rendered on demand, and only for the requests `POST, `PATCH`, `DELETE` and `PUT` with
* the following `content-type` header: 'application/x-www-form-urlencoded', 'multipart/form-data', 'text/plain'.
*
* If the "origin" header doesn't match the `pathname` of the request, Astro will return a 403 status code and will not render the page.
*/
checkOrigin?: boolean;
};
/**
* @docs
* @name vite
@ -1955,63 +1996,7 @@ export interface AstroUserConfig {
* In the event of route collisions, where two routes of equal route priority attempt to build the same URL, Astro will log a warning identifying the conflicting routes.
*/
globalRoutePriority?: boolean;
/**
* @docs
* @name experimental.security
* @type {boolean}
* @default `false`
* @version 4.6.0
* @description
*
* Enables CSRF protection for Astro websites.
*
* The CSRF protection works only for pages rendered on demand (SSR) using `server` or `hybrid` mode. The pages must opt out of prerendering in `hybrid` mode.
*
* ```js
* // astro.config.mjs
* export default defineConfig({
* output: "server",
* experimental: {
* security: {
* csrfProtection: {
* origin: true
* }
* }
* }
* })
* ```
*/
security?: {
/**
* @name security.csrfProtection
* @type {object}
* @default '{}'
* @version 4.6.0
* @description
*
* Allows you to enable security measures to prevent CSRF attacks: https://owasp.org/www-community/attacks/csrf
*/
csrfProtection?: {
/**
* @name security.csrfProtection.origin
* @type {boolean}
* @default 'false'
* @version 4.6.0
* @description
*
* When enabled, performs a check that the "origin" header, automatically passed by all modern browsers, matches the URL sent by each `Request`.
*
* The "origin" check is executed only for pages rendered on demand, and only for the requests `POST, `PATCH`, `DELETE` and `PUT` with
* the following `content-type` header: 'application/x-www-form-urlencoded', 'multipart/form-data', 'text/plain'.
*
* If the "origin" header doesn't match the `pathname` of the request, Astro will return a 403 status code and will not render the page.
*/
origin?: boolean;
};
};
/**
* @docs
* @name experimental.rewriting

View file

@ -558,6 +558,6 @@ function createBuildManifest(
buildFormat: settings.config.build.format,
middleware,
rewritingEnabled: settings.config.experimental.rewriting,
checkOrigin: settings.config.experimental.security?.csrfProtection?.origin ?? false,
checkOrigin: settings.config.security?.checkOrigin ?? false,
};
}

View file

@ -277,7 +277,7 @@ function buildManifest(
assets: staticFiles.map(prefixAssetPath),
i18n: i18nManifest,
buildFormat: settings.config.build.format,
checkOrigin: settings.config.experimental.security?.csrfProtection?.origin ?? false,
checkOrigin: settings.config.security?.checkOrigin ?? false,
rewritingEnabled: settings.config.experimental.rewriting,
};
}

View file

@ -79,6 +79,7 @@ const ASTRO_CONFIG_DEFAULTS = {
vite: {},
legacy: {},
redirects: {},
security: {},
experimental: {
actions: false,
directRenderScript: false,
@ -86,7 +87,6 @@ const ASTRO_CONFIG_DEFAULTS = {
contentCollectionJsonSchema: false,
clientPrerender: false,
globalRoutePriority: false,
security: {},
rewriting: false,
},
} satisfies AstroUserConfig & { server: { open: boolean } };
@ -492,6 +492,12 @@ export const AstroConfigSchema = z.object({
}
})
),
security: z
.object({
checkOrigin: z.boolean().default(false),
})
.optional()
.default(ASTRO_CONFIG_DEFAULTS.security),
experimental: z
.object({
actions: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.actions),
@ -515,17 +521,6 @@ export const AstroConfigSchema = z.object({
.boolean()
.optional()
.default(ASTRO_CONFIG_DEFAULTS.experimental.globalRoutePriority),
security: z
.object({
csrfProtection: z
.object({
origin: z.boolean().default(false),
})
.optional()
.default({}),
})
.optional()
.default(ASTRO_CONFIG_DEFAULTS.experimental.security),
rewriting: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.rewriting),
})
.strict(

View file

@ -144,7 +144,7 @@ export function createDevelopmentManifest(settings: AstroSettings): SSRManifest
componentMetadata: new Map(),
inlinedScripts: new Map(),
i18n: i18nManifest,
checkOrigin: settings.config.experimental.security?.csrfProtection?.origin ?? false,
checkOrigin: settings.config.security?.checkOrigin ?? false,
rewritingEnabled: settings.config.experimental.rewriting,
middleware(_, next) {
return next();

View file

@ -3,12 +3,8 @@ import { defineConfig } from 'astro/config';
// https://astro.build/config
export default defineConfig({
output: "server",
experimental: {
security: {
csrfProtection: {
origin: true
}
}
security: {
checkOrigin: true
}
});