fix(security): закрыть открытые эндпоинты + SSRF-гард webhook перед go-live
- /api/dashboard/summary, /api/managers, /api/lead-statuses: были без auth (tenant_id параметром) → auth:sanctum (+tenant); tenant_id из authed-user, не из параметра — закрывает кросс-tenant утечку KPI/списка пользователей - ManagerController: явный where(tenant_id) поверх RLS (BYPASSRLS-роли/тесты) - WebhookUrlGuard + webhooks/test: SSRF-блок private/reserved/loopback IP (cloud-metadata 169.254.169.254 и пр.); update()/delivery — follow-up - TDD: +EndpointAuthHardeningTest(5) +WebhookSsrfGuardTest(10); обновлены Dashboard/Lookups/LeadStatuses тесты под auth - регрессия tests/Feature 960/964 (2 фейла pre-existing: Vite-manifest env + RouteSupplierLeadJobBilling idempotency — оба фейлят и на чистом base) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,7 @@ namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\OutboundWebhookSubscription;
|
||||
use App\Support\WebhookUrlGuard;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
@@ -95,14 +96,25 @@ class WebhookSettingsController extends Controller
|
||||
], Response::HTTP_UNPROCESSABLE_ENTITY);
|
||||
}
|
||||
|
||||
// SSRF-гард: target_url задаёт админ тенанта; блокируем адреса во
|
||||
// внутренней/зарезервированной сети (cloud-metadata 169.254.169.254,
|
||||
// loopback, RFC1918), которые https://-валидация на сохранении не ловит.
|
||||
$blockReason = WebhookUrlGuard::blockReason($sub->target_url);
|
||||
if ($blockReason !== null) {
|
||||
return response()->json([
|
||||
'ok' => false,
|
||||
'status' => null,
|
||||
'message' => $blockReason,
|
||||
], Response::HTTP_UNPROCESSABLE_ENTITY);
|
||||
}
|
||||
|
||||
$testPayload = [
|
||||
'event' => 'webhook.test',
|
||||
'sent_at' => now()->toIso8601String(),
|
||||
'message' => 'Тестовая доставка webhook от Лидерра.',
|
||||
];
|
||||
|
||||
// MVP: unsigned connectivity-проверка. SSRF-харднинг (блок приватных
|
||||
// IP) — пост-MVP security-review; URL уже ограничен https:// валидацией.
|
||||
// Unsigned connectivity-проверка (HMAC-подписанная доставка — отдельный эпик).
|
||||
try {
|
||||
$response = Http::timeout(10)
|
||||
->withHeaders(['X-Webhook-Event' => 'webhook.test'])
|
||||
|
||||
Reference in New Issue
Block a user