سؤال

هل من الممكن "مسح" السلاسل في دلفي؟دعني أشرح:

أنا أكتب تطبيقًا يتضمن ملف DLL لتخويل المستخدمين.سيقوم بقراءة ملف مشفر في XML DOM، واستخدام المعلومات الموجودة هناك، ثم تحرير DOM.

ومن الواضح أن ملف XML غير المشفر لا يزال موجودًا في ذاكرة DLL، وبالتالي عرضة للفحص.الآن، لن أبالغ في حماية هذا - يمكن للمستخدم إنشاء ملف DLL آخر - ولكني أرغب في اتخاذ خطوة أساسية لمنع أسماء المستخدمين من البقاء في الذاكرة لفترة طويلة.ومع ذلك، لا أعتقد أنه يمكنني بسهولة مسح الذاكرة على أي حال بسبب المراجع.إذا قمت باجتياز DOM الخاص بي (وهو فئة TNativeXML) وعثرت على كل مثيل لسلسلة ثم قمت بتحويلها إلى شيء مثل "aaaaa"، فلن يتم تعيين مؤشر السلسلة الجديد فعليًا لمرجع DOM، ثم ترك السلسلة القديمة في مكانها هناك في الذاكرة في انتظار إعادة التخصيص؟هل هناك طريقة للتأكد من أنني أقتل النسخة الوحيدة والأصلية؟

أم أن هناك في D2007 وسيلة لإخباره بمسح كافة الذاكرة غير المستخدمة من الكومة؟حتى أتمكن من تحرير DOM، ثم اطلب منه المسح.

أم يجب أن أواصل مهمتي التالية وأنسى هذا لأنه في الحقيقة لا يستحق العناء.

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

المحلول

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

وIMO أي مستخدم المهتمين وقادرة على القيام بما تصفون لن تكون مسرورة محمل الجد من قبل DLL الخاص بك مسح الذاكرة بما فيه الكفاية.

نصائح أخرى

وهناك نقطتان العامة حول هذا:

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

للرد على سؤال محدد الخاص بك: API ويندوز لديها عدد من الوظائف التي هي مفيدة، مثل <وأ href = "http://msdn.microsoft.com/en-us/library/aa380262(VS.85) .aspx اتصال "يختلط =" نوفولو noreferrer "> CryptProtectMemory . ومع ذلك، وهذا خلق شعور زائف بالأمان إذا قمت بتشفير الذاكرة الخاصة بك، ولكن لديها ثقب في أي مكان آخر في النظام، أو فضح قناة جانبية. ويمكن أن يكون مثل وضع قفل على الباب الخاص بك ولكن ترك النافذة مفتوحة.

وماذا عن شيء مثل هذا؟

procedure WipeString(const str: String);
var
  i:Integer;
  iSize:Integer;
  pData:PChar;

begin
    iSize := Length(str);
    pData := PChar(str);

    for i := 0 to 7 do
    begin
      ZeroMemory(pData, iSize);
      FillMemory(pData, iSize, $FF); // 1111 1111
      FillMemory(pData, iSize, $AA); // 1010 1010
      FillMemory(pData, iSize, $55); // 0101 0101
      ZeroMemory(pData, iSize);
    end;
end;

ودلس لا تملك الذاكرة المخصصة والعمليات القيام به. الذاكرة المخصصة من قبل عملية محددة سيتم تجاهل مرة واحدة إنهاء العملية، سواء كان DLL معلقة حول (لأنه قيد الاستخدام من قبل عملية أخرى) أم لا.

وماذا عن فك تشفير الملف إلى تيار، وذلك باستخدام معالج SAX بدلا من DOM XML للقيام التحقق ثم الكتابة تيار فك قبل تخليصه؟

إذا كنت تستخدم إدارة الذاكرة FastMM في وضع التصحيح كامل، ثم يمكنك اجبارها على الكتابة الذاكرة عندما يتم تحريرها.

وعادة ما يتم استخدام هذا السلوك للكشف عن مؤشرات البرية، ولكنها يمكن أن تستخدم أيضا لماذا تريد الخاص بك.

وعلى صعيد آخر، تأكد من أنك تفهم ما يكتب كريغ Stuntz: لا أكتب هذا التوثيق والترخيص الاشياء بنفسك، استخدام نظام التشغيل الأساسي كلما كان ذلك ممكنا

وراجع للشغل: كتب Hallvard Vassbotn على بلوق لطيفة عن FastMM: http://hallvards.blogspot.com/2007/ 05 / استخدام كامل fastmm-النظر-donating.html

والتحيات،

ويروين Pluimers

وفوضوي ولكن هل يمكن تقديم مذكرة من حجم كومة التي كنت قد استخدمت في حين كنت قد حصلت على كومة مليئة البيانات الحساسة ثم عند التي يتم تحريرها لا على GetMem تخصيص كنت جزءا كبيرا يمتد (ويقول) 200٪ من ذلك. القيام التعبئة على أن قطعة وجعل افتراض أن أي تجزئة هو unlinkely أن تكون ذات فائدة كبيرة للممتحن. بري

وماذا عن حفظ كلمة المرور كقيمة التجزئة في XML والتحقق من خلال مقارنة تجزئة إدخال كلمة المرور مع كلمة المرور تجزئته في XML الخاصة بك.

وتحرير: يمكنك الحفاظ على جميع البيانات الحساسة مشفرة وفك تشفير فقط في آخر لحظة ممكنة

وسيكون من الممكن لتحميل XML فك إلى مجموعة من شار أو بايت بدلا من سلسلة؟ ثم لن يكون هناك أي معالجة النسخ عند الكتابة، لذلك سوف تكون قادرة على ردم الذاكرة مع # 0 قبل تحرير؟

كن حذرا إذا تعيين مجموعة من شار إلى سلسلة، وكذلك دلفي بعض التعامل الذكي هنا من أجل التوافق مع مجموعة معبأة التقليدية [1..x] من شار.

وبالإضافة إلى ذلك، يمكنك استخدام ShortString؟

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

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

يحرر

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

كن حذرًا من الوظائف التي تحاول التعامل مع السلسلة كمؤشر، وحاول استخدامها FillChar أو ZeroMemory لمسح محتويات السلسلة.

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

 

procedure BurnString(var s: UnicodeString);
begin
    {
        If the string is actually constant (reference count of -1), then any attempt to burn it will be
        an access violation; as the memory is sitting in a read-only data page.

        But Delphi provides no supported way to get the reference count of a string.

        It's also an issue if someone else is currently using the string (i.e. Reference Count > 1).
        If the string were only referenced by the caller (with a reference count of 1), then
        our function here, which received the string through a var reference would also have the string with
        a reference count of one.

        Either way, we can only burn the string if there's no other reference.

        The use of UniqueString, while counter-intuitiave, is the best approach.
        If you pass an unencrypted password to BurnString as a var parameter, and there were another reference,
        the string would still contain the password on exit. You can argue that what's the point of making a *copy*
        of a string only to burn the copy. Two things:

            - if you're debugging it, the string you passed will now be burned (i.e. your local variable will be empty)
            - most of the time the RefCount will be 1. When RefCount is one, UniqueString does nothing, so we *are* burning
                the only string
    }
    if Length(s) > 0 then
    begin
        System.UniqueString(s); //ensure the passed in string has a reference count of one
        ZeroMemory(Pointer(s), System.Length(s)*SizeOf(WideChar));

        {
            By not calling UniqueString, we only save on a memory allocation and wipe if RefCnt <> 1
            It's an unsafe micro-optimization because we're using undocumented offsets to reference counts.

            And i'm really uncomfortable using it because it really is undocumented.
            It is absolutely a given that it won't change. And we'd have stopping using Delphi long before
            it changes. But i just can't do it.
        }
        //if PLongInt(PByte(S) - 8)^ = 1 then //RefCnt=1
        //  ZeroMemory(Pointer(s), System.Length(s)*SizeOf(WideChar));

        s := ''; //We want the callee to see their passed string come back as empty (even if it was shared with other variables)
    end;
end;

بمجرد حصولك على UnicodeString الإصدار، يمكنك إنشاء AnsiString و WideString الإصدارات:

procedure BurnString(var s: AnsiString); overload;
begin
    if Length(s) > 0 then
    begin
        System.UniqueString(s);
        ZeroMemory(Pointer(s), System.Length(s)*SizeOf(AnsiChar));

        //if PLongInt(PByte(S) - 8)^ = 1 then //RefCount=1
        //  ZeroMemory(Pointer(s), System.Length(s)*SizeOf(AnsiChar));

        s := '';
    end;
end;

procedure BurnString(var s: WideString);
begin
    //WideStrings (i.e. COM BSTRs) are not reference counted, but they are modifiable
    if Length(s) > 0 then
    begin
        ZeroMemory(Pointer(s), System.Length(s)*SizeOf(WideChar));

        //if PLongInt(PByte(S) - 8)^ = 1 then //RefCount=1
        //  ZeroMemory(Pointer(s), System.Length(s)*SizeOf(AnsiChar));

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