لماذا هي صفيف نهائي ثابت في الفتحة الأمنية؟

StackOverflow https://stackoverflow.com/questions/2842169

  •  27-09-2019
  •  | 
  •  

سؤال

جاوة الفعالة تقول:

// ثقب الأمن المحتمل!

Static Public Public الشيء [] القيم = {...} ؛

هل يمكن لأحد أن يخبرني ما هو ثقب الأمن؟

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

المحلول

إعلان static final public الحقول عادة ما تكون السمة المميزة لثابت الفصل. إنه جيد تمامًا للأنواع البدائية (ints ، الزوجي ، إلخ ..) ، والطبقات غير القابلة للتغيير ، مثل الأوتار و java.awt.Color. مع المصفوفات ، تكمن المشكلة في أنه على الرغم من أن مرجع الصفيف ثابت ، إلا أنه لا يزال من الممكن تغيير عناصر الصفيف ، وبما أنها حقل ، فإن التغييرات غير محمية ، غير متحمسة ، وعادة ما تكون غير مرحب بها.

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

نصائح أخرى

لفهم سبب وجود ثقب أمني محتمل وليس مجرد تغليف ضعيف ، فكر في المثال التالي:

public class SafeSites {
    // a trusted class with permission to create network connections
    public static final String[] ALLOWED_URLS = new String[] {
        "http://amazon.com", "http://cnn.com"};

    // this method allows untrusted code to connect to allowed sites (only)
    public static void doRequest(String url) {
        for (String allowed : ALLOWED_URLS) {
            if (url.equals(allowed)) {
                 // send a request ...
            }
        }
    }
}

public class Untrusted {
     // An untrusted class that is executed in a security sandbox.

     public void naughtyBoy() {
         SafeSites.ALLOWED_URLS[0] = "http://myporn.com";
         SafeSites.doRequest("http://myporn.com");
     }
}

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

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


قال العنبر هذا في تعليق:

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

هذا ليس صحيحا.

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

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

-- جافا فعالة, ، 2nd ed. (صفحة 70)

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

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

في هذا الإعلان ، يمكن للعميل تعديل الشيء [0] ، الشيء [1] ، إلخ (أي عناصر في الصفيف).

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

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

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

public static final String[] VALUES = { "a", "b" }; 

a.VALUES[0] = "changed value on index 0";
System.out.println(String.format("Result: %s", a.VALUES[0]));

ونحصل Result: changed value on index 0

اقترح Joshua Bloch إرجاع نسخة من Array:

private static final String[] VALUES = { "a", "b" };   
public static final String[] values()
{
    return VALUES.clone();
}

حتى الآن عندما نحاول:

a.values()[0] = "changed value on index 0";
System.out.println(String.format("Result: %s", a.values()[0]));

نحن نحصل Result: a وهذا ما أردنا تحقيقه - VALUES غير قابلة للتغيير.

لا يوجد شيء سيء في الإعلان public static final القيم البدائية أو الأوتار أو غيرها من الأشياء غير القابلة للتغيير مثل public static final int ERROR_CODE = 59;

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