سؤال

أحاول تحقيق الغرض من SecureString الخاص بـ .NET.من MSDN:

مثيل فئة System.String غير قابل للتغيير، وعندما لم تعد هناك حاجة إليه، لا يمكن جدولته برمجياً لجمع البيانات المهملة؛أي أن المثيل يكون للقراءة فقط بعد إنشائه ولا يمكن التنبؤ بموعد حذف المثيل من ذاكرة الكمبيوتر.وبالتالي، إذا كان كائن سلسلة يحتوي على معلومات حساسة مثل كلمة المرور أو رقم بطاقة الائتمان أو البيانات الشخصية، فهناك خطر من احتمال الكشف عن المعلومات بعد استخدامها لأن التطبيق الخاص بك لا يمكنه حذف البيانات من ذاكرة الكمبيوتر.

يشبه كائن SecureString كائن String من حيث أنه يحتوي على قيمة نصية.ومع ذلك، يتم تشفير قيمة كائن SecureString تلقائيًا، ويمكن تعديلها حتى يقوم التطبيق الخاص بك بوضع علامة عليها للقراءة فقط، ويمكن حذفها من ذاكرة الكمبيوتر إما عن طريق التطبيق الخاص بك أو أداة تجميع البيانات المهملة .NET Framework.

يتم تشفير قيمة مثيل SecureString تلقائيًا عند تهيئة المثيل أو عند تعديل القيمة.يمكن لتطبيقك أن يجعل المثيل غير قابل للتغيير ويمنع المزيد من التعديل عن طريق استدعاء الأسلوب MakeReadOnly.

هل التشفير التلقائي هو المردود الكبير؟

ولماذا لا أستطيع أن أقول فقط:

SecureString password = new SecureString("password");

بدلاً من

SecureString pass = new SecureString();
foreach (char c in "password".ToCharArray())
    pass.AppendChar(c);

ما هو جانب SecureString الذي أفتقده؟

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

المحلول

بعض أجزاء الإطار المستخدمة حاليًا SecureString:

والغرض الرئيسي هو تقليل سطح الهجوم، بدلا من القضاء عليه. SecureStrings يتم "تثبيتها" في ذاكرة الوصول العشوائي (RAM) حتى لا يقوم جامع البيانات المهملة بنقلها أو عمل نسخ منها.كما أنه يتأكد من عدم كتابة النص العادي في ملف Swap أو في عمليات التفريغ الأساسية.يشبه التشفير إلى حد كبير التشويش ولن يوقف المتسلل المصمم الذي سيكون قادرًا على العثور على الملف مفتاح متماثل تستخدم لتشفيرها وفك تشفيرها.

كما قال الآخرون، السبب الذي دفعك إلى إنشاء ملف SecureString إن كل حرف على حدة يرجع إلى الخلل الواضح الأول في القيام بخلاف ذلك:من المفترض أن لديك القيمة السرية كسلسلة عادية بالفعل، فما الفائدة؟

SecureStringتعد s هي الخطوة الأولى في حل مشكلة الدجاجة والبيضة، لذلك على الرغم من أن معظم السيناريوهات الحالية تتطلب تحويلها مرة أخرى إلى سلاسل منتظمة للاستفادة منها على الإطلاق، فإن وجودها في إطار العمل يعني الآن دعمًا أفضل لها في المستقبل - على الأقل إلى النقطة التي لا يجب أن يكون فيها برنامجك هو الحلقة الضعيفة.

نصائح أخرى

الكثير من الإجابات الرائعة؛إليك ملخص سريع لما تمت مناقشته.

قامت Microsoft بتطبيق فئة SecureString في محاولة لتوفير أمان أفضل للمعلومات الحساسة (مثل بطاقات الائتمان وكلمات المرور وما إلى ذلك).فإنه يوفر تلقائيا:

  • التشفير (في حالة مقالب الذاكرة أو التخزين المؤقت للصفحة)
  • تثبيت في الذاكرة
  • القدرة على وضع علامة للقراءة فقط (لمنع أي تعديلات أخرى)
  • البناء الآمن من خلال عدم السماح بتمرير سلسلة ثابتة

حاليًا، SecureString محدود الاستخدام ولكن نتوقع اعتمادًا أفضل في المستقبل.

بناءً على هذه المعلومات، لا ينبغي لمنشئ SecureString أن يأخذ سلسلة ويقسمها إلى مصفوفة char فحسب، حيث أن كتابة السلسلة بشكل واضح يتعارض مع غرض SecureString.

معلومات إضافية:

  • أ بريد من مدونة .NET Security تتحدث عن نفس الشيء كما تم تغطيته هنا.
  • وآخر واحدإعادة النظر فيها وذكر أداة يمكنها تفريغ محتويات securestring.

يحرر:لقد وجدت أنه من الصعب اختيار أفضل إجابة نظرًا لوجود معلومات جيدة في العديد منها؛سيئة للغاية لا توجد خيارات الإجابة المساعدة.

اجابة قصيرة

لماذا لا أستطيع أن أقول فقط:

SecureString password = new SecureString("password");

لأنه الآن لديك password في الذاكرة؛مع عدم وجود وسيلة لمسحها - وهذا هو بالضبط الهدف سلسلة آمنة.

اجابة طويلة

السبب سلسلة آمنة موجود لأنه لا يمكنك استخدامه ZeroMemory لمسح البيانات الحساسة عند الانتهاء منها.إنه موجود لحل مشكلة موجودة لأن من CLR.

بشكل منتظم محلي التطبيق الذي ستتصل به SecureZeroMemory:

يملأ كتلة من الذاكرة بالأصفار.

ملحوظة:SecureZeroMemory مطابق لـ ZeroMemory, باستثناء أن المترجم لن يقوم بتحسينه.

المشكلة هي أنك لا أستطيع يتصل ZeroMemory أو SecureZeroMemory داخل .NET.وفي سلاسل .NET غير قابلة للتغيير؛لا يمكنك حتى الكتابة فوق محتويات السلسلة كما يمكنك القيام بها بلغات أخرى:

//Wipe out the password
for (int i=0; i<password.Length; i++)
   password[i] = \0;

ذلك ما يمكن أن تفعله؟كيف نوفر القدرة في .NET على مسح كلمة المرور أو رقم بطاقة الائتمان من الذاكرة عند الانتهاء من ذلك؟

الطريقة الوحيدة للقيام بذلك هي وضع السلسلة في بعضها محلي كتلة الذاكرة، حيث أنت يستطيع ثم اتصل ZeroMemory.كائن الذاكرة الأصلية مثل:

  • بستر
  • HGLOBAL
  • CoTaskMem الذاكرة غير المدارة

SecureString يعيد القدرة المفقودة

في .NET، لا يمكن مسح السلاسل النصية عند الانتهاء منها:

  • فهي غير قابلة للتغيير.لا يمكنك الكتابة فوق محتوياتها
  • انت لا تستطيع Dispose منهم
  • تنظيفهم تحت رحمة جامع القمامة

SecureString موجود كطريقة لتمرير سلامة السلاسل، وتكون قادرًا على ضمان تنظيفها عندما تحتاج إلى ذلك.

لقد طرحت السؤال:

لماذا لا أستطيع أن أقول فقط:

SecureString password = new SecureString("password");

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

يستخدم SecureString واجهة برمجة تطبيقات حماية البيانات لتخزين السلسلة المشفرة في الذاكرة؛بهذه الطريقة لن تكون السلسلة موجودة في ملفات المبادلة، أو عمليات تفريغ الأعطال، أو حتى في نافذة المتغيرات المحلية مع زميل يبحث في ما يجب عليك فعله.

كيف أقرأ كلمة المرور؟

ثم هو السؤال:كيف أتفاعل مع السلسلة؟أنت بالتأكيد لا نريد طريقة مثل:

String connectionString = secureConnectionString.ToString()

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

ولهذا السبب يوفر .NET ثلاث وظائف مساعدة مفيدة لتنظيم SecureString في ذاكرة غير مُدارة:

يمكنك تحويل السلسلة إلى فقاعة ذاكرة غير مُدارة، والتعامل معها، ثم مسحها مرة أخرى.

تقبل بعض واجهات برمجة التطبيقات سلاسل آمنة.على سبيل المثال في ADO.net 4.5 SqlConnection.Credential يأخذ مجموعة بيانات اعتماد SQL:

SqlCredential cred = new SqlCredential(userid, password); //password is SecureString
SqlConnection conn = new SqlConnection(connectionString);
conn.Credential = cred;
conn.Open();

يمكنك أيضًا تغيير كلمة المرور ضمن سلسلة الاتصال:

SqlConnection.ChangePassword(connectionString, cred, newPassword);

وهناك الكثير من الأماكن داخل .NET حيث يستمرون في قبول سلسلة عادية لأغراض التوافق، ثم يحولونها سريعًا إلى سلسلة آمنة.

كيفية وضع النص في SecureString؟

هذا لا يزال يترك المشكلة:

كيف يمكنني الحصول على كلمة مرور في SecureString في المقام الأول؟

هذا هو التحدي، ولكن الهدف هو جعلك تفكر في الأمان.

في بعض الأحيان يتم توفير الوظيفة لك بالفعل.على سبيل المثال، WPF كلمة المرور التحكم يمكن أن يعيد لك كلمة المرور التي تم إدخالها كـ سلسلة آمنة مباشرة:

خاصية كلمة المرور.SecurePassword

يحصل على كلمة المرور التي يحتفظ بها حاليا كلمة المرور ك سلسلة آمنة.

يعد هذا مفيدًا لأنه في كل مكان اعتدت فيه على تمرير سلسلة أولية، أصبح لديك الآن نظام كتابة يشكو من أن SecureString غير متوافق مع String.تريد الاستمرار لأطول فترة ممكنة قبل أن تضطر إلى تحويل SecureString مرة أخرى إلى سلسلة عادية.

يعد تحويل SecureString أمرًا سهلاً بدرجة كافية:

  • SecureStringToBSTR
  • PtrToStringBSTR

كما في:

private static string CreateString(SecureString secureString)
{
    IntPtr intPtr = IntPtr.Zero;
    if (secureString == null || secureString.Length == 0)
    {
        return string.Empty;
    }
    string result;
    try
    {
        intPtr = Marshal.SecureStringToBSTR(secureString);
        result = Marshal.PtrToStringBSTR(intPtr);
    }
    finally
    {
        if (intPtr != IntPtr.Zero)
        {
            Marshal.ZeroFreeBSTR(intPtr);
        }
    }
    return result;
}

إنهم حقًا لا يريدونك أن تفعل ذلك.

ولكن كيف يمكنني الحصول على سلسلة في SecureString؟حسنًا، ما عليك فعله هو التوقف عن امتلاك كلمة مرور في ملف خيط في المقام الأول.كنت بحاجة إلى أن يكون في ذلك شئ ما آخر.حتى أ Char[] المصفوفة ستكون مفيدة.

وذلك عندما يمكنك إلحاق كل حرف و امسح النص العادي عند الانتهاء:

for (int i=0; i < PasswordArray.Length; i++)
{
   password.AppendChar(PasswordArray[i]);
   PasswordArray[i] = (Char)0;
}

تحتاج إلى كلمة المرور الخاصة بك المخزنة في بعض الذاكرة التي يمكنك مسحها.قم بتحميله في SecureString من هناك.


ليرة تركية؛دكتور: سلسلة آمنة موجود لتوفير ما يعادل ZeroMemory.

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

هناك عدد قليل جدًا من السيناريوهات التي يمكنك من خلالها استخدام SecureString بشكل معقول في الإصدار الحالي من Framework.إنها مفيدة حقًا فقط للتفاعل مع واجهات برمجة التطبيقات غير المُدارة - يمكنك تنظيمها باستخدام Marshal.SecureStringToGlobalAllocUnicode.

بمجرد تحويله إلى/من System.String، تكون قد هزمت غرضه.

MSDN عينة ينشئ SecureString حرفًا في كل مرة من إدخال وحدة التحكم ويمرر السلسلة الآمنة إلى واجهة برمجة تطبيقات غير مُدارة.إنها معقدة إلى حد ما وغير واقعية.

قد تتوقع أن تحظى الإصدارات المستقبلية من .NET بمزيد من الدعم لـ SecureString مما يجعلها أكثر فائدة، على سبيل المثال:

  • SecureString Console.ReadLineSecure() أو ما شابه ذلك لقراءة إدخال وحدة التحكم في SecureString بدون كافة التعليمات البرمجية المعقدة في العينة.

  • بديل WinForms TextBox الذي يقوم بتخزين خاصية TextBox.Text الخاصة به كسلسلة آمنة بحيث يمكن إدخال كلمات المرور بشكل آمن.

  • ملحقات لواجهات برمجة التطبيقات ذات الصلة بالأمان للسماح بتمرير كلمات المرور على أنها SecureString.

بدون ما سبق، ستكون قيمة SecureString محدودة.

أعتقد أن السبب وراء ضرورة القيام بإلحاق الأحرف بدلاً من إنشاء مثيل مسطح واحد هو أنه في الخلفية، يؤدي تمرير "كلمة المرور" إلى مُنشئ SecureString إلى وضع سلسلة "كلمة المرور" هذه في الذاكرة مما يؤدي إلى هزيمة غرض السلسلة الآمنة.

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

الغرض من الفصل هو منع كشف البيانات الآمنة عبر تفريغ الذاكرة أو أداة مشابهة.

اكتشف MS أنه في بعض حالات التسبب في تعطل الخادم (سطح المكتب، أيًا كان) كانت هناك أوقات تقوم فيها بيئة وقت التشغيل بتفريغ الذاكرة للكشف عن محتويات ما هو موجود في الذاكرة.تقوم السلسلة الآمنة بتشفيرها في الذاكرة لمنع المهاجم من استرداد محتويات السلسلة.

إحدى الفوائد الكبيرة لـ SecureString هي أنه من المفترض تجنب إمكانية تخزين بياناتك على القرص بسبب التخزين المؤقت للصفحة.إذا كان لديك كلمة مرور في الذاكرة ثم قمت بتحميل برنامج أو مجموعة بيانات كبيرة، فقد تتم كتابة كلمة المرور الخاصة بك في ملف المبادلة أثناء ترحيل برنامجك من الذاكرة.باستخدام SecureString، على الأقل لن تبقى البيانات موجودة إلى أجل غير مسمى على القرص الخاص بك بنص واضح.

أعتقد أن السبب في ذلك هو أن السلسلة من المفترض أن تكون آمنة، أي.يجب ألا يتمكن المتسلل من قراءتها.إذا قمت بتهيئتها باستخدام سلسلة، فيمكن للمتسلل قراءة السلسلة الأصلية.

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

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

سأتوقف عن استخدام SecureString .يبدو أن شباب PG يسقطون الدعم له.ربما حتى سحبها في المستقبل - https://github.com/dotnet/apireviews/tree/master/2015-07-14-securestring .

يجب علينا إزالة التشفير من SecureString عبر جميع الأنظمة الأساسية في .NET Core - يجب علينا إلغاء SecureString - ربما لا ينبغي علينا الكشف عن SecureString في .NET Core

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

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