fix(security): add auth to FCM relay, HMAC to shamcash webhook, fix jwtconnect webhook bypass

This commit is contained in:
Hamza-Ayed
2026-06-17 06:27:07 +03:00
parent d6f29802e0
commit 8c6dea5d96
3 changed files with 40 additions and 7 deletions

View File

@@ -1,7 +1,16 @@
<?php
// send_fcm.php - FCM HTTP v1 Sender
// send_fcm.php - FCM HTTP v1 Sender (Internal use only)
header('Content-Type: application/json; charset=utf-8');
// 🔐 Require internal API key for authentication
$apiKey = $_SERVER['HTTP_X_API_KEY'] ?? '';
$expectedKey = getenv('FCM_INTERNAL_API_KEY');
if (empty($expectedKey) || !hash_equals($expectedKey, $apiKey)) {
http_response_code(403);
echo json_encode(['status' => 'error', 'message' => 'Unauthorized']);
exit;
}
$serviceAccountFile = __DIR__ . '/service-account.json';
// السماح فقط بـ POST

View File

@@ -93,11 +93,11 @@ try {
}
// --- Path 3: Webhook Auth Token (MTN/Cliq external services) ---
// ملاحظة: البوابة تعترف بوجود الهيدر فقط. كل webhook يتحقق من القيمة الفعلية بنفسه.
if (!$authMethod) {
$webhookToken = $_SERVER['HTTP_X_AUTH_TOKEN'] ?? '';
$expectedWebhook = getenv('WEBHOOK_AUTH_TOKEN');
if (!empty($webhookToken)) {
if (!empty($expectedWebhook) && !empty($webhookToken) && hash_equals($expectedWebhook, $webhookToken)) {
$authMethod = 'WEBHOOK';
}
}

View File

@@ -1,9 +1,8 @@
<?php
// shamcash/save_transactions.php (Debug Edition)
// shamcash/save_transactions.php
ini_set('display_errors', 0);
error_reporting(E_ALL);
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json");
$log_file = __DIR__ . '/transactions.log';
@@ -17,10 +16,35 @@ function logMsg($msg) {
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
// 🔐 HMAC Signature Verification
$sharedSecret = getenv('SHAMCASH_WEBHOOK_SECRET');
$signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
$timestamp = $_SERVER['HTTP_X_TIMESTAMP'] ?? '';
$rawBody = file_get_contents('php://input');
if (!empty($sharedSecret)) {
if (empty($signature) || empty($timestamp)) {
http_response_code(401);
exit(json_encode(["status" => "error", "msg" => "Missing authentication headers"]));
}
// Verify timestamp is within 5 minutes
if (abs(time() - (int)$timestamp) > 300) {
http_response_code(401);
exit(json_encode(["status" => "error", "msg" => "Request expired"]));
}
$expectedSig = hash_hmac('sha256', $timestamp . '.' . $rawBody, $sharedSecret);
if (!hash_equals($expectedSig, $signature)) {
logMsg("SECURITY: Invalid webhook signature");
http_response_code(403);
exit(json_encode(["status" => "error", "msg" => "Invalid signature"]));
}
logMsg("SECURITY: Webhook signature verified");
}
// الاتصال بقاعدة البيانات
$paths = [__DIR__.'/../jwtconnect.php', __DIR__.'/../../jwtconnect.php', __DIR__.'/../../../jwtconnect.php'];
foreach ($paths as $p) { if (file_exists($p)) { include $p; if(isset($con)) break; } }
if (!isset($con)) { logMsg("CRITICAL: DB Connection Failed"); exit(json_encode(["status" => "error", "msg" => "DB Failed"])); }
foreach ($paths as $p) { if (file_exists($p)) { include $p; } }
if (!isset($con) || !$con) { logMsg("CRITICAL: DB Connection Failed"); exit(json_encode(["status" => "error", "msg" => "DB Failed"])); }
if (file_exists(__DIR__ . "/finalize_deposit.php")) include_once __DIR__ . "/finalize_deposit.php";
if (file_exists(__DIR__ . "/passenger/finalize_deposit.php")) include_once __DIR__ . "/passenger/finalize_deposit.php";