fix(security): add CSRF protection to all POST endpoints + contract tests (B2)
CSRF guards added to 16 admin pages that previously accepted POST requests without token verification (GR-SEC-001): departments, permissions, roles, settings, tenants, users (create/edit/bulk/tokens), and lang switch. New contract tests: - PostEndpointCsrfContractTest: scans all pages/ for POST handlers and verifies checkCsrfToken is present (API/data endpoints exempt). - DatabaseUpdatesContractTest: validates db/updates/ scripts follow naming convention and use idempotent SQL patterns (GR-CORE-010). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,8 @@ use MintyPHP\Http\SessionStoreInterface;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Service\Access\UserAuthorizationPolicy;
|
||||
use MintyPHP\Service\User\UserAccessPdfService;
|
||||
use MintyPHP\Session;
|
||||
use MintyPHP\Support\Flash;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
$session = app(SessionStoreInterface::class)->all();
|
||||
@@ -27,6 +29,12 @@ if (strtoupper((string) (requestInput()->method())) !== 'POST') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Session::checkCsrfToken()) {
|
||||
Flash::error(t('Form expired, please try again'), 'admin/users', 'csrf_expired');
|
||||
Router::redirect('admin/users');
|
||||
return;
|
||||
}
|
||||
|
||||
$errorBag = formErrors();
|
||||
$raw = requestInput()->bodyAll()['uuids'] ?? '';
|
||||
$uuids = [];
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
use MintyPHP\Http\SessionStoreInterface;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Service\Access\UserAuthorizationPolicy;
|
||||
use MintyPHP\Session;
|
||||
use MintyPHP\Support\Flash;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
@@ -31,6 +32,12 @@ if (!$decision->isAllowed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Session::checkCsrfToken()) {
|
||||
Flash::error(t('Form expired, please try again'), "admin/users/edit/{$uuid}", 'csrf_expired');
|
||||
Router::redirect("admin/users/edit/{$uuid}");
|
||||
return;
|
||||
}
|
||||
|
||||
$name = trim((string) (requestInput()->bodyAll()['token_name'] ?? ''));
|
||||
|
||||
if ($name === '') {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
use MintyPHP\Http\SessionStoreInterface;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Service\Access\UserAuthorizationPolicy;
|
||||
use MintyPHP\Session;
|
||||
use MintyPHP\Support\Flash;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
@@ -29,6 +30,12 @@ if (!$decision->isAllowed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Session::checkCsrfToken()) {
|
||||
Flash::error(t('Form expired, please try again'), "admin/users/edit/{$uuid}", 'csrf_expired');
|
||||
Router::redirect("admin/users/edit/{$uuid}");
|
||||
return;
|
||||
}
|
||||
|
||||
$tokenId = (int) (requestInput()->bodyAll()['token_id'] ?? 0);
|
||||
|
||||
if ($tokenId > 0) {
|
||||
|
||||
@@ -4,11 +4,17 @@ use MintyPHP\Http\SessionStoreInterface;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Service\Access\UserAuthorizationPolicy;
|
||||
use MintyPHP\Service\User\UserAccessTemplateService;
|
||||
use MintyPHP\Session;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
$session = app(SessionStoreInterface::class)->all();
|
||||
Guard::requireLogin();
|
||||
|
||||
if (!Session::checkCsrfToken()) {
|
||||
Router::json(['ok' => false, 'error' => 'csrf_expired']);
|
||||
return;
|
||||
}
|
||||
|
||||
$action = strtolower(trim((string) ($action ?? '')));
|
||||
$allowedActions = ['activate', 'deactivate', 'delete', 'send-access'];
|
||||
if (!in_array($action, $allowedActions, true)) {
|
||||
|
||||
@@ -9,6 +9,7 @@ use MintyPHP\Service\Access\UiAccessService;
|
||||
use MintyPHP\Service\Access\UiCapabilityMap;
|
||||
use MintyPHP\Service\Access\UserAuthorizationPolicy;
|
||||
use MintyPHP\Service\CustomField\UserCustomFieldValueService;
|
||||
use MintyPHP\Session;
|
||||
use MintyPHP\Support\Flash;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
@@ -91,6 +92,12 @@ $form = [
|
||||
'active' => 1,
|
||||
];
|
||||
|
||||
if ($request->isMethod('POST') && !Session::checkCsrfToken()) {
|
||||
Flash::error(t('Form expired, please try again'), 'admin/users/create', 'csrf_expired');
|
||||
Router::redirect('admin/users/create');
|
||||
return;
|
||||
}
|
||||
|
||||
if ($request->hasBody('email')) {
|
||||
$post = $request->bodyAll();
|
||||
$input = $post;
|
||||
|
||||
@@ -8,6 +8,7 @@ use MintyPHP\Repository\Auth\RememberTokenRepository;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Service\Access\UserAuthorizationPolicy;
|
||||
use MintyPHP\Service\CustomField\UserCustomFieldValueService;
|
||||
use MintyPHP\Session;
|
||||
use MintyPHP\Support\Flash;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
@@ -173,6 +174,12 @@ if ($canViewSecurityArtifacts) {
|
||||
$canManageApiTokens = $canManageApiTokens && $canViewSecurityArtifacts;
|
||||
$showApiTokens = $canViewSecurityArtifacts && (!empty($apiTokens) || $canManageApiTokens);
|
||||
|
||||
if ($request->isMethod('POST') && !Session::checkCsrfToken()) {
|
||||
Flash::error(t('Form expired, please try again'), "admin/users/edit/{$uuid}", 'csrf_expired');
|
||||
Router::redirect("admin/users/edit/{$uuid}");
|
||||
return;
|
||||
}
|
||||
|
||||
if ($request->hasBody('email')) {
|
||||
$post = $request->bodyAll();
|
||||
$submitDecision = $authorizationService->authorize(UserAuthorizationPolicy::ABILITY_ADMIN_USERS_EDIT_SUBMIT, [
|
||||
|
||||
Reference in New Issue
Block a user