fix(security): fix pervasive IDOR - force JWT user identity in 9 endpoints, fix host injection, exception leaks, wallet auth
This commit is contained in:
@@ -1,12 +1,19 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once __DIR__ . '/../../connect.php';
|
require_once __DIR__ . '/../../connect.php';
|
||||||
|
|
||||||
// استقبال المتغيرات
|
// استقبال المتغيرات — force user IDs from JWT based on role
|
||||||
$driverID = filterRequest("driverID");
|
|
||||||
$passengerID = filterRequest("passengerID");
|
|
||||||
$rideID = filterRequest("rideID");
|
$rideID = filterRequest("rideID");
|
||||||
$note = filterRequest("note");
|
$note = filterRequest("note");
|
||||||
|
|
||||||
|
// Force driverID/passengerID from JWT based on user role
|
||||||
|
if ($role === 'driver') {
|
||||||
|
$driverID = $user_id;
|
||||||
|
$passengerID = filterRequest("passengerID");
|
||||||
|
} else {
|
||||||
|
$passengerID = $user_id;
|
||||||
|
$driverID = filterRequest("driverID");
|
||||||
|
}
|
||||||
|
|
||||||
// تنفيذ الإدخال بطريقة آمنة
|
// تنفيذ الإدخال بطريقة آمنة
|
||||||
$sql = "INSERT INTO `canecl` (`driverID`, `passengerID`, `rideID`, `note`)
|
$sql = "INSERT INTO `canecl` (`driverID`, `passengerID`, `rideID`, `note`)
|
||||||
VALUES (:driverID, :passengerID, :rideID, :note)";
|
VALUES (:driverID, :passengerID, :rideID, :note)";
|
||||||
|
|||||||
@@ -17,7 +17,12 @@ function generateUniqueCode($con) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$driverId = filterRequest("driverId");
|
// Force driverId from JWT — only drivers can manage invitations
|
||||||
|
if ($role !== 'driver') {
|
||||||
|
jsonError("Only drivers can create invitations");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
$driverId = $user_id;
|
||||||
$inviterDriverPhone = filterRequest("inviterDriverPhone");
|
$inviterDriverPhone = filterRequest("inviterDriverPhone");
|
||||||
|
|
||||||
// 🔐 تشفير رقم الهاتف
|
// 🔐 تشفير رقم الهاتف
|
||||||
@@ -52,7 +57,8 @@ if ($checkStmt->rowCount() > 0) {
|
|||||||
"expirationTime" => $expirationTime
|
"expirationTime" => $expirationTime
|
||||||
]);
|
]);
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
jsonError("Database error: " . $e->getMessage());
|
error_log("[invitor/add] DB Error: " . $e->getMessage());
|
||||||
|
jsonError("Database error occurred");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,7 +89,8 @@ if ($checkStmt->rowCount() > 0) {
|
|||||||
jsonError("Failed to save invite data");
|
jsonError("Failed to save invite data");
|
||||||
}
|
}
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
jsonError("Database error: " . $e->getMessage());
|
error_log("[invitor/add] DB Error: " . $e->getMessage());
|
||||||
|
jsonError("Database error occurred");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
@@ -7,8 +7,17 @@ header('Content-Type: application/json');
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
$inviteId = filterRequest("invite_id");
|
$inviteId = filterRequest("invite_id");
|
||||||
$driverId = filterRequest("driver_id");
|
// Force user ID from JWT based on role
|
||||||
$passengerId = filterRequest("passenger_id");
|
if ($role === 'driver') {
|
||||||
|
$driverId = $user_id;
|
||||||
|
$passengerId = null;
|
||||||
|
} elseif ($role === 'passenger') {
|
||||||
|
$passengerId = $user_id;
|
||||||
|
$driverId = null;
|
||||||
|
} else {
|
||||||
|
echo json_encode(["status" => "failure", "message" => "Invalid user role."]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
$countryCode = filterRequest("country_code"); // Expected: Jordan, Syria, Egypt
|
$countryCode = filterRequest("country_code"); // Expected: Jordan, Syria, Egypt
|
||||||
|
|
||||||
if (empty($inviteId)) {
|
if (empty($inviteId)) {
|
||||||
@@ -88,6 +97,7 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function addWalletBalance($url, $userId, $userType, $amount) {
|
function addWalletBalance($url, $userId, $userType, $amount) {
|
||||||
|
$s2sKey = getenv('S2S_SHARED_KEY');
|
||||||
$data = [
|
$data = [
|
||||||
"user_id" => $userId,
|
"user_id" => $userId,
|
||||||
"user_type" => $userType,
|
"user_type" => $userType,
|
||||||
@@ -100,6 +110,11 @@ function addWalletBalance($url, $userId, $userType, $amount) {
|
|||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
curl_setopt($ch, CURLOPT_POST, true);
|
curl_setopt($ch, CURLOPT_POST, true);
|
||||||
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
|
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
|
||||||
|
if ($s2sKey) {
|
||||||
|
curl_setopt($ch, CURLOPT_HTTPHEADER, ["X-Auth-Token: $s2sKey"]);
|
||||||
|
}
|
||||||
$response = curl_exec($ch);
|
$response = curl_exec($ch);
|
||||||
curl_close($ch);
|
curl_close($ch);
|
||||||
return $response;
|
return $response;
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once __DIR__ . '/../../connect.php';
|
require_once __DIR__ . '/../../connect.php';
|
||||||
|
|
||||||
$passenger_id = filterRequest("passenger_id");
|
// Force passenger_id from JWT — never trust user-supplied passenger_id
|
||||||
|
if ($role !== 'passenger') {
|
||||||
|
jsonError("Only passengers can submit ratings");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
$passenger_id = $user_id;
|
||||||
$driverID = filterRequest("driverID");
|
$driverID = filterRequest("driverID");
|
||||||
$rideId = filterRequest("rideId");
|
$rideId = filterRequest("rideId");
|
||||||
$rating = filterRequest("rating");
|
$rating = filterRequest("rating");
|
||||||
|
|||||||
@@ -2,7 +2,12 @@
|
|||||||
require_once __DIR__ . '/../../connect.php';
|
require_once __DIR__ . '/../../connect.php';
|
||||||
|
|
||||||
// --- استقبال المتغيرات ---
|
// --- استقبال المتغيرات ---
|
||||||
$passenger_id = filterRequest("passenger_id");
|
// Force passenger_id from JWT — only passengers can rate drivers
|
||||||
|
if ($role !== 'passenger') {
|
||||||
|
jsonError("Only passengers can rate drivers");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
$passenger_id = $user_id;
|
||||||
$driver_id = filterRequest("driver_id");
|
$driver_id = filterRequest("driver_id");
|
||||||
$ride_id = filterRequest("ride_id");
|
$ride_id = filterRequest("ride_id");
|
||||||
$rating = filterRequest("rating");
|
$rating = filterRequest("rating");
|
||||||
@@ -37,22 +42,11 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
// --- هذا القسم خاص بأخطاء قاعدة البيانات ---
|
error_log("[addRateToDriver] DB Error: " . $e->getMessage() . " | RideID: $ride_id");
|
||||||
|
|
||||||
// 1. تسجيل الخطأ في ملف نصي على السيرفر (للمطور فقط)
|
|
||||||
// سيتم إنشاء ملف اسمه errors.log في نفس المجلد إذا لم يكن موجوداً
|
|
||||||
$errorMsg = "[" . date("Y-m-d H:i:s") . "] DB Error: " . $e->getMessage() . " | RideID: $ride_id \n";
|
|
||||||
file_put_contents("errors.log", $errorMsg, FILE_APPEND);
|
|
||||||
|
|
||||||
// 2. إرجاع رسالة خطأ عامة للتطبيق
|
|
||||||
jsonError("Database Error: Could not save rating");
|
jsonError("Database Error: Could not save rating");
|
||||||
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
// --- هذا القسم خاص بالأخطاء العامة الأخرى ---
|
error_log("[addRateToDriver] General Error: " . $e->getMessage());
|
||||||
|
jsonError("Error: Could not save rating");
|
||||||
$errorMsg = "[" . date("Y-m-d H:i:s") . "] General Error: " . $e->getMessage() . "\n";
|
|
||||||
file_put_contents("errors.log", $errorMsg, FILE_APPEND);
|
|
||||||
|
|
||||||
jsonError("Error: " . $e->getMessage());
|
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
@@ -17,7 +17,8 @@ try {
|
|||||||
|
|
||||||
// ── 1. Input & Validation ──────────────────────────────────────
|
// ── 1. Input & Validation ──────────────────────────────────────
|
||||||
$rideId = filterRequest("id");
|
$rideId = filterRequest("id");
|
||||||
$driverId = filterRequest("driver_id");
|
// Force driver_id from JWT — never trust user-supplied driver_id
|
||||||
|
$driverId = $user_id;
|
||||||
$status = filterRequest("status"); // القيمة التي يرسلها التطبيق: 'accepted'
|
$status = filterRequest("status"); // القيمة التي يرسلها التطبيق: 'accepted'
|
||||||
$passengerToken = filterRequest("passengerToken");
|
$passengerToken = filterRequest("passengerToken");
|
||||||
|
|
||||||
|
|||||||
@@ -57,7 +57,9 @@ $start_location = filterRequest("start_location");
|
|||||||
$end_location = filterRequest("end_location");
|
$end_location = filterRequest("end_location");
|
||||||
$price = filterRequest("price");
|
$price = filterRequest("price");
|
||||||
$price_token = filterRequest("price_token");
|
$price_token = filterRequest("price_token");
|
||||||
$passenger_id = filterRequest("passenger_id");
|
|
||||||
|
// Force passenger_id from JWT — never trust user-supplied passenger_id
|
||||||
|
$passenger_id = $user_id;
|
||||||
$driver_id = filterRequest("driver_id") ?: 0;
|
$driver_id = filterRequest("driver_id") ?: 0;
|
||||||
$status = filterRequest("status");
|
$status = filterRequest("status");
|
||||||
$price_for_driver = filterRequest("price_for_driver");
|
$price_for_driver = filterRequest("price_for_driver");
|
||||||
|
|||||||
@@ -34,7 +34,8 @@ define('WALLET_PAYMENT_URL', 'https://walletintaleq.intaleq.xyz/v1/main/ride/pay
|
|||||||
// 1. Receive Raw Parameters (NO price from client)
|
// 1. Receive Raw Parameters (NO price from client)
|
||||||
// ============================================================
|
// ============================================================
|
||||||
$rideId = filterRequest("rideId");
|
$rideId = filterRequest("rideId");
|
||||||
$driver_id = filterRequest("driver_id");
|
// Force driver_id from JWT — never trust user-supplied driver_id
|
||||||
|
$driver_id = $user_id;
|
||||||
$passengerId = filterRequest("passengerId");
|
$passengerId = filterRequest("passengerId");
|
||||||
$newStatus = filterRequest("status"); // Expected: "Finished"
|
$newStatus = filterRequest("status"); // Expected: "Finished"
|
||||||
$actualDistance = filterRequest("actualDistance");
|
$actualDistance = filterRequest("actualDistance");
|
||||||
|
|||||||
@@ -25,12 +25,13 @@ try {
|
|||||||
$limiter = new RateLimiter($redis);
|
$limiter = new RateLimiter($redis);
|
||||||
$limiter->enforce(RateLimiter::identifier($user_id ?? null), 'upload');
|
$limiter->enforce(RateLimiter::identifier($user_id ?? null), 'upload');
|
||||||
|
|
||||||
$driverID = filterRequest("driverID");
|
// Force driverID from JWT — never trust user-supplied driverID
|
||||||
uploadLog("📥 Received driverID: $driverID");
|
$driverID = $user_id;
|
||||||
|
uploadLog("📥 Using JWT driverID: $driverID");
|
||||||
|
|
||||||
if (empty($driverID)) {
|
if (empty($driverID)) {
|
||||||
uploadLog("❌ Driver ID is missing.", 'ERROR');
|
uploadLog("❌ Driver ID from JWT is missing.", 'ERROR');
|
||||||
jsonError('Driver ID is required.', 400);
|
jsonError('Authentication required.', 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. استخدام دالة الرفع الآمنة (MIME check, random name, 5MB limit)
|
// 2. استخدام دالة الرفع الآمنة (MIME check, random name, 5MB limit)
|
||||||
@@ -47,8 +48,9 @@ try {
|
|||||||
uploadLog("✅ File moved successfully to: " . $uploadResult['path']);
|
uploadLog("✅ File moved successfully to: " . $uploadResult['path']);
|
||||||
|
|
||||||
// 3. تحديث قاعدة البيانات ديناميكياً
|
// 3. تحديث قاعدة البيانات ديناميكياً
|
||||||
$host = $_SERVER['HTTP_HOST'] ?? 'api.siromove.com';
|
// Use configured domain instead of Host header to prevent host header injection
|
||||||
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? "https" : "http";
|
$host = getenv('APP_DOMAIN') ?: 'api.siromove.com';
|
||||||
|
$protocol = 'https';
|
||||||
$linkImage = "$protocol://$host/siro/portrate_captain_image/" . $new_filename;
|
$linkImage = "$protocol://$host/siro/portrate_captain_image/" . $new_filename;
|
||||||
|
|
||||||
// تأكد من أن الاتصال قادم من connect.php أو اجلبه
|
// تأكد من أن الاتصال قادم من connect.php أو اجلبه
|
||||||
|
|||||||
Reference in New Issue
Block a user