aws-samples / aws-samples/serverless-full-stack-webapp-starter-kit

security(webapp): 兄弟サブドメインからの CSRF を防ぐため Server Actions の allowedOrigins を厳格化する

Open
#210 3 comments 0 reactions 0 assignees View on GitHub
enhancement needs-triage security
Dominant language
TypeScript
Stars
229
Forks
45
Avg merge
1m
Merged PRs (30d)
4

Description

executor 07(全コードベースのコードレビュー)が発見し、独立したセキュリティレビュー(サブエージェント, opus-4.7)で裏付けた。

## 問題

`apps/cdk/lib/constructs/webapp.ts` は Docker ビルド引数 `ALLOWED_ORIGIN_HOST` を、カスタムドメイン分岐では `*.${hostedZone.zoneName}` に(CloudFront デフォルト分岐では `*.cloudfront.net` に)設定している。その値は `apps/webapp/next.config.ts` に取り込まれ、`experimental.serverActions.allowedOrigins` に渡される。

`serverActions.allowedOrigins` は CORS リストではなく、Next.js のデフォルトの CSRF 保護(Origin/Host の一致)を抑制する許可リストである。ワイルドカードを追加すると、そのホストゾーンの任意の兄弟サブドメイン(アプリが所有していない、新規登録された、乗っ取られた、他テナントと共有されているサブドメインを含む)が同一アプリのオリジンとして扱われ、認証済みの Server Actions をアプリに対して送信できてしまう。兄弟サブドメインは same-site であるため、`SameSite=Lax` クッキーではこれを防げない。

`*.cloudfront.net` のフォールバックはさらに悪く、インターネット上の _すべての_ CloudFront ディストリビューションを信頼された CSRF オリジンにしてしまう。

一次情報: https://nextjs.org/docs/app/api-reference/config/next-config-js/serverActions (Server Actions allowedOrigins / 組み込みの CSRF 保護)。

## 根拠

- `apps/cdk/lib/constructs/webapp.ts:80` — `ALLOWED_ORIGIN_HOST: hostedZone ? \`_.${hostedZone.zoneName}\` : '_.cloudfront.net'`
- `apps/webapp/next.config.ts:3-18` — ビルド引数から `allowedOrigins` を構築。

## 対応の方向性(要議論)

- カスタムドメイン分岐: 具体的なホスト(`${subDomain}.${hostedZone.zoneName}`、現状は `web.${zone}`)を渡し、ブラウザの Origin と一致させる。
- CloudFront デフォルト分岐: ドメインはデプロイ時に判明し、Lambda ↔ CloudFront の循環依存を生む(コード内で既に文書化済み)ため、「正確なホストを渡すだけ」では不十分。検討する選択肢: (a) デフォルトの `same-origin` 挙動を受け入れ、ビルド引数を完全に削除する(同一ホストから送信される Server Actions は Origin/Host 一致で成功する); (b) `AMPLIFY_APP_ORIGIN_SOURCE_PARAMETER` を既に更新している既存の `AwsCustomResource` を通じて、実行時に `ALLOWED_ORIGIN_HOST` を更新する。

この修正はエンドツーエンド(Lambda Function URL のレスポンスストリーミング → Next.js Server Actions を通じた `x-forwarded-host` の伝播)で検証する必要があるため、盲目的にマージするのではなく議論用の issue として起票する。

## サンプルとしての教育的リスク

このサンプルは、`allowedOrigins` をあたかも寛容な CORS リストであるかのように設定することを新規ユーザーに教えてしまう。コピーしたアプリが `beta.${zone}` や実験的なサブドメインを追加すると、同一ホストゾーンの任意のサブドメインに対する暗黙の信頼を引き継ぐ。

## 関連

- executor 07 の発見まとめ: `.kiro/specs/v3-release-prep/review-full-report.md` (H2)
- #173 の重複ではない(あちらはセッションキャッシュに関するもので CSRF ではない)。

Contributor guide

Open the contributing guide

Research direction

Read apps/cdk/lib/constructs/webapp.ts and apps/webapp/next.config.ts to trace ALLOWED_ORIGIN_HOST into serverActions.allowedOrigins; also review .kiro/specs/v3-release-prep/review-full-report.md. Decide the custom-domain and CloudFront strategy, then validate through Lambda Function URL response streaming and Next.js Server Actions that only intended origins are accepted.

Written by the indexing model from the issue text.

Assessment

Tech stack
aws, nextjs, typescript
Domain
backend, infrastructure, security
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.