شرح API Request Signing لتعزيز حماية API الخاص بك .

يقوم API Request Signing بحماية API الخاص بك من اي استخدام غير مخول له او الضرر به .

1337r00tمنذ 4 سنوات

* السلام عليكم ورحمة الله وبركاته *

------------------

الحمد لله على جميع نِعمه علينا ما علمنا منها وما لم نعلم حمداً والصلاة والسلام على نبينا محمد اشرف الخلق والمرسلين, اما بعد :-

--------------------

# مقدمة :-

عندما تركن سيارتك هل تأخذ مفاتيح سيارتك معك او لا ؟؟ عندما تترك المفاتيح يستطيع السارق ان يسرق السيارة ويستخدمها لأي هدف يريده !..

هذا مايحدث لAPI الخاص بك عندما لاتستخدم API Request Signing, يستطيع المهاجم ان يستخدم API الخاص بك اللذي ممكن ان يكون او يحتوي على (Private API) ونأخذ مثال : لنقل ان لديك تطبيق تسترزق منه انت, وظيفته يستعلم عن الوظائف المتاحة في مدينة الشخص ! قام شخص اخر بعمل Sniffing لتطبيقك وحصل على API endpoint اللذي يستعلم عن الوظائف ويقوم هو بصنع تطبيق مثلك لكنه هزم تطبيقك بتصميمه مثلا ولكن المعلومات كلها من API الخاصة بك ! اي يعني هذا الشخص سرق أهم ركيزة من ركائز نجاح التطبيقات منك وهي البيانات ! وهذا مجرد سيناريو واحد من عدة سيناريوهات قد يفعلها المهاجم .

سوف يعتمد شرحنا على خوارزمية HMAC اللتي تعتبر Hashing, لامانع ان تستخدم التشفير مثل AES او اذا تريد أستخدام JWT  لامانع  لايوجد اي حصر, المهم فهم الفكرة من Request Signing .

-----------------------

# من ("ممكن") أن يستخدم Request Signing :-

يوجد (Nonce || Signature) OAuth2  لكن للأسف مع ظهور مواقع Online ومكتبات تحاكي OAuth2 مع HTTP Requests مثل requests_oauthlib اصبحت غير كافية بالشكل المطلوب انصح باللجوء للطرق اليدوية هي أكثر ماتجعل المهاجم يتعثر في محاولة الهجوم او السرقة .

----------------------

# شرح تقني للAPI Request Signing مع Demo :-

برمجة التطبيق سوف تعتمد على Java (Android Studio) .

برمجة API  سوف تعتمد على PHP .

تنبية : تستطيع استخدام ماتتقنه من  اللغات والمنصات واطارات العمل .

عندما نقوم ببرمجة تطبيقاتنا مع API ونقوم بنقر أي شيء في التطبيق مثلا تقوم مكتبات HTTP بأرسال Request للAPI :-

GET http://1337r00t.me/api/ HTTP/1.1
Params: {"timestamp":"1564405537"}
User-Agent: Dalvik/2.1.0 (Linux; U; Android 5.0.2; Android SDK built for x86 Build/LSY66K)
Host: 1337r00t.me
Connection: Keep-Alive

وهذا البراميتر اللي ارسله المستخدم للسيرفر (API) بأستخدام Params header (ليس Header أفتراضي, انا من وضعته بشكل يدوي) :-

{"timestamp":"1564405537"}

يجب على المبرمج حتى يقوم بعمل API Request Signing يجعل تطبيقه (Java) يقوم بتطبيق خوارزمية HMAC على البراميتر :-

String Parameters = "{\"timestamp\":\""+System.currentTimeMillis() / 1000L+"\"}"; // Parameters
//////////////////////////////////
// HMAC algorithm with Base64
SecretKeySpec key = new SecretKeySpec(("ThisIsMyKey123456PleaseMakeITStrong").getBytes("UTF-8"), "HmacSHA1"); // Set Key
Mac mac = Mac.getInstance("HmacSHA1");
mac.init(key);
String radata = Base64.encodeToString(mac.doFinal(Parameters.getBytes("UTF-8")), Base64.DEFAULT); // HMAC-over-Base64
//////////////////////////////////

تنويه : تم أستخدام SHA1 و "ThisIsMyKey123456PleaseMakeITStrong" هو المفتاح قم بتغييره لأي مفتاح تريد (وأجعله صعب التخمين)

ويجب عليك الآن ان تقوم

<?php
# https://www.php.net/manual/en/reserved.variables.server.php
$signed_params = $_SERVER['HTTP_PARAMS']; // 'Params' Request Header
$signature = base64_encode(hash_hmac("sha1",$signed_params,"ThisIsMyKey123456PleaseMakeITStrong",true)); // HMAC-over-Base64
# https://www.php.net/manual/en/function.hash-hmac.php#100351
?>

والآن نذهب للتطبيق ونستخدم HttpURLConnection لأرسال Requests الى API (تستطيع ان تستخدم مايحلو لك لست ملزما بأستخدام HttpURLConnection )

ويجب اضافة Request Header مثلا نسميه Signed لنضع قيمة متغير radata له

//////////////////////////////////
// Send GET request
URL url = new URL("http://1337r00t.me/api/");
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
connection.setRequestMethod("GET"); // Method Request
connection.setRequestProperty("Params", Parameters); // Param Request Header
///////////////////////////////////////////////////////////////////////////
connection.setRequestProperty("Signed", radata); // Param Request Header
///////////////////////////////////////////////////////////////////////////
connection.getInputStream(); // Send request
//////////////////////////////////

اذا تبقى ان نكتب كود يتحقق من صحة تطابق Params و Signed في API :-

<?php
$signed_params_from_app = $_SERVER['HTTP_SIGNED']; // 'Signed' Request Header
$plain_params = $_SERVER['HTTP_PARAMS']; // 'Params' Request Header
$signed_params_from_api = base64_encode(hash_hmac('sha1',$plain_params,"ThisIsMyKey123456PleaseMakeITStrong",true));
if($signed_params_from_api == $signed_params_from_app){
	echo json_encode(array('output'=>'Correct Request :)'));
	//////////////////////////
	// YOUR API CODE HERE :)
}else{
	echo json_encode(array('output'=>'Incorrect Request :('));
	exit(http_response_code(401));
}
?>

وهكذا عندما يضغط المستخدم اي زر سوف يرسل التطبيق Request الى API :-

GET http://1337r00t.me/api/ HTTP/1.1
Params: {"timestamp":"1564408016"}
Signed: QOdi5JGOlVAj5KG96f4otkIC8e8=
User-Agent: Dalvik/2.1.0 (Linux; U; Android 5.0.2; Android SDK built for x86 Build/LSY66K)
Host: 1337r00t.me
Connection: Keep-Alive
Accept-Encoding: gzip

الآن عندما يرسله يقوم السيرفر بالتحقق من صحة الطلب اذا كان صحيحا يرد :-

{"output":"Correct Request :)"}

واذا حاول العبث مع Parameters سوف يرد له السيرفر :-

{"output":"Incorrect Request :("}

 

بعض المبرمحين يقومون بحظر IP فور اكتشاف أي محاولة تلاعب مع API لأي غرض هجوم او سرقة او استخدام غير مخول له .

لاتقلقوا سوف ارفع المشروع على GitHub الخاص بي لتستطيعوا تجربته وعمل Sniffing للتطبيق والفهم بشكل أكثر :-

مشروع Demo :

https://github.com/1337r00t/API-Request-Signing

تجربة Demo :

https://www.youtube.com/watch?v=XVUS_8xNFKM&feature=youtu.be

 

-------------

# ملاحظات وأجوبة على بعض الأسئلة المتوقعة :-

ملاحظات :-

  • يجب عليك استخدام HTTPS وليس HTTP (تم استخدام في الشرح HTTP لتسهيل عملية Capture Packet)
  • يجب أن تدرك ان كل شيء ممكن تخطيه وخصوصا اللذي شرحتها ممكن تخطيها بسهولة عن طريق الهندسة العكسية
  • يجب أن تكون لديك خلفية عن HTTP Packets وهنا شرح لصديقي صالح على تويتر قد ينفعك .

أسئلة :-

  1. هل هناك أساليب اصعب في API Request Signing ؟ أكيد, وتوجد أساليب جدا جدا معقدة مثل سناب شات تستخدم Native Code مما يجعل صعب جدا جدا جدا عملية الهندسة العكسية .
  2. هل يجب فقط استخدم HEADERS في التحقق ؟ طبعا لا, تستطيع الأعتماد على POST Data او GET Data او مايحلو لك لست محصورا على شيء .
  3. هل أستطيع استخدم API Request Signing  في تطبيقات IOS ؟ بالطبع .
  4. هل تأثيره مقصور على السرقة ؟ لا, تأثيره ممكن يصل الى العثور على ثغرات IDOR وماخفي كان أعظم .

-----------------

والسلام خير ختام

1337r00t | BlackFoxs Inc

كلمات دليلية: request signing
3
إعجاب
3681
مشاهدات
0
مشاركة
1
متابع

التعليقات (0)

لايوجد لديك حساب في عالم البرمجة؟

تحب تنضم لعالم البرمجة؟ وتنشئ عالمك الخاص، تنشر المقالات، الدورات، تشارك المبرمجين وتساعد الآخرين، اشترك الآن بخطوات يسيرة !