سؤال

لا تحتاج إلى تخزين معلومات حساسة (متماثل مفتاح التشفير الذي أريد أن تبقي الخاص) في C++ التطبيق.نهج بسيط هو أن تفعل هذا:

std::string myKey = "mysupersupersecretpasswordthatyouwillneverguess";

ومع ذلك, تشغيل التطبيق من خلال strings عملية (أو أي الأخرى التي تستخرج من سلاسل من ثنائي التطبيق) سوف تكشف السلسلة أعلاه.

ما هي التقنيات التي يجب استخدامها لحجب مثل هذه البيانات الحساسة?

تحرير:

حسنا, لذلك حد كبير كل من قلت "القابلة للتنفيذ الخاص بك يمكن أن يكون عكس هندستها" - بالطبع!هذه الحيوانات الأليفة غيظ لي, لذلك أنا ذاهب إلى خرف قليلا هنا:

لماذا هو أن 99 ٪ (موافق ، لذلك ربما أبالغ قليلا) من ذات الأسئلة في هذا الموقع يتم الرد مع سيل "لا يوجد ممكن طريقة لخلق آمنة تماما البرنامج" - أنه ليس من المفيد الإجابة!الأمن هو مقياس متدرج بين مثالية الاستخدام ولا أمن في الأمن مثالي ولكن لا قابليتها للاستخدام في الأخرى.

وهذه النقطة هي أن تختار موقعك على أن انزلاق الجدول اعتمادا على ما كنت تحاول القيام به والبيئة التي الخاص بك سيتم تشغيل البرمجيات. أنا لا أكتب التطبيق على منشأة عسكرية ، أنا أكتب التطبيق على أجهزة الكمبيوتر المنزلية.أنا بحاجة إلى تشفير البيانات عبر شبكة الاتصال غير موثوق به مع ما قبل المعروفة مفتاح التشفير.في هذه الحالات "الأمن من خلال الغموض" هو على الارجح جيدة بما فيه الكفاية!بالتأكيد شخص ما مع ما يكفي من الوقت والطاقة والمهارة يمكن أن الهندسة العكسية الثنائية و العثور على كلمة السر ، ولكن خمن ماذا ؟ أنا لا أهتم:

الوقت الذي يستغرقه لي لتنفيذ أرفع تأمين النظام هو أكثر تكلفة من الخسائر في المبيعات بسبب تصدع إصدارات (وليس أن أنا في الحقيقة بيع هذا, ولكن يمكنك الحصول على وجهة نظري).هذه السماء الزرقاء "دعونا نفعل ذلك المطلق أفضل طريقة ممكنة" الاتجاه في برمجة جديدة بين المبرمجين هو أحمق على أقل تقدير.

أشكركم على أخذ الوقت للإجابة على هذا السؤال - كانت مفيدة للغاية.للأسف لا أستطيع تقبل سوى إجابة واحدة ، لكن قد يصل صوت كل مفيد إجابات.

هل كانت مفيدة؟

المحلول

في الأساس, أي شخص لديه إمكانية الوصول إلى البرنامج الخاص بك و مصحح يمكن و سوف العثور على المفتاح في التطبيق إذا كانوا يريدون.

ولكن إذا كنت ترغب فقط تأكد من المفتاح لا تظهر عند التشغيل strings على الثنائية الخاصة بك ، يمكنك على سبيل المثال تأكد من أن المفتاح ليس في للطباعة النطاق.

حجب المفتاح مع XOR

فعلى سبيل المثال ، يمكنك استخدام XOR تقسيم الرئيسية في اثنين صفائف بايت:

key = key1 XOR key2

إذا قمت بإنشاء key1 مع نفس بايت طول key يمكنك استخدام (تماما) عشوائية بايت القيم ومن ثم حساب key2:

key1[n] = crypto_grade_random_number(0..255)
key2[n] = key[n] XOR key1[n]

يمكنك القيام بذلك في بناء البيئة ، ومن ثم تخزين فقط ، key1و key2 في التطبيق الخاص بك.

حماية الخاص بك الثنائية

وثمة نهج آخر هو استخدام أداة لحماية الثنائية.على سبيل المثال, هناك العديد من الأدوات التي يمكن أن تأكد الثنائية هو غموض و يبدأ الجهاز الظاهري أنه يعمل على.وهذا يجعل من الصعب(إيه) إلى تصحيح ، و هو أيضا convential طريقة كثير من الصف التجارية تطبيقات آمنة (أيضا للأسف الخبيثة) محمي.

واحدة من رئيس الوزراء أدوات Themida, التي تقوم بعمل ممتاز من حماية الثنائيات.وغالبا ما تستخدم من قبل المعروفة البرامج مثل سبوتيفي ، حماية ضد الهندسة العكسية.لديها ميزات لمنع التصحيح في برامج مثل OllyDbg و إيدا برو.

هناك أيضا قائمة أكبر ربما قديمة نوعا ما ، أدوات لحماية الثنائية.
بعضها مجانا.

كلمة مطابقة

شخص ما هنا تناقش تجزئة كلمة المرور+الملح.

إذا كنت بحاجة لتخزين مفتاح المباراة ضد نوع من قدم المستخدم كلمة المرور, يجب عليك استخدام واحدة-طريقة تجزئة الوظيفة ويفضل من خلال الجمع بين اسم المستخدم وكلمة المرور الملح.المشكلة مع هذا ، على الرغم من أن التطبيق الخاص بك يجب أن تعرف الملح أن تكون قادرة على القيام اتجاه واحد ومقارنة الناتج التجزئة.لذلك كنت لا تزال بحاجة إلى تخزين الملح في مكان ما في التطبيق الخاص بك.ولكن ، كما @إدوارد نقطة في التعليقات أدناه ، وهذا سوف حماية فعالة ضد هجوم القاموس باستخدام هـ.g, قوس قزح الجداول.

أخيرا, يمكنك استخدام مزيج من جميع التقنيات المذكورة أعلاه.

نصائح أخرى

أولا وقبل كل شيء ، أدرك أنه لا يوجد شيء يمكنك القيام بذلك سوف تتوقف بما فيه الكفاية تحديد القراصنة, و هناك الكثير من المحيطين.حماية على كل لعبة وحدة حول تصدع في نهاية المطاف ، لذلك هذا ليس سوى حل مؤقت.

هناك 4 أشياء يمكنك القيام بذلك سوف تزيد من فرص البقاء خفية لفترة من الوقت.

1) إخفاء عناصر السلسلة في بعض الطريق-شيء واضح مثل xoring ( فإن ^ المشغل) السلسلة مع سلسلة أخرى سوف تكون جيدة بما يكفي لجعل سلسلة من المستحيل البحث عن.

2) تقسيم السلسلة إلى قطع-تقسيم سلسلة pop بت في غريب اسمه أساليب غريبة وحدات.لا تجعل من السهل البحث عن طريق إيجاد طريقة مع السلسلة في ذلك.بالطبع بعض طريقة دعوة جميع هذه القطع, لكنه لا يزال يجعل الأمر أصعب قليلا.

3) لا من أي وقت مضى بناء السلسلة في الذاكرة-معظم المتسللين استخدام الأدوات التي تتيح لهم رؤية السلسلة في الذاكرة بعد المشفرة ذلك.إذا كان من الممكن تجنب هذا.على سبيل المثال إذا كنت تقوم بإرسال المفتاح من على خادم ، وإرساله حرف كل سلسلة في جميع أنحاء العالم.بالطبع, إذا كنت تستخدم الأمر من شيء مثل RSA ترميز ثم هذا هو اصعب.

4) القيام مخصص خوارزمية -- على رأس كل هذا ، إضافة لمسة فريدة من نوعها أو اثنين.ربما فقط إضافة 1 إلى كل ما ينتج أو القيام بأي التشفير مرتين أو إضافة السكر.هذا يجعل الأمر أصعب قليلا بالنسبة القراصنة الذين يعرف ما الذي تبحث عنه عند شخص ما يستخدم ، على سبيل المثال ، الفانيليا تجزئة md5 أو التشفير RSA.

قبل كل شيء تأكد من أنها ليست هامة جدا عند (ويكون ذلك عندما إذا كنت يصبح تطبيق شعبية بما فيه الكفاية) المفتاح الخاص بك هو اكتشافها!

استراتيجية لقد استعملت في الماضي لإنشاء مجموعة على ما يبدو-أحرف عشوائية.كنت في البداية إدراج ، ثم حدد موقع خاص بك الشخصيات مع جبري العملية حيث كل خطوة من 0 إلى ن سوف تسفر عن عدد < حجم المصفوفة التي تحتوي على التالي شار في غموض سلسلة.(هذا الجواب هو شعور غموض الآن!)

على سبيل المثال:

بالنظر إلى مجموعة من حرف (أرقام و شرطات هي للإشارة فقط)

0123456789
----------
ALFHNFELKD
LKFKFLEHGT
FLKRKLFRFK
FJFJJFJ!JL

و المعادلة التي الستة الأولى من النتائج هي:3, 6, 7, 10, 21, 47

تسفر عن كلمة "مرحبا" من المصفوفة أعلاه.

أنا أتفق مع @لعبة الداما القابلة للتنفيذ الخاص بك يمكن أن تكون عكسية.

أفضل طريقة لخلق بشكل حيوي ، على سبيل المثال:

std::string myKey = part1() + part2() + ... + partN();

لقد خلق بسيطة التشفير أداة سلاسل, يمكن أن تولد تلقائيا تشفير سلاسل لديها عدد قليل من الخيارات الإضافية إلى فعل ذلك بعض الأمثلة:

سلسلة عالمي متغير:

// myKey = "mysupersupersecretpasswordthatyouwillneverguess";
unsigned char myKey[48] = { 0xCF, 0x34, 0xF8, 0x5F, 0x5C, 0x3D, 0x22, 0x13, 0xB4, 0xF3, 0x63, 0x7E, 0x6B, 0x34, 0x01, 0xB7, 0xDB, 0x89, 0x9A, 0xB5, 0x1B, 0x22, 0xD4, 0x29, 0xE6, 0x7C, 0x43, 0x0B, 0x27, 0x00, 0x91, 0x5F, 0x14, 0x39, 0xED, 0x74, 0x7D, 0x4B, 0x22, 0x04, 0x48, 0x49, 0xF1, 0x88, 0xBE, 0x29, 0x1F, 0x27 };

myKey[30] -= 0x18;
myKey[39] -= 0x8E;
myKey[3] += 0x16;
myKey[1] += 0x45;
myKey[0] ^= 0xA2;
myKey[24] += 0x8C;
myKey[44] ^= 0xDB;
myKey[15] ^= 0xC5;
myKey[7] += 0x60;
myKey[27] ^= 0x63;
myKey[37] += 0x23;
myKey[2] ^= 0x8B;
myKey[25] ^= 0x18;
myKey[12] ^= 0x18;
myKey[14] ^= 0x62;
myKey[11] ^= 0x0C;
myKey[13] += 0x31;
myKey[6] -= 0xB0;
myKey[22] ^= 0xA3;
myKey[43] += 0xED;
myKey[29] -= 0x8C;
myKey[38] ^= 0x47;
myKey[19] -= 0x54;
myKey[33] -= 0xC2;
myKey[40] += 0x1D;
myKey[20] -= 0xA8;
myKey[34] ^= 0x84;
myKey[8] += 0xC1;
myKey[28] -= 0xC6;
myKey[18] -= 0x2A;
myKey[17] -= 0x15;
myKey[4] ^= 0x2C;
myKey[9] -= 0x83;
myKey[26] += 0x31;
myKey[10] ^= 0x06;
myKey[16] += 0x8A;
myKey[42] += 0x76;
myKey[5] ^= 0x58;
myKey[23] ^= 0x46;
myKey[32] += 0x61;
myKey[41] ^= 0x3B;
myKey[31] ^= 0x30;
myKey[46] ^= 0x6C;
myKey[35] -= 0x08;
myKey[36] ^= 0x11;
myKey[45] -= 0xB6;
myKey[21] += 0x51;
myKey[47] += 0xD9;

كما unicode سلسلة مع فك التشفير الحلقة:

// myKey = "mysupersupersecretpasswordthatyouwillneverguess";
wchar_t myKey[48];

myKey[21] = 0x00A6;
myKey[10] = 0x00B0;
myKey[29] = 0x00A1;
myKey[22] = 0x00A2;
myKey[19] = 0x00B4;
myKey[33] = 0x00A2;
myKey[0] = 0x00B8;
myKey[32] = 0x00A0;
myKey[16] = 0x00B0;
myKey[40] = 0x00B0;
myKey[4] = 0x00A5;
myKey[26] = 0x00A1;
myKey[18] = 0x00A5;
myKey[17] = 0x00A1;
myKey[8] = 0x00A0;
myKey[36] = 0x00B9;
myKey[34] = 0x00BC;
myKey[44] = 0x00B0;
myKey[30] = 0x00AC;
myKey[23] = 0x00BA;
myKey[35] = 0x00B9;
myKey[25] = 0x00B1;
myKey[6] = 0x00A7;
myKey[27] = 0x00BD;
myKey[45] = 0x00A6;
myKey[3] = 0x00A0;
myKey[28] = 0x00B4;
myKey[14] = 0x00B6;
myKey[7] = 0x00A6;
myKey[11] = 0x00A7;
myKey[13] = 0x00B0;
myKey[39] = 0x00A3;
myKey[9] = 0x00A5;
myKey[2] = 0x00A6;
myKey[24] = 0x00A7;
myKey[46] = 0x00A6;
myKey[43] = 0x00A0;
myKey[37] = 0x00BB;
myKey[41] = 0x00A7;
myKey[15] = 0x00A7;
myKey[31] = 0x00BA;
myKey[1] = 0x00AC;
myKey[47] = 0x00D5;
myKey[20] = 0x00A6;
myKey[5] = 0x00B0;
myKey[38] = 0x00B0;
myKey[42] = 0x00B2;
myKey[12] = 0x00A6;

for (unsigned int fngdouk = 0; fngdouk < 48; fngdouk++) myKey[fngdouk] ^= 0x00D5;

سلسلة عالمي متغير:

// myKey = "mysupersupersecretpasswordthatyouwillneverguess";
unsigned char myKey[48] = { 0xAF, 0xBB, 0xB5, 0xB7, 0xB2, 0xA7, 0xB4, 0xB5, 0xB7, 0xB2, 0xA7, 0xB4, 0xB5, 0xA7, 0xA5, 0xB4, 0xA7, 0xB6, 0xB2, 0xA3, 0xB5, 0xB5, 0xB9, 0xB1, 0xB4, 0xA6, 0xB6, 0xAA, 0xA3, 0xB6, 0xBB, 0xB1, 0xB7, 0xB9, 0xAB, 0xAE, 0xAE, 0xB0, 0xA7, 0xB8, 0xA7, 0xB4, 0xA9, 0xB7, 0xA7, 0xB5, 0xB5, 0x42 };

for (unsigned int dzxykdo = 0; dzxykdo < 48; dzxykdo++) myKey[dzxykdo] -= 0x42;

بالطبع تخزين البيانات الخاصة في البرامج التي يتم شحنها إلى المستخدم هو دائما خطر.أي بما فيه الكفاية المتعلمين (مخصصة) مهندس يمكن عكس مهندس البيانات.

أن يقال, يمكنك غالبا ما تجعل الأشياء آمنة بما فيه الكفاية من خلال رفع الحواجز التي الناس بحاجة إلى التغلب على الكشف عن البيانات الخاصة بك.وهذا عادة ما يكون حلا وسطا جيدا.

في الحالة الخاصة بك ، يمكنك فوضى سلاسل الخاص بك غير قابل للطباعة البيانات ، ومن ثم فك هذا في وقت التشغيل باستخدام بسيط وظيفة مساعد, مثل هذا:

void unscramble( char *s )
{
    for ( char *str = s + 1; *str != 0; str += 2 ) {
        *s++ = *str;
    }
    *s = '\0';
}

void f()
{
    char privateStr[] = "\001H\002e\003l\004l\005o";
    unscramble( privateStr ); // privateStr is 'Hello' now.

    string s = privateStr;
    // ...
}

يعتمد إلى حد ما على ما كنت تحاول حماية كما joshperry نقطة.من تجربة, وأود أن أقول أنه إذا كان جزء من نظام الترخيص لحماية البرمجيات الخاصة بك ثم لا يكلف نفسه عناء.وسوف eventially هندسة عكسية عليه.ببساطة استخدام بسيط الشفرات مثل ROT-13 لحمايتها من هجمات بسيطة (خط تشغيل سلاسل أكثر من ذلك).إذا كان لتأمين مستخدمي البيانات الحساسة سيكون التساؤل عما إذا كان حماية البيانات مع مفتاح خاص المخزنة محليا هو خطوة حكيمة.مرة أخرى أنه يأتي إلى أسفل إلى ما تحاول حماية.

تحرير:إذا كنت تنوي القيام بذلك ثم مزيج من التقنيات التي كريس يشير سوف تكون أفضل بكثير من rot13.

كما قلت من قبل, لا يوجد طريقة تماما حماية سلسلة الخاص بك.ولكن هناك طرق لحماية wis معقول السلامة.

عندما كان علي أن أفعل هذا, أنا وضعت بعض الأبرياء تبحث السلسلة إلى رمز (إشعار حقوق الطبع والنشر ، على سبيل المثال ، أو بعض مزورة المستخدم موجه أو أي شيء آخر لن تغير من قبل شخص تحديد علاقة لها رمز), تشفير أن استخدام نفسها على أنها مفتاح ، المجزأة التي (إضافة بعض الملح) ، واستخدم نتيجة مفتاح تشفير ما أردت في الحقيقة أن تشفير.

طبعا هذا يمكن أن يكون اخترق, ولكن الأمر يستغرق وقتا تحديد القراصنة للقيام بذلك.

بدلا من تخزين المفتاح الخاص في القابلة للتنفيذ الخاص بك, قد ترغب في أن تطلب من المستخدم وتخزينها طريق خارجي كلمة مدير, تشبه إلى نظام التشغيل Mac OS X Keychain Access.

إذا كنت على ويندوز المستخدم DPAPI ، http://msdn.microsoft.com/en-us/library/ms995355.aspx

السابقة وقال آخر إذا كنت على ماك استخدام المفاتيح.

أساسا كل هذه الأفكار لطيف حول كيفية تخزين المفتاح الخاص داخل الثنائية بما فيه الكفاية الفقراء من منظور أمني أنه يجب عدم القيام بها.أي شخص الحصول على المفتاح الخاص هو صفقة كبيرة ، لا يبقيه داخل البرنامج الخاص بك.اعتمادا على كيفية استيراد التطبيق الخاص بك هو أنك يمكن أن تبقي مفاتيح خاصة على بطاقة ذكية على جهاز التحكم عن بعد جهاز الكمبيوتر الخاص بك رمز يتحدث أو يمكنك أن تفعل ما يفعله معظم الناس والاحتفاظ بها في مكان أمن جدا على الكمبيوتر المحلي ("مفتاح المخزن" الذي هو نوع من مثل غريب آمنة التسجيل) محمية بموجب أذونات كل قوة نظام التشغيل الخاص بك.

هذا هو حل المشكلة و الجواب ليس للحفاظ على المفتاح داخل البرنامج :)

محاولة هذا.المصدر مدونة تشرح كيفية تشفير وفك تشفير على الطاير كافة السلاسل في Visual Studio c++ المشروع.

طريقة واحدة لقد حاولت مؤخرا هو:

  1. تأخذ تجزئة (SHA256) من البيانات الخاصة ثم نشر في المدونة part1
  2. تأخذ XOR البيانات الخاصة و البعثرة و نشر في المدونة part2
  3. تعبئة البيانات:لا تقم بتخزين كما شار str [] ، ولكن نشر في وقت التشغيل باستخدام التعيين تعليمات (كما هو موضح في الكلية أدناه)
  4. الآن توليد البيانات الخاصة على المدى الوقت من خلال اتخاذ XOR من part1 و part2
  5. خطوة إضافية:حساب تجزئة البيانات التي تم إنشاؤها ومقارنتها مع part1.فإنه سيتم التحقق من سلامة البيانات الخاصة.

ماكرو تعبئة البيانات:

ولنفترض البيانات الخاصة هو 4 بايت.يمكننا تعريف ماكرو لذلك الذي يحفظ البيانات مع تعليمات مهمة في ترتيب عشوائي.

#define POPULATE_DATA(str, i0, i1, i2, i3)\
{\
    char *p = str;\
    p[3] = i3;\
    p[2] = i2;\
    p[0] = i0;\
    p[1] = i1;\
}

الآن استخدام هذا الماكرو في التعليمات البرمجية التي تحتاج إلى حفظ part1 و part2, على النحو التالي:

char part1[4] = {0};
char part2[4] = {0};
POPULATE_DATA(part1, 1, 2, 3, 4); 
POPULATE_DATA(part2, 5, 6, 7, 8);

السياق يتوقف ولكن يمكن فقط تخزين تجزئة الرئيسية بالإضافة إلى الملح (سلسلة ثابتة وسهلة غامضة).

ثم عندما (إذا) يدخل المستخدم الرئيسية ، الملح, حساب تجزئة ومقارنة.

على الملح ربما لا لزوم لها في هذه الحالة ، فإنه يتوقف على القوة الغاشمة القاموس الهجوم إذا كانت التجزئة يمكن أن تكون معزولة (بحث جوجل أيضا تعرف إلى العمل).

القراصنة لا يزال فقط لإدراج أحزاب اللقاء المشترك التعليمات في مكان لتجاوز الكثير, ولكن هذا هو أكثر تعقيدا من نص بسيط البحث.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top