قم بمحاذاة معاينة محرر WMD HTML مع التحقق من صحة HTML من جانب الخادم (مثل رمز JavaScript المدمج)

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

سؤال

هناك العديد من أسئلة الفائض المكدس (على سبيل المثال القائمة البيضاء ، ومنع XSS مع التحكم في WMD في C# و WMD Markdown و Server-Side) حول كيفية القيام بتنظيف من جانب الخادم للتخفيض الذي ينتجه محرر WMD للتأكد من أن HTML الذي تم إنشاؤه لا يحتوي على نص ضار ، مثل هذا:

<img onload="alert('haha');" 
   src="http://www.google.com/intl/en_ALL/images/srpr/logo1w.png" />

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

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

أيضًا ، من المحتمل أن تكون فكرة سيئة للسماح لنافذة معاينة العميل بالسماح لـ HTML مختلف عن الخادم الخاص بك.

قام فريق Stack Overflow بتوصيل هذه الحفرة عن طريق إجراء تغييرات على WMD. كيف فعلوا ذلك؟

ملاحظة: لقد اكتشفت هذا بالفعل ، لكنه يتطلب بعض تصحيح أخطاء JavaScript الصعبة ، لذلك أجب على سؤالي هنا لمساعدة الآخرين الذين قد يرغبون في فعل نفس الشيء.

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

المحلول

أحد الإصلاحات المحتملة في WMD.JS ، في pushPreviewHtml() طريقة. إليك الرمز الأصلي من نسخة مكدس فائض من WMD على جيثب:

if (wmd.panels.preview) {
    wmd.panels.preview.innerHTML = text; 
}

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

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

if (wmd.panels.preview) {

    // Original WMD code allowed JavaScript injection, like this:
    //    <img src="http://www.google.com/intl/en_ALL/images/srpr/logo1w.png" onload="alert('haha');"/>
    // Now, we first ensure elements (and attributes of IMG and A elements) are in a whitelist,
    // and if not in whitelist, replace with blanks in preview to prevent XSS attacks 
    // when editing malicious Markdown.
    var okTags = /^(<\/?(b|blockquote|code|del|dd|dl|dt|em|h1|h2|h3|i|kbd|li|ol|p|pre|s|sup|sub|strong|strike|ul)>|<(br|hr)\s?\/?>)$/i;
    var okLinks = /^(<a\shref="(\#\d+|(https?|ftp):\/\/[-A-Za-z0-9+&@#\/%?=~_|!:,.;\(\)]+)"(\stitle="[^"<>]+")?\s?>|<\/a>)$/i;
    var okImg = /^(<img\ssrc="https?:(\/\/[-A-Za-z0-9+&@#\/%?=~_|!:,.;\(\)]+)"(\swidth="\d{1,3}")?(\sheight="\d{1,3}")?(\salt="[^"<>]*")?(\stitle="[^"<>]*")?\s?\/?>)$/i;
    text = text.replace(/<[^<>]*>?/gi, function (tag) {
        return (tag.match(okTags) || tag.match(okLinks) || tag.match(okImg)) ? tag : ""
    })

    wmd.panels.preview.innerHTML = text;  // Original code 
}

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

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

الكود الأصلي:

var _DoAutoLinks = function(text) {

    text = text.replace(/<((https?|ftp|dict):[^'">\s]+)>/gi,"<a href=\"$1\">$1</a>");

    // Email addresses: <address@domain.foo>

    /*
        text = text.replace(/
            <
            (?:mailto:)?
            (
                [-.\w]+
                \@
                [-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+
            )
            >
        /gi, _DoAutoLinks_callback());
    */
    text = text.replace(/<(?:mailto:)?([-.\w]+\@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi,
        function(wholeMatch,m1) {
            return _EncodeEmailAddress( _UnescapeSpecialChars(m1) );
        }
    );

    return text;
}

رمز ثابت:

var _DoAutoLinks = function(text) {
    // use simplified format for links, to enable whitelisting link attributes
    text = text.replace(/(^|\s)(https?|ftp)(:\/\/[-A-Z0-9+&@#\/%?=~_|\[\]\(\)!:,\.;]*[-A-Z0-9+&@#\/%=~_|\[\]])($|\W)/gi, "$1<$2$3>$4");
    text = text.replace(/<((https?|ftp):[^'">\s]+)>/gi, '<a href="$1">$1</a>');
    return text;
}

نصائح أخرى

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

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