جافاسكريبت - هل لا يزال خطف JSON مشكلة في المتصفحات الحديثة؟


أنا أستخدم Backbone.js وخادم الويب Tornado. السلوك القياسي لتلقي بيانات المجموعة في Backbone هو الإرسال كمصفوفة JSON.

من ناحية أخرى، السلوك الافتراضي لتورنادو هو عدم السماح بمصفوفات JSON بسبب الثغرة التالية:

http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx

ذات صلة: http://haacked.com/archive/2009/06/25/json-hijacking.aspx

يبدو لي أكثر طبيعية ألا أضطر إلى تغليف الـ JSON الخاص بي في كائن عندما يكون في الحقيقة قائمة من الكائنات.

لم أتمكن من إعادة إنتاج هذه الهجمات في المتصفحات الحديثة (أي كروم، فايرفوكس، سفاري، وإنترنت إكسبلورر 9 الحالية). وفي الوقت نفسه، لم أتمكن من تأكيد في أي مكان أن المتصفحات الحديثة قد عالجت هذه القضايا.

لضمان ألا يتم تضليلي بواسطة أي مهارات برمجة ضعيفة محتملة أو مهارات بحث ضعيفة على جوجل:

هل لا تزال هجمات اختطاف JSON تشكل مشكلة اليوم في المتصفحات الحديثة؟

(ملاحظة: عذراً على التكرار المحتمل للسؤال: هل من الممكن القيام بـ 'اختطاف JSON' على المتصفحات الحديثة؟ لكن بما أن الإجابة المقبولة لا تبدو وكأنها تجيب على السؤال - فكرت أنه حان الوقت لطرحه مرة أخرى والحصول على بعض التوضيحات الأكثر وضوحًا.)

الإجابة رقم 1

لا، لم يعد من الممكن التقاط القيم الممررة إلى منشئي [] أو {} في Firefox 21 أو Chrome 27 أو IE 10. إليك صفحة اختبار صغيرة، مستندة إلى الهجمات الرئيسية الموضحة في http://www.thespanner.co.uk/2011/05/30/json-hijacking/:

(http://jsfiddle.net/ph3Uv/2/)

var capture = function() {
    var ta = document.querySelector('textarea')
	ta.innerHTML = '';
	ta.appendChild(document.createTextNode("Captured: "+JSON.stringify(arguments)));
	return arguments;
}
var original = Array;

var toggle = document.body.querySelector('input[type="checkbox"]');
var toggleCapture = function() {
    var isOn = toggle.checked;
    window.Array = isOn ? capture : original;
    if (isOn) {
        Object.defineProperty(Object.prototype, 'foo', {set: capture});    
    } else {
        delete Object.prototype.foo;
    }
};
toggle.addEventListener('click', toggleCapture);
toggleCapture();

[].forEach.call(document.body.querySelectorAll('input[type="button"]'), function(el) {
    el.addEventListener('click', function() {
        document.querySelector('textarea').innerHTML = 'Safe.';
        eval(this.value);
    });
});
<div><label><input type="checkbox" checked="checked"> Capture</label></div>
<div><input type="button" value="[1, 2]" /> <input type="button" value="Array(1, 2);" /> <input type="button" value="{foo: 'bar'}" /> <input type="button" value="({}).foo = 'bar';" /></div>
<div><textarea></textarea></div>

يتجاوز window.Array ويضيف مُعيّنًا إلى Object.prototype.foo ويختبر تهيئة المصفوفات والكائنات عبر الصيغ القصيرة والطويلة.

تنص مواصفة ES4، في القسم 1.5، على "ضرورة استخدام الروابط العالمية والمعيارية لكل من Object و Array لإنشاء كائنات جديدة لمبادرات الكائنات والمصفوفات" وتلاحظ في سابقة التنفيذ أنه "متصفحات Internet Explorer 6 و Opera 9.20 و Safari 3 لا تحترم أيًا من إعادة ربط Object و Array محليًا أو عالميًا، بل تستخدم منشئات Object و Array الأصلية." هذا ما تم الاحتفاظ به في ES5، القسم 11.1.4.

شرح ألن ويرفس-بروك أن ES5 يحدد أيضًا أن تهيئة الكائن لا يجب أن تؤدي إلى تشغيل المُحددات، لأنه يستخدم DefineOwnProperty. ملاحظات MDN: العمل مع الكائنات تشير إلى أن "بدءًا من JavaScript 1.8.1، لم تعد المُحددات تُستدعى عند تعيين الخصائص في مهيئات الكائن والمصفوفة." تم معالجة هذا في قضية V8 رقم 1015.