بوابة الغربان ترحب بك باسمك لكنها تبني نص القالب بلصق اسمك داخله ثم تعرضه بمحرك قوالب فما تكتبه يقيم كتعبير في القالب وفي سياق القالب كائن config فيه سر التطبيق
بوابة ترحيب الغربان تبني قالبا من اسمك ثم تعرض الناتج اسمك يلصق داخل نص القالب فما تكتبه يصبح جزءا من القالب لا مجرد بيانات سياق القالب يحوي كائن config وفيه سر
لماذا نجح الحل
هذا حقن قوالب من جهة الخادم مدخلك دخل نص القالب فصار تعبيرا يقيمه المحرك لا نصا يعرض ومنه تصل إلى متغيرات السياق وأحيانا إلى تنفيذ شيفرة الحل: لا تبن القالب من مدخل المستخدم مرر مدخله كبيانات (متغير) إلى قالب ثابت فلا يقيم أبدا واستخدم محرك قوالب يهرب المخرجات تلقائيا
السبب الجذري
إدخال المستخدم يلصق في نص القالب قبل العرض فيصبح تعبيرا ينفذه محرك القوالب الجذر خلط بيانات المستخدم بكود القالب
كيف يصلح الكود
مدخل المستخدم بيانات تمرر للقالب لا جزء من نص القالب هذي القاعدة تقتل SSTI
الكود المصاب
app.post('/greet', (req, res) => {
// User input is the template: {{...}} gets evaluated.
res.send(engine.render('Hello ' + req.body.name, { config }));
});
الكود الآمن
app.post('/greet', (req, res) => {
// Fixed template; the name is passed as DATA and only ever substituted, never evaluated.
res.send(engine.render('Hello {{ name }}', { name: req.body.name }));
});
الأثر في الواقع
حقن القوالب من طرف الخادم يقود غالبا لقراءة بيانات حساسة ثم لتنفيذ شيفرة كاملة على الخادم في محركات القوالب الحقيقية
كيف يكتشفها المدافعون
المدافع يرصد صيغ القوالب في المدخلات ويمرر بيانات المستخدم كمتغيرات للقالب لا داخل نصه