summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Emanuele Stoppa <my.burning@gmail.com> 2024-05-22 12:10:30 +0100
committerGravatar GitHub <noreply@github.com> 2024-05-22 12:10:30 +0100
commit2d4c8faa56a64d963fe7847b5be2d7a59e12ed5b (patch)
tree543617bfbfb4518e048775c24b30e9b28aa8f9b6
parentc30a4159864845fc4f01c22bfaab378bd6a6c1f6 (diff)
downloadastro-2d4c8faa56a64d963fe7847b5be2d7a59e12ed5b.tar.gz
astro-2d4c8faa56a64d963fe7847b5be2d7a59e12ed5b.tar.zst
astro-2d4c8faa56a64d963fe7847b5be2d7a59e12ed5b.zip
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>
-rw-r--r--.changeset/chatty-experts-smell.md30
-rw-r--r--packages/astro/src/@types/astro.ts99
-rw-r--r--packages/astro/src/core/build/generate.ts2
-rw-r--r--packages/astro/src/core/build/plugins/plugin-manifest.ts2
-rw-r--r--packages/astro/src/core/config/schema.ts19
-rw-r--r--packages/astro/src/vite-plugin-astro-server/plugin.ts2
-rw-r--r--packages/astro/test/fixtures/csrf-check-origin/astro.config.mjs8
7 files changed, 84 insertions, 78 deletions
diff --git a/.changeset/chatty-experts-smell.md b/.changeset/chatty-experts-smell.md
new file mode 100644
index 000000000..c9ac56f37
--- /dev/null
+++ b/.changeset/chatty-experts-smell.md
@@ -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).
diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts
index 82f4977a2..b1782f39c 100644
--- a/packages/astro/src/@types/astro.ts
+++ b/packages/astro/src/@types/astro.ts
@@ -781,6 +781,47 @@ export interface AstroUserConfig {
/**
* @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
* @typeraw {ViteUserConfig}
* @description
@@ -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
diff --git a/packages/astro/src/core/build/generate.ts b/packages/astro/src/core/build/generate.ts
index ad3877948..eda7739da 100644
--- a/packages/astro/src/core/build/generate.ts
+++ b/packages/astro/src/core/build/generate.ts
@@ -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,
};
}
diff --git a/packages/astro/src/core/build/plugins/plugin-manifest.ts b/packages/astro/src/core/build/plugins/plugin-manifest.ts
index 561e8875b..31c3593dd 100644
--- a/packages/astro/src/core/build/plugins/plugin-manifest.ts
+++ b/packages/astro/src/core/build/plugins/plugin-manifest.ts
@@ -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,
};
}
diff --git a/packages/astro/src/core/config/schema.ts b/packages/astro/src/core/config/schema.ts
index 81d5600ea..ca795b91d 100644
--- a/packages/astro/src/core/config/schema.ts
+++ b/packages/astro/src/core/config/schema.ts
@@ -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(
diff --git a/packages/astro/src/vite-plugin-astro-server/plugin.ts b/packages/astro/src/vite-plugin-astro-server/plugin.ts
index f57660245..8d65940bf 100644
--- a/packages/astro/src/vite-plugin-astro-server/plugin.ts
+++ b/packages/astro/src/vite-plugin-astro-server/plugin.ts
@@ -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();
diff --git a/packages/astro/test/fixtures/csrf-check-origin/astro.config.mjs b/packages/astro/test/fixtures/csrf-check-origin/astro.config.mjs
index af516bcd9..da3e09912 100644
--- a/packages/astro/test/fixtures/csrf-check-origin/astro.config.mjs
+++ b/packages/astro/test/fixtures/csrf-check-origin/astro.config.mjs
@@ -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
}
});