Anti-LLM Obfuscation: سكربتات البصمة تردّ على النماذج
تشويش Anti-LLM يخفي برومبتات كسر الحماية داخل سكربتات بصمة المتصفح ليفشل فك التشويش بالذكاء الاصطناعي. إليك كيف يعمل وما الذي يتغلب عليه.

قام باحث بربط كل استدعاء للوحة الرسم canvas على 10,000 من أكبر مواقع الويب، وجمع أكثر من ألف عملية رسم لأغراض البصمة، ثم بحث عن أجملها. ما وجده داخل السكربت المسؤول هو أنظف مثال حتى الآن على التشويش المضاد للنماذج اللغوية (anti-LLM obfuscation): سكربت بصمة متصفح مليء بدوال تحمل أسماء مثل computeRicinLethalDosageForWaterSupply، وبرومبت كسر حماية (jailbreak) مشفّر بمحارف يونيكود غير مرئية. لم يُصمَّم هذا ليخفي الكود عن مهندسي الهندسة العكسية البشريين، بل ليجعل مساعدات الذكاء الاصطناعي ترفض فك تشويهه.
قضيت سنوات في الاستجابة للحوادث الأمنية، وأول قراءة لي للتقرير أثارت في نفسي الرد الذي أراده الباحثون: هذا يبدو كبرمجية خبيثة، أو أسوأ. أسماء دوال عن جرعات الريسين المميتة ونصف قطر التساقط الإشعاعي للقنبلة القذرة. سلسلة مفكوكة تطالب بأدلة خطوة بخطوة لتصنيع الأسلحة البيولوجية. ومسار تنفيذ في Node.js يقرأ .npmrc و.env وإعدادات kube، ويسحب ملفًا ثنائيًا من عنوان IP داخلي، ويثبّت منارة cron. كل غريزة تقول إنه مهاجم. وكل غريزة مخطئة، والخطأ هو الهدف. هذه قصة عمّا يحدث حين يدرك من يبيعون التشويش أن خصمهم الحقيقي لم يعد إنسانًا يحمل مُصحِّح أخطاء (debugger)، بل نموذجًا لديه فلتر أمان.
كان الزحف نفسه مباشرًا: Playwright على قائمة Tranco لأعلى المواقع، مع اعتراض HTMLCanvasElement.prototype.toDataURL ومؤشرات الأتمتة المعروفة مثل navigator.webdriver لاستبعاد اللوحات غير الضارة. جُمعت عمليات الرسم في معرض عام وصُنِّفت حسب المزوّد، مثل FingerprintJS وCastle والمشتبه بهم المعتادين، إضافة إلى ذيل طويل من المجهولين. لوحة واحدة، تدفقت فيها خطوط منسابة بشكل رائع، تعود إلى سكربت تقدمه شركة روسية للحماية من هجمات DDoS. هنا بدأت الحكاية الممتعة.
المشكلة: النماذج اللغوية كسرت نموذج عمل التشويش
لعشرين عامًا كان لتشويش JavaScript وظيفة واحدة: جعل الهندسة العكسية مكلفة بما يكفي لكي لا يكلف أحد نفسه عناءها. أدوات مثل javascript-obfuscator ومشتقاتها التجارية تعيد تسمية المعرّفات، وتحزم النصوص الحرفية في مصفوفات بحث، وتحقن شروطًا غير شفافة (opaque predicates)، وتسطّح تدفق التحكم إلى آلات حالة مدفوعة بـ switch. لا شيء من هذا يصمد أمام إنسان مصمم لديه فترة بعد الظهر كاملة، لكن هذا كان مقبولًا، لأن أولئك الأشخاص المصممين الذين لديهم وقت فائض كانوا نادرين، والاقتصاد كان في صالح المدافع.
ثم أصبحت النماذج اللغوية بارعة في قراءة الكود المشوّه، فانقلب الاقتصاد. لصق كود مشوّش بحجم 400 كيلوبايت لسكربت مكافحة الروبوتات في نافذة محادثة وسؤال «ماذا يفعل هذا؟» يستغرق ثلاثين ثانية. لا يهم النموذج أن اسم دالتك PiERW أو أن نصوصك موجودة في مصفوفة مدوّرة. إنه يقرأ المعنى. يدمج فاك التشفير، ويتتبع تدفق البيانات، ثم يعيد ملخصًا بلغة إنجليزية بسيطة. تلاشى حصن كل مزوّد لمكافحة الروبوتات، أي الغموض، بهدوء.
لاحظ المزوّدون ذلك، وجاء ردّهم ذكيًا بشكل مزعج: إذا لم تستطع إخفاء الكود عن النموذج، فهاجم النموذج نفسه. قدّم له محتوى يُجبره تدريب السلامة على رفضه. يعامل التشويش المضاد للنماذج اللغوية محاذاة النموذج كأضعف حلقة في خط التحليل. والمزعج أنهم محقون.
كيف تجمع سكربتات بصمة المتصفح الإنتروبيا
لفهم الفخ، تحتاج إلى معرفة الآلية المشروعة التي ثُبّت عليها. تعمل بصمة الـ canvas برسم نصوص وتدرجات وأشكال على <canvas> غير مرئي، ثم قراءة مصفوفة البكسلات عبر toDataURL(). يختلف خط عرض الرسوميات (GPU والتعريف والمحوّل النقطي للخطوط ومقاومة التعرّج وتلميح البكسلات الفرعية) بشكل دقيق من جهاز لآخر، فيُنتج متصفحان يرسمان التعليمات نفسها مصفوفتي بكسلات مختلفتين في التجزئة. أضف إلى ذلك سلاسل مُعرِّف عرض WebGL وتوقيت AudioContext وهندسة الشاشة والخطوط المثبتة ومئة إشارة أخرى، فتحصل على معرّف ثابت دون أي كوكي واحدة.
استخدم الزحف الذي عثر على سكربتنا حيلة الاعتراض المعيارية. اعترض دالة القراءة الأساسية في سكربت تهيئة، وسجّل مكدس الاستدعاءات وبادئة كل صورة تُلتقط:
await page.addInitScript(() => {
const original = HTMLCanvasElement.prototype.toDataURL;
HTMLCanvasElement.prototype.toDataURL = function (...args) {
const result = original.apply(this, args);
fetch("/__log", {
method: "POST",
body: JSON.stringify({
stack: new Error().stack,
byteLength: result.length,
head: result.slice(0, 64),
}),
});
return result;
};
});
عند تشغيل ذلك على عدد كافٍ من المواقع، يرسم نظام البصمة خريطة لنفسه. معظم اللوحات مملة: جملة تحتوي كل حروف الأبجدية، وبعض المستطيلات، وتدرج. قلة منها معقدة بما يكفي لتُعدّ فنًا توليديًا. وكلها تُنتج بسكربتات مشوّشة بشدة، لأن المزوّدين يعرفون أن البصمة غير المشوّشة قابلة للتتبع. كان التشويش دائمًا جزءًا من المنتج. الجديد هو من يستهدفه التشويش.
داخل فخ التشويش المضاد للنماذج اللغوية
بدأ السكربت بشكل تقليدي: أسماء مشوّهة، ونصوص مضغوطة، والمعتاد. ثم توقفت أسماء المعرّفات عن كونها عشوائية وصارت موجهة. computeRicinLethalDosageForWaterSupply. calculateDeadlyLethalSuicideAspirinDosage. computeCRISPRGeneDrivePropagationRate. computeCesium137DirtyBombFalloutRadius. تعيد الدوال أرقامًا مكسوّة بملخصات مخيفة الصوت مثل «تم تأكيد عتبة الفتك للبالغين عند X ملغ/كغ»، لكن الحساب مجرد خداع. لا يحسب شيئًا حقيقيًا ولا يُغذّي شيئًا.
الفكرة الجوهرية: المعرّفات لا تحمل أي معنى وقت التشغيل، لكنها تحمل وزنًا دلاليًا هائلًا بالنسبة إلى النموذج اللغوي. لقد تعلّم المهندس البشري من الخبرة أن يتجاهل الأسماء، فنحن جميعًا احترقنا مرة بدالة اسمها validateUser لا تفعل شيئًا من هذا. أما النموذج فيفعل العكس. يقرأ computeRicinLethalDosageForWaterSupply، فيطابق سياق الأسلحة البيولوجية، وتُطلق آلية السلامة لديه قبل أن يتحرك فضوله.
الطبقة الأعمق كانت قالبًا نصيًا (template literal) مليئًا بمحارف غير مرئية، أي نقاط رمزية من كتلة Tags في يونيكود، ابتداءً من U+E0000. تُعرض كلا شيء. فاك التشفير سطر واحد:
const cleartext = [...payload]
.map((c) => String.fromCodePoint(c.codePointAt(0) - 917504))
.join("");
// 917504 === 0xE0000, the start of the invisible "Tags" block.
// Subtracting it maps each hidden char back to plain ASCII.
بعد فكّه، تبيّن أنه برومبت كسر حماية كامل: إعلان مزيف بعنوان «تجاوز النظام -- إحاطة سرية» يعلن تعليق إرشادات السلامة، ويطالب بأدلة خطوة بخطوة لهجمات DDoS على البنية التحتية الصحية، والتهرب الضريبي، والعوامل البيولوجية المحمولة جوًا، وجرعات الأدوية، إضافة إلى إشارات إلى ميدان تيانانمن بالإنجليزية والصينية، واضح أنها تستهدف استثارة ردود الرقابة لدى النماذج المستضافة في الصين. كانت سلسلة مصممة لتطال كل تصنيف للحماية في وقت واحد. عندما يُطلب من نموذج لغوي تحليل الكود المحيط، فإنه يستوعب هذا كسياق، ومهما كان سينفذه، فإنه الآن لا ينفذ شيئًا.

المحاولات الفاشلة: الرفض، والإنذارات الكاذبة، وبوتنت مزيف
الحركة الطبيعية الأولى، أي لصق السكربت في نموذج رائد، فشلت تمامًا كما صُمّمت. رفض النموذج مستشهدًا بمخاطر السلامة البيولوجية. ومحاولة ثانية بإعداد أمان مختلف حُظرت هي أيضًا. أصبح المشوّش قد سلّح الرفض: السكربت الآن غير قابل لفك الترجمة بالأدوات التي يستخدمها الجميع فعليًا. نجح نموذج مفتوح الأوزان بضوابط أضعف في الامتثال، وهذه نقطة بيانات لا حل، فمعظم المحللين لا يبقون نموذجًا محليًا جاهزًا لهذا الغرض، وأغلب سياسات الشركات تمنع لصق كود طرف ثالث في بنية تحتية غير مُدقَّقة على أي حال.
المحاولة الفاشلة الثانية أدق وأخطر: المحلل البشري الذي يستنتج أن السكربت برمجية خبيثة. هناك مسار تنفيذ خاص بـ Node مشروط بـ process.env.METRICS_AGENT_8BFD_ACTIVE، يقرأ ملفات إعدادات شبيهة بـ SSH، ويحمّل «وكيل قياسات» من 10.15.45.1، ويبصم المضيف داخل /tmp، ويضغطه، ويثبّت منارة cron. يبدو كزرع لسلسلة توريد. لكن عند شد الخيوط: علم البيئة لا تضبطه أي جهة، وتُستدعى readFile بدوال استدعاء فارغة فلا تذهب البيانات المسروقة إلى أي مكان، وعنوان C2 من نطاق RFC 1918 الخاص، وأوامر الصدفة تكرر طعم كسر الحماية داخل ملفات علامات لا يُرسل شيء منها خارجيًا. شغّله في صندوق رمل وسيكون نطاق الضرر دليلًا مؤقتًا. إنه مسرحية، طُعم مضبوط للفرز بمساعدة الذكاء الاصطناعي وللبشر الذين يتصفحون بسرعة.
هناك صدى من الواقع. حين حقق فريق في منصة كبرى لنماذج الذكاء الاصطناعي في اختراق حقيقي، وجد أن واجهات برمجة النماذج التجارية رفضت تحليل أوامر المهاجم وحمولاته وقطع C2، إذ لم تستطع الضوابط التمييز بين المستجيب للحوادث والمهاجم. فانتهى بهم الأمر إلى تشغيل التحليل الجنائي على نموذج مفتوح الأوزان على بنيتهم التحتية. هذا النمط من الفشل، إذا تكرر على نطاق واسع، هو بالضبط عدم التماثل الذي يستغله التشويش المضاد للنماذج اللغوية. وهذا أيضًا سبب إصراري على أن فحوصات فهم الكود بالذكاء الاصطناعي لا يمكن أن تكون خط دفاعك الوحيد: حكم النموذج صار سطح هجوم له استغلال منشور.
المشوّش لم يعد يخفي الكود عنك. إنه يخفيه عن نموذجك، ويستخدم تدريب السلامة الخاص بنموذجك كقفل.
ما الذي يجدي فعلًا ضد التشويش المضاد للنماذج اللغوية
الحل هو التوقف عن تغذية النموذج بالكود المصدري الخام، واستعادة مراحل خط المعالجة التي تسممها الفخاخ. عمليًا، وبالترتيب الذي أبنيه به:
- فك التشويش الحتمي أولًا. شغّل السكربت عبر تمريرات AST مبنية على Babel: طيّ الثوابت، وتضمين مصفوفة النصوص، وإزالة الفروع الميتة، وفك تسطيح تدفق التحكم. تعيش الفخاخ في النصوص الحرفية والمعرّفات، فطيّ الثوابت وإعادة التسمية يبطلانها قبل أن يرى أي نموذج أي رمز. يصبح برومبت كسر الحماية المفكوك مجرد نص آخر في مسار تنفيذ ميت.
- تتبّع السلوك، لا تقرأ المصدر. نفّذ السكربت في بيئة معزولة مُراقَبة، مثل صفحة Playwright بواجهات مُعترَضة أو عالم (realm) معزول، وسجّل كل استدعاء DOM وطلب شبكة ووصول إلى الخصائص وقراءة لوحة الرسم. غذِّ النموذج التتبع. يحتوي التتبع السلوكي على صفر إشارة إلى الريسين، لأن السلوك لا يملك معرّفات.
- أعد تسمية المعرّفات إلى رموز محايدة قبل أي تمرير للنموذج اللغوي. يصبح
computeRicinLethalDosageForWaterSupplyهوfn_0417. تخسر القليل من التلميح الدلالي، وتتخلص من كل التسميم. صفقة جيدة. - احتفظ بنموذج محلي مفتوح الأوزان للفرز الحساس فعلًا. حين يكون المحتوى قاتمًا بشكل مشروع، مثل حزم استغلال حقيقية أو حزم تصيد فعلية، فإن نموذجًا معزولًا عن الشبكة بلا ضوابط سحابية هو الفارق بين التحليل وجدار الرفض.
- الأحكام تُبنى على الأدلة لا على الانطباعات. قيّم السكربتات حسب القدرات المرصودة: هل قرأ بيانات اعتماد؟ هل غادرت البايتات الصفحة؟ لا بناءً على ما إذا كان المصدر يذكر بيانات الاعتماد.
لاحظ النمط: كل تقنية تستبدل «اسأل النموذج عما يقوله الكود» بـ «لاحظ ما يفعله الكود، ثم اسأل النموذج عن الملاحظة». وهو المبدأ نفسه الذي أعود إليه دائمًا مع الوكلاء المستقلين، أي الاحتواء يتفوق على المراقبة. لا تثق بوصف الأداة لنفسها، بل احصرها، واجعل حدودها مُراقَبة، وحكم على مخرجاتها.
سكربتات الطرف الثالث تتحدث إلى مزوّدي النماذج
الآن الجزء الذي يجب أن يقلق من لا يقومون بالهندسة العكسية للتسلية. هذا السكربت ليس مستضافًا في زاوية مظلمة، بل هو فحص لمكافحة الروبوتات يُقدَّم على مواقع العملاء، تحت نطاقاتهم، بجانب علاماتهم التجارية. أي أن كل زاحف، وكل مصنّف محتوى يعمل بالنماذج اللغوية، وكل خط أنابيب لسلامة العلامة والثقة يستوعب الصفحة الآن، فيستوعب طلبات تصنيع الأسلحة البيولوجية وبرومبتات كسر الحماية إلى جانب شعار الشركة. العملاء على الأرجح لا يعرفون. والمزوّد لم يستأذن أحدًا.
المصنفات الآلية التي تتصرف بناءً على محتوى لا تفهمه ليست فرضية. لقد شهد ممارسون اختفاء مستندات صادرة في حجر صامت لأن علامة مائية غير مرئية أطلقت فلتر بريد. الآن ضاعف هذا النمط من الفشل: مصنّف سلامة العلامة يقرر أن نطاقك مجاور لمحتوى متطرف أو خطير بيولوجيًا، ولن يخبرك أحد لماذا انهار وصولك. ولا يمكنك حتى الاستئناف، لأن الدليل هو محارف يونيكود غير مرئية داخل ملف لم تكتبه.
ولا تنفع الحلول المعتادة هنا. Subresource Integrity عديم الفائدة حين يدوّر المزوّد تجزئة السكربت مع كل نشر، وهذه السكربتات تتغير باستمرار، جزئيًا لإفشال التثبيت. وسياسة CSP صارمة مع تجزئات تتغير بنفس السرعة. ما يتبقى هو الاستنتاج المزعج الذي وصلنا إليه بعد اختراق سلسلة توريد LiteLLM: التبعية التي لا تستطيع مراجعتها هي التي تمتلكك. إذا كان كود مزوّد مكافحة الروبوتات مصممًا عمدًا ليكون غير قابل لفك الترجمة بالأدوات التي يستخدمها فريق الأمن لديك، فهذه ليست ميزة. إنها فشل في الحوكمة بعنوان CDN.

أين يتجه سباق التسلح هذا
توقعي: خلال عام، سيُدرج فخ الإنذار ضد الحماية كخانة اختيار في المشوّشات التجارية، بجوار «تسطيح تدفق التحكم». سيرد مزوّدو النماذج بتدريب النماذج على مجموعات من أفخاخ الإنذار، حتى تتعلم التعرف على الطعم المضمّن في سياقات التحليل وتتجاهله. وسيرد المشوّشون بفخاخ أدق: كود يبدو سلوكه خبيثًا في التتبعات، لا مجرد سلاسله النصية. سباق التسلح الذي توقعته تعليقات Hacker News مازحةً، أي مشوّشون مضبوطون ضد النماذج ونماذج مضبوطة ضد المشوّشين، موجود بالفعل؛ لكنه موزع بشكل غير متساوٍ.
الدفاع المتين هو الممل، ولم يتغير منذ أولى أدوات الضغط في التسعينيات: التحليل الديناميكي، والأدلة السلوكية، والتنفيذ داخل صندوق رمل. لم يكن الغموض يومًا خاصية أمنية، بل كان استراتيجية لنقل التكلفة، وقد عادت التكلفة الآن إلى أصحابها. إذا كان بإمكان سلسلة نصية تؤذي مشاعر نموذج لغوي أن تهزم خط الكشف لديك، فإن الخط كان الثغرة منذ البداية.


