Add CSRF, CAPTCHA, and input validation improvements
Introduces CSRF protection to all sensitive controller actions, integrates configurable CAPTCHA (reCAPTCHA v2/v3, Turnstile) for authentication and registration flows, and centralizes input validation via a new InputValidator helper. Adds new helpers and services for CSRF and CAPTCHA, updates settings and migration for CAPTCHA configuration, and enhances logging and error handling in TLD registry import processes. Also improves validation for user, domain, group, and profile inputs throughout the application.
This commit is contained in:
@@ -23,7 +23,7 @@ class DomainController extends Controller
|
||||
public function index()
|
||||
{
|
||||
// Get filter parameters
|
||||
$search = $_GET['search'] ?? '';
|
||||
$search = \App\Helpers\InputValidator::sanitizeSearch($_GET['search'] ?? '', 100);
|
||||
$status = $_GET['status'] ?? '';
|
||||
$groupId = $_GET['group'] ?? '';
|
||||
$sortBy = $_GET['sort'] ?? 'domain_name';
|
||||
@@ -131,6 +131,9 @@ class DomainController extends Controller
|
||||
return;
|
||||
}
|
||||
|
||||
// CSRF Protection
|
||||
$this->verifyCsrf('/domains/create');
|
||||
|
||||
$domainName = trim($_POST['domain_name'] ?? '');
|
||||
$groupId = !empty($_POST['notification_group_id']) ? (int)$_POST['notification_group_id'] : null;
|
||||
|
||||
@@ -141,6 +144,13 @@ class DomainController extends Controller
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate domain format
|
||||
if (!\App\Helpers\InputValidator::validateDomain($domainName)) {
|
||||
$_SESSION['error'] = 'Invalid domain name format (e.g., example.com)';
|
||||
$this->redirect('/domains/create');
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if domain already exists
|
||||
if ($this->domainModel->existsByDomain($domainName)) {
|
||||
$_SESSION['error'] = 'Domain already exists';
|
||||
@@ -212,6 +222,9 @@ class DomainController extends Controller
|
||||
return;
|
||||
}
|
||||
|
||||
// CSRF Protection
|
||||
$this->verifyCsrf('/domains');
|
||||
|
||||
$id = (int)($params['id'] ?? 0);
|
||||
$domain = $this->domainModel->find($id);
|
||||
|
||||
@@ -391,6 +404,9 @@ class DomainController extends Controller
|
||||
return;
|
||||
}
|
||||
|
||||
// CSRF Protection
|
||||
$this->verifyCsrf('/domains/bulk-add');
|
||||
|
||||
// POST - Process bulk add
|
||||
$domainsText = trim($_POST['domains'] ?? '');
|
||||
$groupId = !empty($_POST['notification_group_id']) ? (int)$_POST['notification_group_id'] : null;
|
||||
@@ -467,6 +483,9 @@ class DomainController extends Controller
|
||||
return;
|
||||
}
|
||||
|
||||
// CSRF Protection
|
||||
$this->verifyCsrf('/domains');
|
||||
|
||||
$domainIds = $_POST['domain_ids'] ?? [];
|
||||
|
||||
if (empty($domainIds)) {
|
||||
@@ -475,6 +494,14 @@ class DomainController extends Controller
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate bulk operation size
|
||||
$sizeError = \App\Helpers\InputValidator::validateArraySize($domainIds, 1000, 'Domain selection');
|
||||
if ($sizeError) {
|
||||
$_SESSION['error'] = $sizeError;
|
||||
$this->redirect('/domains');
|
||||
return;
|
||||
}
|
||||
|
||||
$refreshed = 0;
|
||||
$failed = 0;
|
||||
|
||||
@@ -516,6 +543,9 @@ class DomainController extends Controller
|
||||
return;
|
||||
}
|
||||
|
||||
// CSRF Protection
|
||||
$this->verifyCsrf('/domains');
|
||||
|
||||
$domainIds = $_POST['domain_ids'] ?? [];
|
||||
|
||||
if (empty($domainIds)) {
|
||||
@@ -524,6 +554,14 @@ class DomainController extends Controller
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate bulk operation size
|
||||
$sizeError = \App\Helpers\InputValidator::validateArraySize($domainIds, 1000, 'Domain selection');
|
||||
if ($sizeError) {
|
||||
$_SESSION['error'] = $sizeError;
|
||||
$this->redirect('/domains');
|
||||
return;
|
||||
}
|
||||
|
||||
$deleted = 0;
|
||||
foreach ($domainIds as $id) {
|
||||
if ($this->domainModel->delete($id)) {
|
||||
@@ -542,6 +580,9 @@ class DomainController extends Controller
|
||||
return;
|
||||
}
|
||||
|
||||
// CSRF Protection
|
||||
$this->verifyCsrf('/domains');
|
||||
|
||||
$domainIds = $_POST['domain_ids'] ?? [];
|
||||
$groupId = !empty($_POST['group_id']) ? (int)$_POST['group_id'] : null;
|
||||
|
||||
@@ -551,6 +592,14 @@ class DomainController extends Controller
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate bulk operation size
|
||||
$sizeError = \App\Helpers\InputValidator::validateArraySize($domainIds, 1000, 'Domain selection');
|
||||
if ($sizeError) {
|
||||
$_SESSION['error'] = $sizeError;
|
||||
$this->redirect('/domains');
|
||||
return;
|
||||
}
|
||||
|
||||
$updated = 0;
|
||||
foreach ($domainIds as $id) {
|
||||
if ($this->domainModel->update($id, ['notification_group_id' => $groupId])) {
|
||||
@@ -569,6 +618,9 @@ class DomainController extends Controller
|
||||
return;
|
||||
}
|
||||
|
||||
// CSRF Protection
|
||||
$this->verifyCsrf('/domains');
|
||||
|
||||
$domainIds = $_POST['domain_ids'] ?? [];
|
||||
$isActive = isset($_POST['is_active']) ? (int)$_POST['is_active'] : 1;
|
||||
|
||||
@@ -578,6 +630,14 @@ class DomainController extends Controller
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate bulk operation size
|
||||
$sizeError = \App\Helpers\InputValidator::validateArraySize($domainIds, 1000, 'Domain selection');
|
||||
if ($sizeError) {
|
||||
$_SESSION['error'] = $sizeError;
|
||||
$this->redirect('/domains');
|
||||
return;
|
||||
}
|
||||
|
||||
$updated = 0;
|
||||
foreach ($domainIds as $id) {
|
||||
if ($this->domainModel->update($id, ['is_active' => $isActive])) {
|
||||
@@ -597,6 +657,9 @@ class DomainController extends Controller
|
||||
return;
|
||||
}
|
||||
|
||||
// CSRF Protection
|
||||
$this->verifyCsrf('/domains');
|
||||
|
||||
$id = (int)($params['id'] ?? 0);
|
||||
$domain = $this->domainModel->find($id);
|
||||
|
||||
@@ -608,6 +671,14 @@ class DomainController extends Controller
|
||||
|
||||
$notes = $_POST['notes'] ?? '';
|
||||
|
||||
// Validate notes length
|
||||
$lengthError = \App\Helpers\InputValidator::validateLength($notes, 5000, 'Notes');
|
||||
if ($lengthError) {
|
||||
$_SESSION['error'] = $lengthError;
|
||||
$this->redirect('/domains/' . $id);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->domainModel->update($id, [
|
||||
'notes' => $notes
|
||||
]);
|
||||
|
||||
Reference in New Issue
Block a user