120 lines
4.4 KiB
Markdown
120 lines
4.4 KiB
Markdown
---
|
||
phase: 04-csrf-protection
|
||
plan: 01
|
||
subsystem: auth
|
||
tags: [csrf, security, session, admin]
|
||
|
||
requires:
|
||
- phase: []
|
||
provides: []
|
||
provides:
|
||
- "CsrfToken class — token generation, validation, regeneration"
|
||
- "CSRF protection on all admin FormRequestHandler POSTs"
|
||
- "CSRF protection on login and 2FA forms"
|
||
- "Token regeneration after successful login (session fixation prevention)"
|
||
affects: []
|
||
|
||
tech-stack:
|
||
added: []
|
||
patterns: ["CSRF guard before field validation in FormRequestHandler", "bin2hex(random_bytes(32)) per-session token"]
|
||
|
||
key-files:
|
||
created:
|
||
- autoload/Shared/Security/CsrfToken.php
|
||
- tests/Unit/Shared/Security/CsrfTokenTest.php
|
||
modified:
|
||
- autoload/admin/Support/Forms/FormRequestHandler.php
|
||
- admin/templates/components/form-edit.php
|
||
- admin/templates/site/unlogged-layout.php
|
||
- admin/templates/users/user-2fa.php
|
||
- autoload/admin/App.php
|
||
|
||
key-decisions:
|
||
- "Single CSRF validate() call placed before switch($sa) in special_actions() — covers all POST actions uniformly"
|
||
- "regenerate() called on successful login AND after 2FA verify — both session fixation points"
|
||
|
||
patterns-established:
|
||
- "CSRF check = first operation in handleSubmit(), before field validation"
|
||
- "CsrfToken::getToken() in templates via htmlspecialchars() escape"
|
||
|
||
duration: ~
|
||
started: 2026-03-12T00:00:00Z
|
||
completed: 2026-03-12T00:00:00Z
|
||
---
|
||
|
||
# Phase 4 Plan 01: CSRF Protection Summary
|
||
|
||
**CSRF protection added to entire admin panel — all state-changing POST endpoints now validate a per-session token.**
|
||
|
||
## Performance
|
||
|
||
| Metric | Value |
|
||
|--------|-------|
|
||
| Duration | single session |
|
||
| Completed | 2026-03-12 |
|
||
| Tasks | 3 completed |
|
||
| Files modified | 7 |
|
||
|
||
## Acceptance Criteria Results
|
||
|
||
| Criterion | Status | Notes |
|
||
|-----------|--------|-------|
|
||
| AC-1: Formularz edycji zawiera _csrf_token | Pass | form-edit.php linia 81 |
|
||
| AC-2: POST bez tokenu odrzucany przez FormRequestHandler | Pass | FormRequestHandler.php linia 36–42 |
|
||
| AC-3: Formularz logowania zawiera _csrf_token | Pass | unlogged-layout.php linia 46 |
|
||
| AC-4: special_actions() waliduje CSRF dla user-logon i 2FA | Pass | App.php linia 47–51, przed switch |
|
||
| AC-5: Token unikalny per sesja, min. 64 znaki hex | Pass | bin2hex(random_bytes(32)) = 64 znaków |
|
||
|
||
## Accomplishments
|
||
|
||
- Nowa klasa `\Shared\Security\CsrfToken` z `getToken()`, `validate()`, `regenerate()`
|
||
- Guard w `FormRequestHandler::handleSubmit()` jako pierwsza operacja przed walidacją pól
|
||
- Token w szablonach: `form-edit.php`, `unlogged-layout.php`, `user-2fa.php` (oba formularze)
|
||
- `regenerate()` wywoływany po udanym logowaniu (linia 96) i po weryfikacji 2FA (linia 140) — zapobiega session fixation
|
||
- 6 testów jednostkowych w `CsrfTokenTest.php`
|
||
|
||
## Task Commits
|
||
|
||
| Task | Commit | Type | Description |
|
||
|------|--------|------|-------------|
|
||
| Wszystkie 3 taski | `55988887` | security | faza 4 - ochrona CSRF panelu administracyjnego |
|
||
|
||
## Files Created/Modified
|
||
|
||
| File | Change | Purpose |
|
||
|------|--------|---------|
|
||
| `autoload/Shared/Security/CsrfToken.php` | Created | Token generation, validation, regeneration |
|
||
| `tests/Unit/Shared/Security/CsrfTokenTest.php` | Created | 6 unit tests dla CsrfToken |
|
||
| `autoload/admin/Support/Forms/FormRequestHandler.php` | Modified | CSRF guard w handleSubmit() |
|
||
| `admin/templates/components/form-edit.php` | Modified | Hidden input _csrf_token |
|
||
| `admin/templates/site/unlogged-layout.php` | Modified | Token w formularzu logowania |
|
||
| `admin/templates/users/user-2fa.php` | Modified | Token w obu formularzach 2FA |
|
||
| `autoload/admin/App.php` | Modified | CSRF walidacja w special_actions() + regenerate() |
|
||
|
||
## Decisions Made
|
||
|
||
| Decision | Rationale | Impact |
|
||
|----------|-----------|--------|
|
||
| Jeden blok validate() przed switch($sa) | Pokrywa wszystkie case jednym sprawdzeniem | Prostota, mniej kodu |
|
||
| `\Exception` catch (nie `\Throwable`) | PHP 7.4 compat, wystarczy dla typowych wyjątków | Akceptowalny tradeoff |
|
||
| Logout poza zakresem (GET link) | Zmiana na POST wykracza poza tę fazę | Zostawione do osobnej iteracji |
|
||
|
||
## Deviations from Plan
|
||
|
||
Brak — plan wykonany zgodnie ze specyfikacją.
|
||
|
||
## Next Phase Readiness
|
||
|
||
**Ready:**
|
||
- Cały admin panel chroniony przed CSRF
|
||
- Wzorzec do replikacji: `CsrfToken::getToken()` w szablonie + `validate()` w handlerze
|
||
|
||
**Concerns:**
|
||
- `admin/ajax.php` (shop-category, users ajax) jeszcze nie pokryty — odnotowane w planie jako out-of-scope
|
||
|
||
**Blockers:** None
|
||
|
||
---
|
||
*Phase: 04-csrf-protection, Plan: 01*
|
||
*Completed: 2026-03-12*
|