diff --git a/.claude/skills/migrate-to-1.0/SKILL.md b/.claude/skills/migrate-to-1.0/SKILL.md index c8cc95e..4a3906d 100644 --- a/.claude/skills/migrate-to-1.0/SKILL.md +++ b/.claude/skills/migrate-to-1.0/SKILL.md @@ -82,7 +82,9 @@ becomes Also add `use Ray\WebFormModule\Annotation\CsrfProtection;`. If `antiCsrf=false` (or omitted), drop the option without adding -`#[CsrfProtection]` — methods without the attribute perform no CSRF check. +`#[CsrfProtection]`. The method itself then performs no attribute-driven +CSRF check; the form may still enforce CSRF if it uses `SetAntiCsrfTrait` +(see "Out of scope" below). ### 1c. `@InputValidation` and `@VndError` @@ -194,7 +196,8 @@ Report to the user: - Migrating other libraries' annotations (only `Ray\WebFormModule\Annotation\*`). - Renaming `SetAntiCsrfTrait` — the trait and `setAntiCsrf()` method are unchanged in 1.0. -- Changes to forms that use `AntiCsrf` without `#[CsrfProtection]` — - flag these to the user: in 1.0 they will silently stop enforcing CSRF. - The user must decide whether to add `#[CsrfProtection]` to the validated - controller method or accept the new behaviour. +- Deciding whether `#[CsrfProtection]` added by Step 1b is redundant. Forms + that already use `SetAntiCsrfTrait` enforce CSRF via `AbstractForm::apply()` + regardless of the attribute, so the attribute Step 1b inserts is harmless + but unnecessary. Flag these to the user so they can drop the attribute if + they prefer a single declaration site. diff --git a/.markdownlint.json b/.markdownlint.json new file mode 100644 index 0000000..5ea4e95 --- /dev/null +++ b/.markdownlint.json @@ -0,0 +1,5 @@ +{ + "MD046": { + "style": "fenced" + } +} diff --git a/README.JA.md b/README.JA.md index 1d5c2f3..278b46a 100644 --- a/README.JA.md +++ b/README.JA.md @@ -127,20 +127,26 @@ class MyController ### CSRF Protections -CSRF対策は **opt-in** です。`SetAntiCsrfTrait` を使うフォームには `AntiCsrfInterface` が注入されますが、 -トークンの検証は `#[CsrfProtection]` 属性が付いたメソッドでのみ行われます。 -`#[CsrfProtection]` が無いメソッドでは、フォーム側に AntiCsrf がセットされていても CSRF チェックは実行されません。 +CSRF対策は **opt-in** で、独立した 2 つの経路のいずれかで有効化できます。 + +- **フォーム単位**: フォームに `use SetAntiCsrfTrait;` を追加します。 + Ray.Di がトレイトの `#[Inject]` setter 経由で `AntiCsrfInterface` を注入し、 + `postConstruct()` でトークンフィールドが追加され、`apply()` の呼び出しごとに + トークンが検証されます。 +- **アクション単位**: バリデーション対象のコントローラメソッドに + `#[CsrfProtection]` を付与します。`AuraInputInterceptor` が `apply()` 実行前に + `AntiCsrfInterface` をフォームへ注入します。 + +どちらの経路でも、トークン不一致時には `AbstractForm::apply()` が +`CsrfViolationException` を throw します。どちらも使わない場合は CSRF 検証は +行われません。両方を併用しても害はありませんが冗長なので、用途に合わせて +どちらか一方を選んでください。 + +アクション単位 — コントローラのメソッドで宣言: ```php -use Ray\WebFormModule\AbstractAuraForm; use Ray\WebFormModule\Annotation\CsrfProtection; use Ray\WebFormModule\Annotation\FormValidation; -use Ray\WebFormModule\SetAntiCsrfTrait; - -class MyForm extends AbstractAuraForm -{ - use SetAntiCsrfTrait; -} class MyController { @@ -152,6 +158,18 @@ class MyController } ``` +フォーム単位 — フォーム自身で宣言: + +```php +use Ray\WebFormModule\AbstractForm; +use Ray\WebFormModule\SetAntiCsrfTrait; + +class MyForm extends AbstractForm +{ + use SetAntiCsrfTrait; +} +``` + セキュリティレベルを高めるためにはユーザーの認証を含んだカスタムCsrfクラスを作成してフォームクラスにセットします。 詳しくはAura.Inputの[Applying CSRF Protections](https://github.com/auraphp/Aura.Input#applying-csrf-protections)をご覧ください。 diff --git a/README.md b/README.md index 274dca2..fddc5e8 100644 --- a/README.md +++ b/README.md @@ -142,21 +142,26 @@ or render input element basis. ``` ### CSRF Protections -CSRF protection is **opt-in**. A form that uses `SetAntiCsrfTrait` is wired -with an `AntiCsrfInterface`, but the token is only verified when the -validated method is annotated with `#[CsrfProtection]`. Methods without -`#[CsrfProtection]` perform no CSRF check even if the form supports it. +CSRF protection is **opt-in** and can be enabled through either of two +independent paths: + +- **Per-form**: add `use SetAntiCsrfTrait;` to the form. `AntiCsrfInterface` + is injected by Ray.Di through the trait's `#[Inject]` setter, the token + field is added in `postConstruct()`, and every `apply()` call verifies + the token. +- **Per-action**: annotate the validated controller method with + `#[CsrfProtection]`. `AuraInputInterceptor` then injects + `AntiCsrfInterface` into the form before `apply()` runs. + +Either path causes `AbstractForm::apply()` to throw `CsrfViolationException` +on token mismatch. Without either path, no CSRF check is performed. Combining +both paths is harmless but redundant — pick whichever fits your use case. + +Per-action — declare CSRF on the controller method: ```php -use Ray\WebFormModule\AbstractAuraForm; use Ray\WebFormModule\Annotation\CsrfProtection; use Ray\WebFormModule\Annotation\FormValidation; -use Ray\WebFormModule\SetAntiCsrfTrait; - -class MyForm extends AbstractAuraForm -{ - use SetAntiCsrfTrait; -} class MyController { @@ -167,6 +172,19 @@ class MyController } } ``` + +Per-form — declare CSRF on the form itself: + +```php +use Ray\WebFormModule\AbstractForm; +use Ray\WebFormModule\SetAntiCsrfTrait; + +class MyForm extends AbstractForm +{ + use SetAntiCsrfTrait; +} +``` + You can provide your custom `AntiCsrf` class. See more detail at [Aura.Input](https://github.com/auraphp/Aura.Input#applying-csrf-protections) ## Migration from 0.x