شارك المقالة

شرح Hybrid Encryption في Flutter باستخدام RSA وAES لتأمين البيانات

عندما نتعامل مع تطبيقات حساسة مثل تطبيقات FinTech أو المحافظ الرقمية أو أنظمة الدفع، فإن حماية البيانات أثناء انتقالها بين تطبيق Flutter والسيرفر تصبح من أهم أجزاء التصميم الأمني.

من الأفكار المهمة في هذا المجال مفهوم Hybrid Encryption، وهو أسلوب يجمع بين نوعين مختلفين من التشفير: Asymmetric Encryption مثل RSA، وSymmetric Encryption مثل AES.

الفكرة ببساطة هي أن نستخدم RSA في عملية تبادل مفتاح التشفير، ثم نستخدم AES بعد ذلك لتشفير البيانات الفعلية بين التطبيق والسيرفر، لأن AES أكثر كفاءة في التعامل مع كميات كبيرة من البيانات.

ما هو Hybrid Encryption؟

Hybrid Encryption أو التشفير الهجين هو أسلوب يجمع بين التشفير غير المتماثل Asymmetric Encryption والتشفير المتماثل Symmetric Encryption.

في المثال الذي سنشرحه، سنستخدم:

  • RSA لتبادل مفتاح AES بشكل آمن.
  • AES لتشفير البيانات الفعلية.

والسبب في الجمع بينهما هو أن RSA مناسب لحماية وتبادل الأسرار الصغيرة، بينما AES مصمم ليكون سريعًا عند تشفير البيانات الكبيرة والمتكررة.

الفكرة من البداية

السيرفر يقوم بإنشاء زوج من المفاتيح:

  • Public Key: يمكن إرساله إلى التطبيق ولا يمثل سرًا بحد ذاته.
  • Private Key: يجب أن يبقى داخل السيرفر ولا يتم إرساله إلى التطبيق.

بعد ذلك يبدأ التطبيق في إنشاء مفتاح تشفير متماثل جديد يسمى AES Key.

بدلًا من إرسال هذا المفتاح مباشرة عبر الشبكة، يقوم التطبيق بتشفيره باستخدام RSA Public Key الذي حصل عليه من السيرفر.

السيرفر يستقبل المفتاح المشفر، ويستخدم RSA Private Key لفك تشفيره والحصول على نفس AES Key.

الآن أصبح التطبيق والسيرفر يمتلكان نفس مفتاح AES، ويمكن استخدامه لتشفير البيانات التي سيتم إرسالها لاحقًا.

شكل العملية بالكامل

يمكن تبسيط العملية بالشكل التالي:


                SERVER
                  │
       Generate RSA Key Pair
                  │
        ┌─────────┴─────────┐
        │                   │
   Public Key          Private Key
        │                   │
        │              يبقى داخل السيرفر
        │
        ▼
     FLUTTER
        │
   Generate AES Key
        │
        ▼
Encrypt AES Key using
RSA Public Key
        │
        ▼
Send Encrypted AES Key
        │
        ▼
      SERVER
        │
Decrypt using RSA Private Key
        │
        ▼
     AES Key
        │
        ├───────────────┐
        │               │
        ▼               ▼
 Encrypt Requests   Decrypt Responses
        │               │
        └───────┬───────┘
                │
              AES

لماذا لا نستخدم RSA لتشفير كل البيانات؟

هنا تظهر أهمية Hybrid Encryption.

RSA هو تشفير غير متماثل، ويمكن استخدامه لتشفير بيانات صغيرة، لكنه ليس الخيار المناسب لتشفير كل Request وResponse داخل التطبيق.

لذلك نستخدم RSA في مرحلة محددة فقط، وهي حماية أو تبادل المفتاح المتماثل، وبعد ذلك نعتمد على AES لتشفير البيانات.

بمعنى آخر:


RSA
│
└── حماية AES Key

AES
│
├── Encrypt Request
├── Encrypt Response
├── Encrypt User Data
└── Encrypt Sensitive Data

الخطوة الأولى: إنشاء RSA Keys في السيرفر

السيرفر ينشئ زوجًا من المفاتيح:


Public Key
Private Key

ويقوم بإرسال الـ Public Key إلى التطبيق.

أما الـ Private Key فيظل داخل البنية الخلفية للسيرفر ولا يتم تخزينه داخل تطبيق Flutter.

الخطوة الثانية: التطبيق ينشئ AES Key

عند بدء جلسة التشفير، يقوم التطبيق بإنشاء مفتاح AES عشوائي قوي.


final aesKey = generateRandomAesKey();

المهم هنا أن المفتاح يجب أن يتم إنشاؤه باستخدام مصدر عشوائية آمن Cryptographically Secure Random وليس باستخدام Random العادي.

الخطوة الثالثة: تشفير AES Key باستخدام RSA

بعد الحصول على Public Key من السيرفر، يتم استخدامه لتشفير AES Key.


AES Key
   │
   ▼
RSA Public Key
   │
   ▼
Encrypted AES Key

ثم يتم إرسال المفتاح المشفر إلى السيرفر.

الخطوة الرابعة: السيرفر يفك تشفير AES Key

السيرفر يمتلك الـ Private Key وبالتالي يستطيع فك تشفير الـ AES Key.


Encrypted AES Key
        │
        ▼
RSA Private Key
        │
        ▼
Original AES Key

وبهذه الطريقة لا يحتاج التطبيق إلى إرسال مفتاح AES بشكل واضح عبر الشبكة.

الخطوة الخامسة: تشفير الـ Requests

بعد أن أصبح التطبيق والسيرفر يمتلكان نفس AES Key، يمكن استخدامه لتشفير البيانات.

مثلًا بدلًا من إرسال:


{
  "cardNumber": "4111111111111111",
  "amount": 250
}

يقوم التطبيق بتحويل البيانات إلى صيغة مشفرة وإرسالها إلى السيرفر.


{
  "encryptedData": "....encrypted payload....",
  "iv": "....",
  "tag": "...."
}

السيرفر يستخدم نفس مفتاح AES لإعادة البيانات إلى شكلها الأصلي.

لماذا AES-GCM مهم؟

عند تطبيق AES في نظام حقيقي، لا يكفي أن تكون البيانات مشفرة فقط؛ من المهم أيضًا التحقق من سلامة البيانات والتأكد من أنها لم يتم تعديلها أثناء النقل.

لهذا السبب يمكن استخدام نمط مثل AES-GCM الذي يوفر التشفير مع التحقق من سلامة البيانات ضمن عملية واحدة.

مكتبة PointyCastle في Dart توفر دعمًا لـ AES وGCM وكذلك RSA وOAEP. :contentReference[oaicite:1]{index=1}

مثال مبسط في Flutter

يمكن استخدام مكتبة PointyCastle عند الحاجة إلى تنفيذ هذه الخوارزميات داخل Dart.


dependencies:
  pointycastle: ^4.0.0

ثم يمكن استخدام RSA مع OAEP لتشفير المفتاح المتماثل.


import 'package:pointycastle/export.dart';

Uint8List encryptAesKey(
  RSAPublicKey publicKey,
  Uint8List aesKey,
) {
  final cipher = OAEPEncoding(RSAEngine())
    ..init(
      true,
      PublicKeyParameter<RSAPublicKey>(publicKey),
    );

  return cipher.process(aesKey);
}

وعلى السيرفر يتم استخدام RSA Private Key لفك تشفير المفتاح.


Uint8List decryptAesKey(
  RSAPrivateKey privateKey,
  Uint8List encryptedAesKey,
) {
  final cipher = OAEPEncoding(RSAEngine())
    ..init(
      false,
      PrivateKeyParameter<RSAPrivateKey>(privateKey),
    );

  return cipher.process(encryptedAesKey);
}

توثيق PointyCastle يوضح دعم RSA باستخدام OAEP للتشفير وفك التشفير، كما يوضح استخدام Public Key أثناء التشفير وPrivate Key أثناء فك التشفير. :contentReference[oaicite:2]{index=2}

كيف يتم تشفير الـ Request؟

بعد حصول التطبيق والسيرفر على AES Key، يصبح لدينا تدفق مشابه لهذا:


Flutter
   │
   │ JSON
   ▼
AES-GCM Encryption
   │
   ▼
Encrypted Payload
   │
   ▼
HTTPS
   │
   ▼
Server
   │
AES-GCM Decryption
   │
   ▼
Original JSON

ماذا يحدث عند إرسال Response؟

نفس الفكرة تعمل في الاتجاه الآخر.


Server
   │
   │ Response Data
   ▼
AES Encryption
   │
   ▼
Encrypted Response
   │
   ▼
Flutter
   │
AES Decryption
   │
   ▼
Original Response

هل نحتاج إلى AES Key واحد دائمًا؟

ليس بالضرورة.

في التصميمات الأكثر تطورًا يمكن إنشاء Session Key لكل جلسة أو استخدام آليات حديثة لتبادل المفاتيح وإدارة دورة حياة المفاتيح.

هذا يسمح بتقليل مدة استخدام المفتاح وتقليل أثر تسرب مفتاح واحد في حال حدوث مشكلة أمنية.

هل هذا يعني أننا لا نحتاج HTTPS؟

لا.

وجود Hybrid Encryption داخل التطبيق لا يعني أن HTTP أصبح آمنًا أو أنه يمكن الاستغناء عن TLS.

في التطبيقات الحقيقية، يجب أن يكون الاتصال عبر HTTPS مع شهادة TLS صحيحة.

والسبب أن TLS يوفر مجموعة كاملة من آليات حماية الاتصال، وليس مجرد تشفير البيانات فقط.

كما أن بروتوكول TLS الحديث، وخصوصًا TLS 1.3، يستخدم آليات حديثة لتبادل المفاتيح مثل (EC)DHE بدل الاعتماد على نموذج RSA القديم لتبادل مفتاح الجلسة، ثم يتم استخدام تشفير متماثل عالي الكفاءة لحماية البيانات أثناء الجلسة.

لذلك فإن المثال السابق مفيد جدًا لفهم مفهوم Hybrid Encryption، لكنه ليس وصفًا حرفيًا لما يحدث داخل كل اتصال HTTPS حديث.

متى يمكن أن يكون التشفير الإضافي مفيدًا؟

قد توجد حالات تحتاج فيها إلى طبقة تشفير إضافية داخل التطبيق نفسه، مثل:

  • حماية بيانات حساسة جدًا على مستوى الـ payload.
  • تطبيقات FinTech والأنظمة المالية.
  • أنظمة تحتوي على بيانات شخصية أو مالية شديدة الحساسية.
  • عندما يكون لديك متطلبات أمنية خاصة تتجاوز حماية قناة الاتصال.
  • عندما تريد أن تكون بعض البيانات مشفرة حتى داخل طبقات معينة من البنية الخلفية.

معلومة مهمة جدًا

لا يجب بناء نظام تشفير مخصص لمجرد أن البيانات تبدو حساسة، خصوصًا إذا كان HTTPS/TLS يغطي المتطلب الأمني بالفعل.

التشفير المخصص يضيف تعقيدًا كبيرًا في إدارة المفاتيح، وتدويرها، والتعامل مع IV / Nonce والتحقق من سلامة البيانات، ومعالجة الأخطاء، والتوافق بين Flutter والسيرفر.

لذلك يجب أن يكون لديك سبب أمني واضح قبل إضافة طبقة تشفير مخصصة فوق TLS.

أين نقوم بتخزين AES Key؟

هذه نقطة مهمة جدًا.

لا يفضل تخزين AES Key في SharedPreferences بشكل مباشر، خصوصًا إذا كان المفتاح طويل العمر.

حسب طبيعة التطبيق يمكن الاعتماد على التخزين الآمن الذي يوفره النظام، مثل:

  • Android Keystore
  • iOS Keychain
  • Secure Storage abstractions

كما يجب التفكير في مدة صلاحية المفتاح ومتى يتم تجديده أو إبطاله.

الصورة النهائية للفكرة


                 SERVER
                    │
          RSA Public / Private
                    │
          Public Key → Flutter
                    │
                    ▼
               FLUTTER
                    │
            Generate AES Key
                    │
                    ▼
        Encrypt AES Key with RSA
                    │
                    ▼
             Send to Server
                    │
                    ▼
               SERVER
                    │
       Decrypt using RSA Private Key
                    │
                    ▼
               AES Key
                    │
          ┌─────────┴─────────┐
          │                   │
          ▼                   ▼
      Flutter              Server
          │                   │
          └────── AES ────────┘
                  │
                  ▼
       Encrypt Requests
       Encrypt Responses

الخلاصة

Hybrid Encryption هو مفهوم مهم جدًا لفهم كيفية الجمع بين التشفير المتماثل وغير المتماثل.

الفكرة الأساسية هي:

  • RSA أو خوارزمية غير متماثلة مشابهة تستخدم لحماية أو تبادل سر صغير مثل مفتاح الجلسة.
  • AES يستخدم لتشفير البيانات الفعلية بكفاءة عالية.
  • HTTPS/TLS يظل خط الدفاع الأساسي لحماية الاتصال بين التطبيق والسيرفر.

وبالتالي يمكن تبسيط الفكرة في جملة واحدة:


RSA → Protect the Key
AES → Protect the Data
TLS → Protect the Connection

وهذا هو السبب في أن مفهوم Hybrid Encryption مهم جدًا لأي Flutter Developer يعمل على تطبيقات FinTech أو الأنظمة التي تتعامل مع بيانات حساسة.



PointyCastle على pub.dev

المزيد من المقالات البرمجية على Geecoders

الكود كامل


import 'dart:typed_data';

import 'package:pointycastle/export.dart';

Uint8List encryptAesKey(
  RSAPublicKey publicKey,
  Uint8List aesKey,
) {
  final cipher = OAEPEncoding(RSAEngine())
    ..init(
      true,
      PublicKeyParameter<RSAPublicKey>(publicKey),
    );

  return cipher.process(aesKey);
}

Uint8List decryptAesKey(
  RSAPrivateKey privateKey,
  Uint8List encryptedAesKey,
) {
  final cipher = OAEPEncoding(RSAEngine())
    ..init(
      false,
      PrivateKeyParameter<RSAPrivateKey>(privateKey),
    );

  return cipher.process(encryptedAesKey);
}


شاهد أيضًا
مقالات ذات صلة
🚫 مانع الإعلانات مفعل

يجب إيقاف مانع الإعلانات لاستكمال تصفح الموقع