fix(security): add auth to FCM relay, HMAC to shamcash webhook, fix jwtconnect webhook bypass
This commit is contained in:
@@ -1,7 +1,16 @@
|
|||||||
<?php
|
<?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');
|
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';
|
$serviceAccountFile = __DIR__ . '/service-account.json';
|
||||||
|
|
||||||
// السماح فقط بـ POST
|
// السماح فقط بـ POST
|
||||||
|
|||||||
@@ -93,11 +93,11 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// --- Path 3: Webhook Auth Token (MTN/Cliq external services) ---
|
// --- Path 3: Webhook Auth Token (MTN/Cliq external services) ---
|
||||||
// ملاحظة: البوابة تعترف بوجود الهيدر فقط. كل webhook يتحقق من القيمة الفعلية بنفسه.
|
|
||||||
if (!$authMethod) {
|
if (!$authMethod) {
|
||||||
$webhookToken = $_SERVER['HTTP_X_AUTH_TOKEN'] ?? '';
|
$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';
|
$authMethod = 'WEBHOOK';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
// shamcash/save_transactions.php (Debug Edition)
|
// shamcash/save_transactions.php
|
||||||
|
|
||||||
ini_set('display_errors', 0);
|
ini_set('display_errors', 0);
|
||||||
error_reporting(E_ALL);
|
error_reporting(E_ALL);
|
||||||
header("Access-Control-Allow-Origin: *");
|
|
||||||
header("Content-Type: application/json");
|
header("Content-Type: application/json");
|
||||||
|
|
||||||
$log_file = __DIR__ . '/transactions.log';
|
$log_file = __DIR__ . '/transactions.log';
|
||||||
@@ -17,10 +16,35 @@ function logMsg($msg) {
|
|||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
|
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'];
|
$paths = [__DIR__.'/../jwtconnect.php', __DIR__.'/../../jwtconnect.php', __DIR__.'/../../../jwtconnect.php'];
|
||||||
foreach ($paths as $p) { if (file_exists($p)) { include $p; if(isset($con)) break; } }
|
foreach ($paths as $p) { if (file_exists($p)) { include $p; } }
|
||||||
if (!isset($con)) { logMsg("CRITICAL: DB Connection Failed"); exit(json_encode(["status" => "error", "msg" => "DB Failed"])); }
|
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__ . "/finalize_deposit.php")) include_once __DIR__ . "/finalize_deposit.php";
|
||||||
if (file_exists(__DIR__ . "/passenger/finalize_deposit.php")) include_once __DIR__ . "/passenger/finalize_deposit.php";
|
if (file_exists(__DIR__ . "/passenger/finalize_deposit.php")) include_once __DIR__ . "/passenger/finalize_deposit.php";
|
||||||
|
|||||||
Reference in New Issue
Block a user