پرش به محتوای اصلی
آسیب‌پذیری‌های سایت

Server-Side Template Injection چیست؟ بررسی آسیب‌پذیری SSTI در وب‌سایت‌ها

Server-Side Template Injection یا SSTI نوعی آسیب‌پذیری Injection است که زمانی رخ می‌دهد که ورودی غیرقابل‌اعتماد به‌جای داده، بخشی از Template قابل‌تفسیر سمت سرور شود. آسیب‌پذیری SSTI بسته به Template Engine و سطح دسترسی برنامه می‌تواند باعث افشای اطلاعات، تغییر خروجی و در شرایط خاص پیامدهای جدی‌تر شود. استفاده از Template ثابت، ارسال ورودی کاربر به‌عنوان Variable، محدود کردن Context، Sandbox، Least Privilege و کنترل منابع از مهم‌ترین راهکارهای پیشگیری از SSTI هستند.

تیم امنیت رخنه‌کاو ۳۹ دقیقه مطالعه انتشار:

Server-Side Template Injection یا به‌اختصار SSTI نوعی آسیب‌پذیری تزریق در برنامه‌های تحت وب است که زمانی رخ می‌دهد که ورودی قابل‌کنترل توسط کاربر به‌جای آنکه صرفاً به‌عنوان «داده» وارد یک قالب شود، بخشی از خود Template یا دستورهای قابل‌تفسیر موتور قالب‌ساز شود. در چنین شرایطی، Template Engine ممکن است ورودی مهاجم را به‌عنوان Expression یا Directive پردازش کند. پیامد SSTI بسته به موتور قالب‌ساز و سطح دسترسی برنامه می‌تواند از افشای اطلاعات تا دسترسی به داده‌های حساس و در برخی شرایط اجرای کد روی سرور گسترش پیدا کند.

نکته کلیدی در پیشگیری از آسیب‌پذیری SSTI این است که داده کاربر هرگز نباید به Template Source تبدیل شود. استفاده از قالب‌های ثابت، ارسال داده به‌صورت Variable، محدود کردن قابلیت‌های Template Engine، استفاده صحیح از Sandbox در موارد ضروری، اصل Least Privilege و بررسی مسیر ورود داده تا محل رندر از مهم‌ترین کنترل‌های دفاعی هستند.

Server-Side Template Injection یا SSTI چیست؟

برای درک Server-Side Template Injection ابتدا باید بدانیم موتورهای Template یا Template Engine چه کاری انجام می‌دهند.

بسیاری از برنامه‌های تحت وب برای تولید صفحات پویا از یک موتور قالب‌ساز استفاده می‌کنند. وظیفه این موتور آن است که یک ساختار ثابت را با داده‌های متغیر ترکیب کند و خروجی نهایی را تولید کند.

فرض کنید یک وب‌سایت برای نمایش نام کاربر چنین ساختار مفهومی داشته باشد:

Template ثابت:
سلام [نام کاربر]، به حساب خود خوش آمدید.

Data:
نام کاربر = علی

برنامه قالب ثابت را نگه می‌دارد و مقدار «علی» را به‌عنوان داده در محل تعریف‌شده قرار می‌دهد. در این مدل، نام کاربر قرار نیست به‌عنوان دستور برنامه‌نویسی یا عبارت Template تفسیر شود.

مشکل زمانی آغاز می‌شود که معماری برنامه به شکلی باشد که داده قابل‌کنترل توسط کاربر ابتدا وارد متن Template شود و سپس کل محتوای ساخته‌شده توسط Template Engine تفسیر شود.

در این حالت مرز مهم میان «Data» و «Template Code» از بین می‌رود.

MITRE این دسته از ضعف‌ها را در CWE-1336 با عنوان Improper Neutralization of Special Elements Used in a Template Engine تعریف می‌کند. در این ضعف، داده‌ای که از منبع خارجی تأثیر می‌پذیرد می‌تواند شامل عناصری شود که موتور Template آنها را به‌عنوان Expression یا Directive تفسیر کند.

OWASP نیز SSTI را در Web Security Testing Guide تحت دسته Injection بررسی می‌کند و موتورهایی مانند Jinja2، Twig و FreeMarker را از نمونه‌های فناوری‌هایی می‌داند که در صورت استفاده نادرست ممکن است در معرض چنین مشکلی قرار بگیرند.

بنابراین SSTI صرفاً مشکل «نمایش اشتباه یک متن» نیست؛ مشکل اصلی این است که ورودی غیرقابل‌اعتماد وارد محیطی شده که قابلیت تفسیر دستور دارد. Template Engine چگونه کار می‌کند؟

Template Engine چگونه کار می‌کند؟

Template Engine یا موتور قالب‌ساز ابزاری است که به توسعه‌دهنده اجازه می‌دهد ساختار نمایش داده را از بخش‌های دیگر برنامه جدا کند.

برای مثال، یک سیستم فروشگاهی می‌تواند یک قالب ثابت برای ایمیل تأیید سفارش داشته باشد و اطلاعاتی مانند نام مشتری، شماره سفارش، مبلغ و تاریخ خرید را هنگام ارسال ایمیل داخل آن قرار دهد.

در معماری صحیح، دو بخش کاملاً از یکدیگر جدا هستند:

بخشوظیفه
Templateتعیین ساختار و منطق مجاز نمایش
Dataمقادیری مانند نام، مبلغ، عنوان یا تاریخ
Template Engineترکیب Template و Data
Outputصفحه، ایمیل یا محتوای نهایی

این تفکیک از نظر امنیتی بسیار مهم است.

اگر برنامه فقط داده را در یک Template از قبل تعریف‌شده قرار دهد، کاربر نباید بتواند ساختار اجرایی قالب را تغییر دهد.

اما بعضی Template Engineها قابلیت‌هایی بسیار فراتر از جایگزینی ساده متن دارند. بسته به موتور مورد استفاده، ممکن است امکاناتی مانند شرط، حلقه، Filter، Function، دسترسی به Propertyها و Objectها یا سایر قابلیت‌های برنامه‌نویسی وجود داشته باشد.

همین قدرت باعث می‌شود اشتباه در نحوه استفاده از Template Engine خطرناک باشد.

هرچه موتور Template امکانات بیشتری در اختیار قالب قرار دهد، اهمیت جداسازی Template از داده و محدود کردن Context بیشتر می‌شود. آسیب‌پذیری SSTI چگونه ایجاد می‌شود؟

آسیب‌پذیری SSTI چگونه ایجاد می‌شود؟

ریشه بیشتر آسیب‌پذیری‌های Server-Side Template Injection را می‌توان در یک اشتباه معماری خلاصه کرد:

«برنامه به کاربر اجازه می‌دهد روی Template Source تأثیر بگذارد.»

این اتفاق ممکن است به‌صورت مستقیم یا غیرمستقیم رخ دهد.

برای مثال فرض کنید برنامه قرار است یک پیام خوشامدگویی تولید کند.

طراحی امن به‌شکل مفهومی چنین است:

Template ثابت → Template Engine
                    ↑
                User Data

در این معماری، داده کاربر صرفاً یک Variable است.

اما معماری پرخطر می‌تواند چنین باشد:

User Input
    ↓
ساخت یا تغییر Template
    ↓
Template Engine
    ↓
Output

در حالت دوم، داده قابل‌کنترل توسط کاربر قبل از مرحله پردازش وارد خود قالب شده است.

PortSwigger نیز در توضیح SSTI تأکید می‌کند که یکی از الگوهای اصلی ایجاد این ضعف، ترکیب مستقیم ورودی کاربر با Template به‌جای ارسال آن به‌عنوان داده است. این اشتباه ممکن است باعث شود دستورات Template توسط موتور سمت سرور پردازش شوند.

تفاوت میان داده و Template Code

یکی از بهترین روش‌های ذهنی برای تشخیص خطر SSTI این سؤال است:

«آیا کاربر فقط مقدار یک متغیر را کنترل می‌کند یا می‌تواند روی متن قابل‌تفسیر توسط Template Engine تأثیر بگذارد؟»

کنترل مقدار یک متغیر لزوماً به معنی SSTI نیست.

اما اگر داده کاربر به Template Source تبدیل شود، سطح خطر کاملاً تغییر می‌کند.

فرض کنید یک سیستم ایمیل دارای قالب ثابت زیر باشد:

سلام [customer_name]
سفارش شما ثبت شد.

اگر customer_name صرفاً به‌عنوان Variable وارد شود، ساختار Template ثابت باقی می‌ماند.

ولی اگر توسعه‌دهنده ابتدا متن قابل‌کنترل توسط کاربر را به رشته Template اضافه کند و سپس رشته نهایی را Compile یا Render کند، مرز میان داده و دستور از بین رفته است.

این دقیقاً همان مرزی است که در Code Review باید به آن توجه شود. چرا SSTI می‌تواند یک آسیب‌پذیری بسیار جدی باشد؟

چرا SSTI می‌تواند یک آسیب‌پذیری بسیار جدی باشد؟

تمام موارد SSTI شدت یکسانی ندارند.

شدت آسیب‌پذیری به عوامل متعددی وابسته است:

نوع Template Engine، قابلیت‌های زبان Template، Objectهایی که در Context قرار گرفته‌اند، تنظیمات Sandbox، سطح دسترسی Process برنامه، معماری سیستم و محدودیت‌های محیط اجرا همگی روی پیامد نهایی تأثیر دارند.

PortSwigger شدت معمول SSTI را بالا در نظر می‌گیرد، اما هم‌زمان تأکید می‌کند که پیامد واقعی آن به موتور Template و نحوه استفاده برنامه بستگی دارد. در موارد پرخطر، Template Injection می‌تواند امنیت داده و عملکرد برنامه و حتی خود سرور را تحت تأثیر قرار دهد.

افشای اطلاعات حساس

اگر Template Environment به اطلاعات بیشتری از آنچه برای رندر لازم است دسترسی داشته باشد، یک ضعف SSTI ممکن است مسیر مشاهده اطلاعات حساس را ایجاد کند.

این اطلاعات بسته به معماری سیستم می‌تواند شامل مواردی مانند تنظیمات برنامه، داده‌های داخلی یا Objectهایی باشد که نباید در دسترس Template قرار می‌گرفتند.

به همین دلیل یکی از اصول مهم Hardening آن است که Template فقط اطلاعات ضروری را دریافت کند.

مستندات رسمی Jinja نیز توصیه می‌کند هنگام استفاده از محیط‌های Template، تنها داده‌های مرتبط در اختیار Template قرار بگیرند و از ارسال Objectهای غیرضروری، به‌خصوص Objectهایی که Method دارای Side Effect دارند، خودداری شود.

تغییر خروجی برنامه

در مواردی که مهاجم بتواند Expressionهای Template را کنترل کند، احتمال تغییر محتوای تولیدشده توسط برنامه وجود دارد.

در یک سیستم تولید ایمیل، این مسئله می‌تواند روی محتوای ایمیل اثر بگذارد.

در یک سیستم تولید صفحات وب، ممکن است خروجی صفحه تحت تأثیر قرار بگیرد.

این اثر به‌تنهایی نیز می‌تواند از نظر Integrity یا یکپارچگی اطلاعات مشکل امنیتی مهمی محسوب شود.

دسترسی به قابلیت‌های داخلی برنامه

برخی Template Engineها مجموعه‌ای از Functionها، Filterها، Propertyها و Objectها را در اختیار Template قرار می‌دهند.

اگر Environment بیش از حد قدرتمند باشد، یک SSTI ممکن است به مهاجم اجازه دهد به بخش‌هایی از Application Runtime دسترسی پیدا کند که اساساً برای کاربر طراحی نشده‌اند.

به همین دلیل محدود کردن سطح دسترسی Template اهمیت زیادی دارد.

اجرای کد از راه دور

یکی از جدی‌ترین پیامدهایی که در برخی ترکیب‌های آسیب‌پذیر امکان‌پذیر است Remote Code Execution یا RCE است.

RCE یعنی مهاجم بتواند از طریق ضعف موجود، کدی را در محیط سرور اجرا کند.

این نتیجه برای تمام آسیب‌پذیری‌های SSTI اتفاق نمی‌افتد، اما علت اصلی حساسیت بالای متخصصان امنیت نسبت به این دسته از ضعف‌ها همین احتمال است.

OWASP در توضیح SSTI به خطر اجرای کد در سمت سرور اشاره می‌کند و تحقیقات PortSwigger نیز نشان داده‌اند که برخی Template Engineهای قدرتمند در شرایط آسیب‌پذیر می‌توانند به پیامدهای بسیار جدی منتهی شوند.

SSTI در چه بخش‌هایی از سایت ممکن است دیده شود؟

SSTI فقط به صفحه اصلی یا فرم تماس محدود نیست.

هر جایی که سیستم از Template Engine برای تولید محتوای پویا استفاده کند و داده قابل‌کنترل توسط کاربر وارد فرایند ساخت Template شود، باید بررسی شود.

یکی از نمونه‌های مهم سیستم‌های تولید ایمیل است.

یک پلتفرم ممکن است برای ساخت ایمیل خوشامدگویی، بازیابی رمز عبور، فاکتور، خبرنامه یا اعلان از Template استفاده کند.

اگر کاربران یا مدیران سطح پایین اجازه ویرایش Template داشته باشند، باید مشخص شود این محتوا در چه محیطی پردازش می‌شود.

CMSها و سامانه‌هایی که قابلیت ساخت صفحات سفارشی دارند نیز می‌توانند نیازمند بررسی باشند.

همچنین قابلیت‌های زیر از نظر معماری ارزش بررسی بیشتری دارند:

سیستم تولید گزارش، سیستم صدور فاکتور، قالب پیامک، قالب اعلان، Wiki، صفحه‌ساز، سیستم Marketing Automation، تولید PDF، پنل سفارشی‌سازی قالب، سیستم Ticket و ماژول‌های تولید محتوای پویا.

وجود این قابلیت‌ها به معنی آسیب‌پذیر بودن سایت نیست.

موضوع اصلی نحوه انتقال داده قابل‌کنترل به Template Engine است.

چه موتورهایی ممکن است در بحث SSTI مطرح باشند؟

آسیب‌پذیری SSTI به یک زبان یا Framework خاص محدود نیست.

MITRE در توضیح CWE-1336 به فناوری‌ها و Template Engineهای مختلفی از جمله Jinja2، Twig، Pug، Java Server Pages، FreeMarker، Velocity، ColdFusion و Smarty اشاره می‌کند.

برخی نمونه‌های شناخته‌شده را می‌توان به‌شکل زیر در نظر گرفت:

Template Engineاکوسیستم رایج
JinjaPython
TwigPHP
FreeMarkerJava
VelocityJava
SmartyPHP
PugJavaScript / Node.js

وجود هر یک از این موتورهای Template به معنی وجود SSTI نیست.

یک Template Engine می‌تواند سال‌ها در یک برنامه استفاده شود بدون آنکه چنین ضعفی ایجاد کند.

مشکل زمانی است که Trust Boundary به‌درستی رعایت نشود و داده غیرقابل‌اعتماد قابلیت تأثیرگذاری روی Template Code پیدا کند. تفاوت SSTI با XSS چیست؟

تفاوت SSTI با XSS چیست؟

SSTI گاهی با Cross-Site Scripting یا XSS اشتباه گرفته می‌شود، زیرا هر دو ممکن است ابتدا از طریق یک فیلد ورودی کاربر دیده شوند.

اما محل تفسیر و هدف آنها متفاوت است.

در XSS، مسئله اصلی این است که داده کنترل‌شده توسط مهاجم به شکلی وارد خروجی شود که مرورگر قربانی آن را به‌عنوان کد Client-Side تفسیر کند.

اما در Server-Side Template Injection، پردازش آسیب‌پذیر در سمت سرور و داخل Template Engine اتفاق می‌افتد.

ویژگیSSTIXSS
محل اصلی پردازشسرورمرورگر کاربر
مؤلفه آسیب‌پذیرTemplate EngineHTML/DOM/JavaScript Context
هدف اصلی حملهمحیط Template و سرورSession یا محیط مرورگر
احتمال RCE سروردر برخی شرایط وجود داردمعمولاً هدف مستقیم XSS نیست
دفاع اصلیجداسازی Template و DataContext-Aware Output Encoding و کنترل ورودی

این تفاوت بسیار مهم است.

ممکن است توسعه‌دهنده خروجی HTML را Escape کند و تصور کند مشکل حل شده است، درحالی‌که اگر Expression قبل از مرحله Escape توسط Template Engine پردازش شده باشد، کنترل HTML Encoding به‌تنهایی ریشه SSTI را برطرف نمی‌کند.

بنابراین دفاع در برابر XSS و SSTI هرچند ممکن است نقاط مشترکی داشته باشد، اما یکسان نیست.

تفاوت SSTI با SQL Injection چیست؟

SQL Injection زمانی ایجاد می‌شود که داده قابل‌کنترل توسط کاربر وارد ساختار Query دیتابیس شود و مرز میان «داده» و «دستور SQL» از بین برود.

SSTI نیز از نظر مفهومی شباهت جالبی دارد.

در SSTI مرز میان «داده» و «Template Expression» شکسته می‌شود.

ویژگیSSTISQL Injection
InterpreterTemplate EngineDatabase Engine
محل InjectionTemplateQuery
داده‌ای که نباید دستور شودUser InputUser Input
راهکار معماری اصلیTemplate ثابت + VariableParameterized Query
پیامد احتمالیافشای داده تا RCE بسته به محیطدستکاری یا افشای دیتابیس و سایر پیامدها

در SQL Injection استفاده از Parameterized Query یکی از کنترل‌های بنیادی است.

در SSTI نیز یک اصل مشابه وجود دارد: داده باید به‌عنوان داده به Template داده شود، نه اینکه برای ساخت Template Source از آن استفاده شود.

تفاوت SSTI با OS Command Injection

در Command Injection ورودی غیرقابل‌اعتماد وارد دستوری می‌شود که قرار است توسط Shell یا سیستم‌عامل پردازش شود.

اما در SSTI Interpreter اولیه Template Engine است.

این نکته به این معنی نیست که اثر SSTI همیشه محدود به Template Engine می‌ماند. اگر محیط Template به قابلیت‌های قدرتمند Runtime دسترسی داشته باشد، در شرایط آسیب‌پذیر ممکن است دامنه اثر گسترده‌تر شود.

از دید توسعه‌دهنده، اصل دفاعی در هر دو مورد مشابه است:

نباید اجازه داد داده غیرقابل‌اعتماد به بخش اجرایی یک Interpreter تبدیل شود.

تفاوت SSTI و SSI Injection چیست؟

شباهت نام Server-Side Template Injection و Server-Side Include Injection گاهی باعث سردرگمی می‌شود.

SSI Injection مربوط به دستورهای Server-Side Includes است که وب‌سرور یا مؤلفه مربوطه پردازش می‌کند.

در مقابل، SSTI مربوط به Template Engine برنامه است.

PortSwigger نیز SSI Injection را به‌صورت جداگانه طبقه‌بندی می‌کند و آن را حالتی می‌داند که داده کنترل‌شده توسط کاربر وارد محتوایی شود که بعداً برای Server-Side Include Directiveها پردازش می‌شود.

بنابراین SSTI و SSI Injection با وجود شباهت اسمی دو ضعف متفاوت هستند.

SSTI چگونه شناسایی می‌شود؟

در یک ارزیابی امنیتی حرفه‌ای، هدف نباید صرفاً وارد کردن رشته‌های مختلف در فیلدهای سایت باشد.

رویکرد بهتر این است که ابتدا معماری برنامه درک شود.

تیم امنیت باید بداند کدام Endpointها از Template Engine استفاده می‌کنند، داده از کجا می‌آید، Template چگونه ساخته می‌شود و در نهایت چه تابعی آن را Render یا Compile می‌کند.

شناسایی از طریق Code Review

Code Review یکی از ارزشمندترین روش‌ها برای پیدا کردن SSTI است.

در بررسی کد باید مسیر Data Flow از Source تا Sink دنبال شود.

Source می‌تواند Request Parameter، Form، API Body، Database Field قابل‌کنترل توسط کاربر یا داده دریافتی از سیستم خارجی باشد.

Sink جایی است که یک Template ساخته یا Render می‌شود.

مسئله مهم آن است که ببینیم آیا داده غیرقابل‌اعتماد صرفاً Variable است یا روی Template Source اثر می‌گذارد.

MITRE نیز Static Application Security Testing یا SAST را یکی از روش‌هایی معرفی می‌کند که می‌تواند برخی نمونه‌های CWE-1336 را با مدل‌سازی جریان داده و پیدا کردن مسیر Source-to-Sink شناسایی کند.

بررسی فراخوانی‌های Template Engine

در Code Review باید توابعی که Template را از String، فایل یا Database دریافت می‌کنند مشخص شوند.

سپس باید منشأ محتوای ورودی آنها بررسی شود.

یک تابع Render به خودی خود آسیب‌پذیر نیست.

سؤال اصلی این است:

Template از کجا آمده است؟

اگر Template یک فایل ثابت کنترل‌شده توسط توسعه‌دهنده است و داده‌های کاربر به‌عنوان Variable در اختیار آن قرار می‌گیرند، مدل بسیار امن‌تری داریم.

اگر خود Template از یک فیلد قابل‌کنترل توسط کاربر دریافت شود، بررسی امنیتی دقیق‌تری لازم است.

تست پویا در محیط مجاز

در Dynamic Testing یا تست پویا نیز امکان بررسی رفتار Template Engine وجود دارد.

اما این کار باید فقط روی سامانه‌ای انجام شود که مالک آن هستید یا مجوز صریح تست آن را دارید.

در محیط Staging می‌توان از ورودی‌های کاملاً بی‌خطر استفاده کرد تا مشخص شود آیا یک مقدار صرفاً به‌عنوان Text نمایش داده می‌شود یا موتور Template تلاش می‌کند آن را تفسیر کند.

هدف این مرحله اثبات تفاوت بین Data و Template Evaluation است، نه اجرای دستور یا دسترسی به سیستم.

در یک تست حرفه‌ای دفاعی، به محض آنکه مشخص شد داده غیرقابل‌اعتماد توسط Template Engine تفسیر می‌شود، می‌توان یافته را ثبت و وارد مرحله Remediation کرد؛ برای اثبات آسیب‌پذیری نیازی به گسترش تست به سمت تخریب، دسترسی غیرمجاز یا اجرای کد نیست.

نشانه‌های احتمالی SSTI در یک برنامه

تشخیص SSTI فقط از روی ظاهر سایت آسان نیست.

با این حال برخی الگوهای معماری می‌توانند نیاز به بررسی بیشتر را نشان دهند.

برای مثال، وجود قابلیت «ساخت Template سفارشی» یکی از نقاطی است که باید Trust Model آن دقیق بررسی شود.

اگر کاربر می‌تواند قالب ایمیل یا گزارش بسازد، این پرسش مطرح می‌شود که آیا قالب ایجادشده در یک محیط محدود رندر می‌شود یا مانند یک Template مورد اعتماد در اختیار موتور قرار می‌گیرد.

Error Messageهای مربوط به Template Engine نیز می‌توانند نشانه‌ای از وجود مسیر Template Evaluation باشند.

البته مشاهده نام Jinja، Twig یا FreeMarker در خطا به معنی وجود SSTI نیست. این موضوع فقط نشان می‌دهد که باید جریان داده بررسی شود.

خطاهای Parse مربوط به Template نیز ممکن است سرنخ ایجاد کنند.

ولی متخصص امنیت نباید فقط براساس Error Message نتیجه قطعی بگیرد.

اثبات صحیح نیازمند بررسی مسیر ورود داده و نحوه پردازش آن است.

چرا Escape کردن HTML برای جلوگیری از SSTI کافی نیست؟

یکی از اشتباهات رایج در برخورد با SSTI این است که توسعه‌دهنده تصور می‌کند HTML Escaping مشکل را حل می‌کند.

HTML Escaping برای مقابله با گروهی از مشکلات خروجی، به‌خصوص XSS، بسیار مهم است.

اما SSTI در لایه دیگری اتفاق می‌افتد.

اگر Template Engine ابتدا داده را به‌عنوان Template Expression تفسیر کند و سپس خروجی HTML تولید شود، Escape کردن مرحله نهایی الزاماً جلوی تفسیر Template را نمی‌گیرد.

بنابراین باید دو سؤال جدا پرسیده شود:

آیا داده قبل از Render می‌تواند به Template Code تبدیل شود؟

و آیا خروجی نهایی برای Context مقصد به‌درستی Encode شده است؟

پاسخ به سؤال دوم جای سؤال اول را نمی‌گیرد.

یک برنامه ممکن است در برابر XSS خروجی مناسبی Encode کند اما همچنان از نظر SSTI طراحی ناامنی داشته باشد. روش اصلی جلوگیری از Server-Side Template Injection

روش اصلی جلوگیری از Server-Side Template Injection

مهم‌ترین راهکار پیشگیری بسیار ساده به نظر می‌رسد، اما در عمل حیاتی است:

ورودی کاربر را به Template تبدیل نکنید.

Template باید توسط توسعه‌دهنده یا منبع کاملاً مورد اعتماد تعریف شود.

داده کاربر باید به‌عنوان Variable به آن ارسال شود.

PortSwigger نیز در توصیه‌های Remediation خود بیان می‌کند که در صورت امکان نباید Template از ورودی کاربر ساخته شود و ارسال ورودی به Template به‌عنوان Parameter معمولاً جایگزین امن‌تری است.

از دید معماری می‌توان این اصل را چنین خلاصه کرد:

روش مناسب:

Fixed Template
     +
Untrusted Data as Variables
     ↓
Template Engine
     ↓
Output

نه:

Untrusted Data
     ↓
Template Source
     ↓
Template Engine

این تفاوت کوچک ظاهری، مرز اصلی میان طراحی امن و طراحی مستعد SSTI است.

اگر کاربران واقعاً باید Template بسازند چه کنیم؟

گاهی Business Requirement ایجاب می‌کند که کاربران قالب سفارشی بسازند.

برای مثال یک سامانه SaaS بازاریابی ممکن است به مشتری اجازه دهد Template ایمیل اختصاصی طراحی کند.

در این حالت نمی‌توان همیشه Templateهای کاربر را به‌طور کامل حذف کرد.

اما معماری امنیتی باید تغییر کند.

اولین تصمیم این است که آیا واقعاً به یک Template Engine کامل نیاز داریم یا خیر.

اگر نیازهای سیستم فقط شامل جایگزینی چند Placeholder ساده باشد، استفاده از زبان محدودتر می‌تواند Attack Surface را کاهش دهد.

PortSwigger پیشنهاد می‌کند در مواردی که Template قابل‌کنترل توسط کاربر یک الزام واقعی است، استفاده از موتورهای ساده‌تر و Logic-Less را بررسی کنید یا راهنمای Hardening موتور انتخاب‌شده را اجرا کنید.

هرچه زبان Template قدرت کمتری داشته باشد، قابلیت سوءاستفاده نیز معمولاً محدودتر می‌شود.

البته این مسئله جای Secure Design را نمی‌گیرد.

Sandbox در جلوگیری از SSTI چه نقشی دارد؟

Sandbox محیطی است که تلاش می‌کند قابلیت‌های در دسترس Template را محدود کند.

برای نمونه ممکن است دسترسی به Attributeهای خاص، Functionها، Methodها یا عملیات معینی را مسدود کند.

Jinja دارای SandboxedEnvironment است که برای کنترل عملیات در Templateهای غیرقابل‌اعتماد طراحی شده است.

اما مستندات رسمی Jinja صراحتاً هشدار می‌دهند که Sandbox به‌تنهایی یک راهکار امنیتی کامل نیست.

Jinja توصیه می‌کند علاوه بر Sandbox، داده‌های در دسترس Template محدود شوند و محدودیت‌هایی روی منابعی مانند CPU و Memory نیز وجود داشته باشد، زیرا حتی یک Template محدود ممکن است باعث مصرف بیش از اندازه منابع شود.

Twig نیز دارای Sandbox است.

مستندات Twig می‌گویند Template Source در حالت عادی Trusted Code محسوب می‌شود و اگر برنامه قرار است Template دریافت‌شده از کاربر غیرقابل‌اعتماد را اجرا کند، باید Sandbox مناسب فعال و پیکربندی شود. Sandbox در Twig امکان تعریف Allowlist برای قابلیت‌های مجاز را فراهم می‌کند.

بنابراین Sandbox باید بخشی از Defense in Depth باشد، نه تنها خط دفاع.

اصل Least Privilege در مقابله با SSTI

فرض کنید یک آسیب‌پذیری در Application Layer وجود داشته باشد.

شدت نهایی حادثه تا حد زیادی به سطح دسترسی همان Application بستگی خواهد داشت.

اگر Process برنامه با دسترسی بسیار بالا اجرا شود، خطای Application می‌تواند اثر بسیار بیشتری داشته باشد.

اما اگر Process فقط به فایل‌ها، سرویس‌ها و منابع موردنیاز خودش دسترسی داشته باشد، Blast Radius کاهش پیدا می‌کند.

بنابراین Least Privilege یا اصل حداقل دسترسی یکی از کنترل‌های مهم در کنار اصلاح خود SSTI است.

حساب کاربری سرویس وب نباید دسترسی مدیریتی غیرضروری داشته باشد.

دسترسی فایل‌ها باید حداقلی باشد.

Credentialهای غیرضروری نباید در اختیار Process قرار بگیرند.

دسترسی شبکه‌ای برنامه به سرویس‌های داخلی نیز باید براساس نیاز واقعی طراحی شود.

این کنترل‌ها SSTI را برطرف نمی‌کنند، اما می‌توانند پیامد یک ضعف ناشناخته یا Zero-Day را محدود کنند.

Context موتور Template را محدود کنید

یکی از مهم‌ترین نکات امنیتی که گاهی نادیده گرفته می‌شود، مقدار داده و Objectهایی است که در اختیار Template قرار می‌گیرند.

فرض کنید Template فقط به نام مشتری و مبلغ فاکتور نیاز دارد.

در چنین شرایطی منطقی نیست کل Object مربوط به User، Application، Configuration یا Database در اختیار Template قرار بگیرد.

هر Object اضافی سطح حمله بیشتری ایجاد می‌کند.

روش بهتر آن است که یک Data Transfer Object یا ساختار داده بسیار محدود ساخته شود که فقط اطلاعات موردنیاز Template را شامل شود.

برای مثال:

Template Context:
- customer_name
- order_number
- order_total

به‌جای:

Template Context:
- entire_application_object
- database_object
- configuration_object
- user_session_object

حتی اگر Sandbox فعال باشد، Context کوچک‌تر و ساده‌تر طراحی امن‌تری محسوب می‌شود.

Allowlist بهتر از Blocklist است

در طراحی سیستم Template قابل‌تنظیم، ممکن است توسعه‌دهنده تلاش کند چند کلمه یا Pattern خطرناک را مسدود کند.

این مدل Blocklist در بسیاری از موارد شکننده است.

Template Engineها Syntaxهای پیچیده‌ای دارند و نسخه‌های جدید ممکن است قابلیت‌های تازه‌ای اضافه کنند.

راه امن‌تر آن است که دقیقاً مشخص شود چه قابلیت‌هایی مجاز هستند.

برای مثال اگر یک سیستم ایمیل فقط باید اجازه استفاده از نام، تاریخ و شماره سفارش را بدهد، همین موارد را در Allowlist قرار دهید.

هر چیزی خارج از آن باید غیرقابل‌دسترسی باشد.

این رویکرد با مفهوم Deny by Default هم‌راستا است: قابلیت‌ها به‌صورت پیش‌فرض ممنوع باشند مگر اینکه دلیل مشخصی برای فعال بودن آنها وجود داشته باشد.

محدودیت CPU، Memory و زمان اجرا

امنیت Template فقط به اجرای کد محدود نیست.

حتی یک Template که امکان دسترسی به سیستم‌عامل ندارد ممکن است بتواند حجم بسیار زیادی خروجی ایجاد کند یا پردازش سنگینی تحمیل کند.

مستندات Jinja نیز این موضوع را مطرح می‌کنند و توصیه می‌کنند محدودیت منابع مانند CPU و Memory برای محیط رندر در نظر گرفته شود.

در سامانه‌هایی که کاربران Template سفارشی ایجاد می‌کنند، موارد زیر اهمیت ویژه دارند:

محدودیت زمان Render، محدودیت حجم خروجی، محدودیت Memory، محدودیت اندازه Template و کنترل تعداد عملیات قابل انجام.

اگر معماری اجازه دهد، اجرای Templateهای غیرقابل‌اعتماد در Process یا Environment جداگانه نیز می‌تواند Isolation بیشتری فراهم کند.

آیا WAF می‌تواند SSTI را متوقف کند؟

Web Application Firewall یا WAF می‌تواند بخشی از Defense in Depth باشد، اما نباید درمان اصلی SSTI محسوب شود.

WAF می‌تواند برخی الگوهای شناخته‌شده یا Requestهای مشکوک را شناسایی کند.

اما مشکل اصلی SSTI در Architecture برنامه قرار دارد.

اگر برنامه به کاربر اجازه دهد Template Code تولید کند، مسدود کردن چند Pattern خاص در WAF مشکل طراحی را از بین نمی‌برد.

Template Engineها نیز Syntax یکسانی ندارند.

بنابراین Ruleای که برای یک موتور مناسب است الزاماً برای موتور دیگر کارایی ندارد.

همچنین Blocklistهای سطح HTTP ممکن است با Encoding، Contextهای مختلف یا تغییرات Syntax مواجه شوند.

راهکار اصلی همچنان اصلاح Code و Trust Boundary است.

WAF باید لایه تکمیلی محسوب شود، نه جایگزین Remediation.

نقش SAST، DAST و Code Review در پیدا کردن SSTI

هیچ ابزار واحدی تضمین نمی‌کند تمام SSTIها را پیدا کند.

بهترین روش ترکیبی از چند تکنیک است.

SAST می‌تواند جریان داده را در Source Code بررسی کند و مسیرهایی را که داده کاربر به APIهای Template می‌رسد پیدا کند.

DAST می‌تواند رفتار برنامه در Runtime را بررسی کند.

Code Review دستی نیز برای درک Business Logic و تشخیص اینکه یک مقدار واقعاً Data است یا Template Source اهمیت زیادی دارد.

یک ارزیابی بالغ معمولاً این سه لایه را در کنار هم قرار می‌دهد.

ابزار خودکار ممکن است یک مسیر مشکوک پیدا کند، اما توسعه‌دهنده یا AppSec Engineer باید مشخص کند آیا ورودی واقعاً قابل‌کنترل است و در چه Contextی پردازش می‌شود.

از طرف دیگر، بعضی SSTIها ممکن است در قابلیت‌های خاص مانند قالب ایمیل یا گزارش رخ دهند که Scanner عمومی به‌راحتی به آنها دسترسی ندارد.

بنابراین Inventory کامل Featureهای دارای Template اهمیت زیادی دارد. چک‌لیست دفاعی جلوگیری از SSTI

چک‌لیست دفاعی جلوگیری از SSTI

برای بررسی امنیت یک سیستم می‌توان از این چک‌لیست استفاده کرد:

  • Template Source فقط از منابع مورد اعتماد دریافت شود؛ ورودی کاربر به‌عنوان Variable ارسال شود؛ تمام محل‌های Render و Compile در Codebase شناسایی شوند؛ Data Flow از Request، API و Database تا Template Engine بررسی شود؛ Templateهای قابل‌ویرایش توسط کاربر به‌صورت Untrusted در نظر گرفته شوند؛ در صورت نیاز واقعی به Template کاربر از Sandbox رسمی و Allowlist استفاده شود؛ تنها داده‌های ضروری وارد Template Context شوند؛ Objectهای قدرتمند، Serviceها و Configurationهای غیرضروری در اختیار Template قرار نگیرند؛ Process برنامه با Least Privilege اجرا شود؛ برای Templateهای غیرقابل‌اعتماد محدودیت CPU، Memory، زمان اجرا و اندازه خروجی اعمال شود؛ Errorهای Template بدون افشای Stack Trace و اطلاعات حساس مدیریت شوند؛ تست‌های امنیتی در CI/CD قرار گیرند؛ وابستگی‌ها و Template Engine به‌روز نگه داشته شوند؛ WAF فقط به‌عنوان لایه مکمل استفاده شود؛ قابلیت‌های Template سفارشی به‌صورت دوره‌ای Code Review شوند؛ Logging و Monitoring برای خطاها و رفتارهای غیرمعمول Template فعال باشد.

اشتباهات رایج توسعه‌دهندگان در مواجهه با SSTI

اعتماد به HTML Escaping

یکی از پرتکرارترین اشتباهات، یکسان دانستن SSTI با XSS است.

HTML Escaping برای XSS اهمیت زیادی دارد اما مشکل Template Evaluation را الزاماً حل نمی‌کند.

دفاع باید در نقطه‌ای انجام شود که مشخص می‌کند چه چیزی Template است و چه چیزی Data.

ساخت Template با String Concatenation

ساختن Template به‌وسیله ترکیب رشته ثابت و ورودی کاربر یک Anti-Pattern مهم است.

اگر نتیجه این ترکیب دوباره توسط Template Engine پردازش شود، احتمال ایجاد SSTI افزایش پیدا می‌کند.

ارسال کل Object برنامه به Template

گاهی برای راحتی توسعه، Objectهای بسیار بزرگ در Template Context قرار می‌گیرند.

این کار دسترسی Template را بیش از نیاز واقعی افزایش می‌دهد.

Context باید حداقلی باشد.

تصور اینکه Sandbox همه چیز را حل می‌کند

Sandbox یک کنترل امنیتی مهم است، اما نباید تنها کنترل باشد.

خود مستندات Jinja نیز تأکید می‌کنند Sandbox امنیت کامل را تضمین نمی‌کند و کنترل داده و منابع همچنان ضروری است.

استفاده از Blacklist

مسدود کردن چند کلمه، Function یا Character خاص معمولاً Secure Design محسوب نمی‌شود.

Allowlist قابلیت‌های ضروری قابل‌اعتمادتر است.

اجرای Application با دسترسی زیاد

یک ضعف Application اگر با Process دارای دسترسی بسیار بالا ترکیب شود، پیامد بسیار شدیدتری پیدا می‌کند.

Least Privilege باید حتی در برنامه‌ای که تصور می‌کنید SSTI ندارد رعایت شود.

نادیده گرفتن Templateهای ایمیل و گزارش

تیم‌ها معمولاً صفحات HTML اصلی سایت را بررسی می‌کنند اما Email Template، PDF Template، Report Generator و Notification System را فراموش می‌کنند.

SSTI می‌تواند در هر جایی که Template Engine وجود دارد ظاهر شود.

اگر در سایت SSTI پیدا شد چه اقداماتی انجام دهیم؟

اولین کار باید محدود کردن سطح خطر باشد.

اگر آسیب‌پذیری مربوط به قابلیت اختیاری مانند Template سفارشی است، تا زمان اصلاح می‌توان آن قابلیت را غیرفعال یا دسترسی به آن را محدود کرد.

سپس Data Flow باید مشخص شود.

باید بدانیم ورودی از کجا وارد شده، کجا ذخیره شده و در کدام Template API پردازش شده است.

بعد از آن باید معماری اصلاح شود تا ورودی به‌عنوان Variable وارد Template ثابت شود.

اگر Template کاربر یک نیاز تجاری واقعی است، باید Sandbox، Allowlist، محدودیت Context و Isolation به‌شکل صحیح طراحی شوند.

اما اصلاح Code پایان کار نیست.

اگر شواهدی وجود دارد که آسیب‌پذیری قبلاً مورد سوءاستفاده قرار گرفته است، موضوع باید به‌عنوان Incident احتمالی بررسی شود.

Logهای Application، Reverse Proxy، WAF، سیستم‌عامل و سرویس‌های مرتبط باید تحلیل شوند.

Credentialهایی که Process آسیب‌پذیر امکان دسترسی به آنها داشته است باید در Scope بررسی قرار گیرند.

در صورت وجود احتمال دسترسی غیرمجاز، Rotation کلیدها، Tokenها و Passwordهای مرتبط می‌تواند ضروری باشد.

همچنین باید بررسی شود آیا فایل‌ها یا Configurationهای سیستم تغییر کرده‌اند یا خیر.

در رخدادهای جدی، صرفاً Patch کردن Endpoint بدون Incident Response کافی نیست.

Logging مناسب برای شناسایی تلاش‌های SSTI

Logging می‌تواند به تیم امنیت در شناسایی رفتار غیرعادی کمک کند.

با این حال نباید داده حساس یا Credentialها وارد Log شوند.

رویدادهای مفیدی که می‌توان ثبت کرد شامل Errorهای Template، افزایش غیرمعمول Template Compilation، Templateهای ردشده توسط Sandbox، افزایش زمان Render و تغییرات Templateهای ذخیره‌شده هستند.

در سامانه‌هایی که Template کاربر ذخیره می‌شود، Audit Log اهمیت زیادی دارد.

باید مشخص باشد چه کاربری چه Templateای را در چه زمانی ایجاد یا ویرایش کرده است.

تغییرات حساس بهتر است دارای Version History باشند.

این اطلاعات در زمان Incident Response ارزش بسیار زیادی پیدا می‌کنند.

SSTI و اصل Defense in Depth

یکی از مهم‌ترین درس‌های امنیت وب این است که نباید یک کنترل منفرد را شکست‌ناپذیر فرض کرد.

برای مقابله با SSTI نیز چند لایه امنیتی لازم است.

لایه اول Secure Design است: کاربر نباید Template Source را کنترل کند.

لایه دوم محدود کردن Context است.

لایه سوم Sandbox و Allowlist در مواردی است که Template غیرقابل‌اعتماد یک نیاز واقعی است.

لایه چهارم Least Privilege و Isolation در سطح Application و سیستم‌عامل است.

لایه پنجم Resource Limiting است.

لایه ششم Logging، Monitoring و Detection است.

و لایه‌های تکمیلی می‌توانند شامل WAF، SAST، DAST، Dependency Management و Code Review باشند.

این معماری باعث می‌شود حتی در صورت شکست یک کنترل، کنترل‌های دیگر بتوانند شدت حادثه را کاهش دهند.

SSTI در محیط‌های Microservice و Cloud

در معماری‌های جدید، یک سرویس آسیب‌پذیر الزاماً یک سرور سنتی مجزا نیست.

ممکن است Template Rendering داخل Container، Function، Pod یا Microservice انجام شود.

در چنین محیطی اصل Least Privilege اهمیت بیشتری پیدا می‌کند.

یک Template Renderer بهتر است فقط به سرویس‌هایی دسترسی داشته باشد که برای انجام وظیفه خود نیاز دارد.

Network Policyها می‌توانند ارتباط غیرضروری میان سرویس‌ها را محدود کنند.

Secretها نیز نباید بدون دلیل در Environment هر Container قرار گیرند.

اگر Renderer فقط وظیفه تولید ایمیل دارد، دسترسی آن به دیتابیس‌های غیرمرتبط یا سرویس‌های مدیریتی باید مورد سؤال قرار بگیرد.

بنابراین در Cloud Security نیز اصلاح SSTI فقط در سطح Source Code خلاصه نمی‌شود.

Blast Radius باید در کل معماری بررسی شود.

تست SSTI باید چگونه به‌صورت مسئولانه انجام شود؟

تست امنیتی SSTI باید فقط روی سیستم متعلق به خودتان، محیط آزمایشگاهی یا سامانه‌ای انجام شود که مجوز صریح تست آن را دارید.

هدف تست دفاعی باید شناسایی رفتار ناامن باشد، نه اثبات حداکثر خسارت ممکن.

اگر در یک محیط Staging مشخص شد که ورودی کاربر برخلاف انتظار به‌عنوان Expression توسط Template Engine تفسیر می‌شود، همین موضوع می‌تواند برای شروع Remediation کافی باشد.

نیازی نیست تست به سمت دسترسی به فایل، اجرای دستور، مشاهده Secret یا عبور از Sandbox گسترش داده شود.

در گزارش امنیتی نیز بهتر است Evidence حداقلی ثبت شود.

یک گزارش حرفه‌ای باید Endpoint، محل ورودی، Template Engine احتمالی، مسیر Data Flow، شرایط لازم برای وقوع مشکل، تأثیر بالقوه و پیشنهاد اصلاح را مشخص کند.

این رویکرد هم از نظر اخلاقی و هم از نظر عملی برای تیم توسعه مفیدتر است.

چگونه SSTI را در چرخه توسعه نرم‌افزار کنترل کنیم؟

بهترین زمان برای جلوگیری از SSTI قبل از Production است.

در مرحله Design باید Trust Boundaryها مشخص شوند.

اگر Product Manager قابلیت ساخت Template سفارشی درخواست کرده است، تیم امنیت باید از همان مرحله سؤال کند:

چه کسانی می‌توانند Template بسازند؟

چه داده‌هایی در اختیار Template قرار می‌گیرد؟

آیا Template Language باید دارای Logic باشد؟

چه محدودیت‌هایی لازم است؟

Template کجا Render می‌شود؟

Process رندر به چه منابعی دسترسی دارد؟

در مرحله Development می‌توان Secure Wrapper برای Template Engine ایجاد کرد تا توسعه‌دهندگان به‌صورت پیش‌فرض از روش امن استفاده کنند.

در مرحله Code Review باید هر استفاده جدید از APIهای Compile، Render-from-String یا قابلیت‌های مشابه بررسی شود.

در CI/CD نیز SAST و تست‌های امنیتی می‌توانند به شناسایی Regression کمک کنند.

در Production، Monitoring و Patch Management تکمیل‌کننده چرخه خواهند بود.

این مدل بسیار مؤثرتر از آن است که امنیت فقط هنگام Pentest نهایی بررسی شود.

اولویت اصلاح SSTI چگونه تعیین می‌شود؟

تمام یافته‌های SSTI نباید بدون Context دقیقاً یکسان ارزیابی شوند.

برای تعیین شدت باید چند سؤال پاسخ داده شود.

آیا کاربر ناشناس می‌تواند به ورودی آسیب‌پذیر دسترسی داشته باشد؟

آیا نیاز به Authentication وجود دارد؟

آیا فقط Administrator قابل‌اعتماد می‌تواند Template را تغییر دهد؟

Template Engine چه قابلیت‌هایی دارد؟

چه Objectهایی داخل Context موجودند؟

Sandbox فعال است؟

Process چه دسترسی‌هایی دارد؟

آیا Application داخل Environment محدود اجرا می‌شود؟

چه اطلاعاتی در معرض دسترسی هستند؟

پاسخ به این سؤالات تعیین می‌کند یک یافته SSTI تا چه اندازه خطرناک است.

برای مثال یک Template محدود با Allowlist کوچک در Process ایزوله با Template Engine قدرتمندی که مستقیماً Objectهای داخلی Application را در اختیار Template قرار می‌دهد قابل مقایسه نیست.

بنابراین Severity باید بر اساس شرایط واقعی سیستم تعیین شود.

نقش به‌روزرسانی Template Engine در امنیت

به‌روز نگه داشتن Template Engine بخش مهمی از امنیت است، اما به‌تنهایی SSTI را حل نمی‌کند.

SSTI معمولاً نتیجه نحوه استفاده برنامه از Template Engine است.

حتی جدیدترین نسخه یک موتور Template نیز اگر ورودی غیرقابل‌اعتماد را به‌عنوان Template مورد اعتماد پردازش کند ممکن است در یک معماری ناامن قرار بگیرد.

با این حال Update همچنان ضروری است، زیرا Sandbox، Parser و سایر مؤلفه‌های Template Engine نیز نرم‌افزار هستند و ممکن است در نسخه‌های مختلف Fixهای امنیتی دریافت کنند.

بهترین سیاست ترکیبی از Dependency Management و Secure Usage است.

یعنی هم موتور Template به‌روز باشد و هم نحوه استفاده از آن صحیح طراحی شود.

آیا حذف Characterهای خاص از ورودی راهکار خوبی است؟

معمولاً خیر.

فیلتر کردن چند Character یا Pattern خاص ممکن است در ظاهر راه سریعی برای جلوگیری از Template Injection باشد، اما مشکل بنیادی را حل نمی‌کند.

اول اینکه Syntax موتورهای Template با یکدیگر متفاوت است.

دوم اینکه Template Languageها ممکن است راه‌های متعدد برای بیان یک عملیات داشته باشند.

سوم اینکه به‌روزرسانی Engine می‌تواند Syntax یا قابلیت‌های جدیدی معرفی کند.

چهارم اینکه Encoding و مراحل مختلف پردازش می‌توانند رفتار Filter را پیچیده کنند.

بنابراین راهکار امن‌تر این است که داده کاربر اصلاً در موقعیتی قرار نگیرد که Engine آن را به‌عنوان Template Syntax تفسیر کند.

Validation همچنان مفید است، اما باید در کنار معماری امن باشد.

نمونه معماری امن برای تولید ایمیل

فرض کنیم سایت رخنه‌کاو یک سامانه فرضی دارد که پس از ثبت درخواست، ایمیل تأیید برای کاربر ارسال می‌کند.

Template ایمیل باید توسط تیم توسعه یا Administrator مورد اعتماد تعریف شود.

متغیرهای موردنیاز نیز می‌توانند شامل موارد محدودی باشند:

name
ticket_number
created_at

Application این داده‌ها را دریافت می‌کند و به Template Engine می‌دهد.

کاربر فقط مقدار name یا اطلاعات فرم خودش را کنترل می‌کند.

او نمی‌تواند Template ایمیل را تغییر دهد.

اگر بعدها قابلیت ساخت Template توسط کاربران سازمانی اضافه شود، بهتر است یک Template Language محدود با Placeholderهای مشخص تعریف شود.

برای مثال مشتری فقط بتواند محل نمایش نام یا شماره تیکت را تعیین کند.

او نباید به Objectهای Application، Configuration یا Functionهای Runtime دسترسی داشته باشد.

این مثال نشان می‌دهد Secure Design بسیار مؤثرتر از تلاش برای تشخیص و حذف ورودی‌های «بد» است.

بررسی امنیتی Templateهای ذخیره‌شده در دیتابیس

گاهی تیم توسعه تصور می‌کند چون Template از Database خوانده می‌شود پس Trusted است.

این نتیجه همیشه درست نیست.

باید مشخص شود Template چگونه وارد Database شده است.

اگر یک کاربر، Editor، API یا سیستم خارجی بتواند مقدار را تغییر دهد، Database صرفاً محل ذخیره‌سازی است و Trust Level داده را تغییر نمی‌دهد.

این اصل در امنیت با عنوان Stored Input اهمیت دارد.

داده غیرقابل‌اعتماد حتی پس از ذخیره شدن همچنان غیرقابل‌اعتماد است.

بنابراین هنگام Code Review نباید فقط Request مستقیم را بررسی کرد.

Data Flow ممکن است چنین باشد:

User
 ↓
API
 ↓
Database
 ↓
Template Renderer

در این حالت Vulnerability ممکن است در زمان دیگری و توسط یک Worker یا Background Job فعال شود.

به همین دلیل بررسی End-to-End Data Flow اهمیت زیادی دارد.

امنیت Template در پنل مدیریت

یکی دیگر از سوءبرداشت‌های رایج این است که هر چیزی در Admin Panel قرار دارد امن محسوب می‌شود.

وجود Authentication ریسک را کاهش می‌دهد اما Trust Boundary را حذف نمی‌کند.

ممکن است سیستم چند Role مدیریتی داشته باشد.

یک Editor یا Marketing User لزوماً نباید قابلیت اجرای Template با دسترسی سطح Application داشته باشد.

همچنین Account مدیریتی ممکن است در اثر Phishing یا Credential Theft تصاحب شود.

بنابراین حتی قابلیت‌های پنل مدیریت نیز باید براساس Least Privilege طراحی شوند.

اگر Template Editor فقط برای Super Admin ضروری است، Roleهای دیگر نباید به آن دسترسی داشته باشند.

اگر Template قابل‌ویرایش است، Sandbox و محدودیت Context همچنان ارزشمند هستند.

امنیت Templateهای چندمستاجری یا Multi-Tenant

SSTI در یک SaaS چندمستاجری می‌تواند اهمیت بیشتری داشته باشد.

در Multi-Tenant Architecture باید اطمینان حاصل شود که Template متعلق به Tenant A هیچ راهی برای مشاهده یا اثرگذاری بر داده Tenant B ندارد.

بنابراین Template Context باید علاوه بر محدود بودن، از نظر Tenant Boundary نیز کنترل شود.

هر Query مربوط به داده باید به Tenant صحیح محدود باشد.

Template Renderer نباید Object سراسری در اختیار داشته باشد که امکان عبور از مرز Tenant را ایجاد کند.

اگر Templateهای مشتریان واقعاً قابل‌برنامه‌ریزی هستند، Isolation قوی‌تر می‌تواند ضروری باشد.

در چنین محیط‌هایی یک خطای کوچک ممکن است علاوه بر Confidentiality، مرز جداسازی مشتریان را نیز تحت تأثیر قرار دهد.

چگونه یک گزارش SSTI حرفه‌ای نوشته می‌شود؟

گزارش خوب باید برای توسعه‌دهنده قابل‌استفاده باشد.

صرف نوشتن «سایت SSTI دارد» کافی نیست.

گزارش بهتر است ابتدا Component یا Endpoint درگیر را معرفی کند.

سپس توضیح دهد چه ورودی‌ای روی Template Source اثر می‌گذارد.

Data Flow باید تا حد ممکن مشخص شود.

بعد باید تفاوت رفتار فعلی با رفتار امن توضیح داده شود.

Impact نیز باید متناسب با شرایط واقعی Application بیان شود و از بزرگ‌نمایی خودداری شود.

اگر صرفاً Template Evaluation تأیید شده ولی RCE آزمایش نشده است، گزارش نباید ادعا کند «RCE قطعی» وجود دارد.

می‌توان نوشت که به دلیل ماهیت Template Engine، پیامد بالقوه نیازمند بررسی دقیق‌تر است.

در بخش Remediation باید پیشنهاد مشخص ارائه شود:

استفاده از Fixed Template، ارسال داده به‌صورت Variable، محدودسازی Context، Sandbox در صورت لزوم و کاهش دسترسی Process.

این نوع گزارش برای تیم Development بسیار ارزشمندتر از گزارشی است که فقط مجموعه‌ای از Payloadها را ارائه کند.

سؤالات متداول درباره SSTI

آیا SSTI همان XSS است؟

خیر. XSS عمدتاً زمانی اتفاق می‌افتد که محتوای غیرقابل‌اعتماد در مرورگر کاربر به‌شکل ناامن تفسیر شود. SSTI در Template Engine سمت سرور رخ می‌دهد. به همین دلیل پیامدهای SSTI در برخی شرایط می‌توانند مستقیماً زیرساخت Server-Side را تحت تأثیر قرار دهند.

آیا تمام Template Engineها در برابر SSTI آسیب‌پذیر هستند؟

خیر. وجود Template Engine به معنی آسیب‌پذیری نیست. مشکل اصلی زمانی ایجاد می‌شود که داده غیرقابل‌اعتماد به Template Code یا Template Source تبدیل شود یا محیط Template بیش از حد دسترسی داشته باشد.

آیا Jinja می‌تواند SSTI داشته باشد؟

اگر برنامه از Jinja به شکلی استفاده کند که Template غیرقابل‌اعتماد را بدون کنترل مناسب پردازش کند، خطر Template Injection می‌تواند مطرح شود. Jinja برای سناریوهای Template غیرقابل‌اعتماد SandboxedEnvironment ارائه می‌کند، اما مستندات آن تأکید می‌کنند Sandbox به‌تنهایی امنیت کامل ایجاد نمی‌کند.

آیا Twig در برابر SSTI امن است؟

امنیت به نحوه استفاده از Twig بستگی دارد. مستندات رسمی Twig Template Source را در حالت عادی Trusted Code در نظر می‌گیرند. اگر برنامه Templateهای غیرقابل‌اعتماد را می‌پذیرد، Sandbox باید متناسب با نیاز برنامه فعال و محدود شود.

آیا WAF برای جلوگیری از SSTI کافی است؟

خیر. WAF می‌تواند بعضی Requestهای مشکوک را مسدود کند، اما ریشه SSTI معمولاً در معماری Application قرار دارد. اصلاح کد و جداسازی Template از User Data کنترل اصلی محسوب می‌شود.

آیا HTML Escaping جلوی SSTI را می‌گیرد؟

الزاماً خیر. HTML Escaping بیشتر برای امن‌سازی خروجی در Context HTML استفاده می‌شود. SSTI ممکن است قبل از تولید HTML و در مرحله پردازش Template اتفاق بیفتد. بنابراین Template و Data باید از ابتدا جدا باشند.

مهم‌ترین روش پیشگیری از SSTI چیست؟

بهترین اصل این است که Template از ورودی کاربر ساخته نشود. Template باید ثابت و مورد اعتماد باشد و User Input صرفاً به‌عنوان Variable یا Data وارد آن شود.

اگر محصول به Template سفارشی کاربر نیاز داشته باشد چه کنیم؟

در این شرایط بهتر است ابتدا بررسی شود آیا یک Template Language محدود یا Logic-Less نیاز را برطرف می‌کند. اگر موتور کامل Template ضروری است، Sandbox، Allowlist، Context محدود، Resource Limiting، Isolation و Least Privilege باید به‌صورت چندلایه استفاده شوند.

آیا SSTI همیشه باعث RCE می‌شود؟

خیر. تأثیر SSTI به موتور Template، قابلیت‌های Environment، داده‌های قابل‌دسترسی و تنظیمات سیستم بستگی دارد. در بعضی شرایط تأثیر محدود است و در برخی محیط‌های قدرتمند می‌تواند بسیار جدی شود. بنابراین RCE نباید بدون شواهد به هر SSTI نسبت داده شود.

SSTI با چه شناسه CWE شناخته می‌شود؟

MITRE ضعف Improper Neutralization of Special Elements Used in a Template Engine را با شناسه CWE-1336 ثبت کرده و SSTI را یکی از اصطلاحات مرتبط با این ضعف معرفی می‌کند.

جمع‌بندی

Server-Side Template Injection یا SSTI یکی از آسیب‌پذیری‌های مهم حوزه Injection است که در اثر شکسته شدن مرز میان «داده» و «Template Code» به وجود می‌آید.

Template Engineها ابزارهای بسیار مفیدی هستند و استفاده از آنها به‌خودی خود مشکل امنیتی ایجاد نمی‌کند. خطر زمانی آغاز می‌شود که ورودی غیرقابل‌اعتماد به‌جای آنکه فقط یک Variable باشد، بتواند روی Template Source یا دستورهای قابل‌تفسیر موتور اثر بگذارد.

اهمیت SSTI از این واقعیت ناشی می‌شود که Template در سمت سرور پردازش می‌شود. بسته به موتور، Context و سطح دسترسی Application، پیامد آن می‌تواند از تغییر خروجی یا افشای اطلاعات تا دسترسی‌های جدی‌تر گسترش پیدا کند. با این حال شدت هر یافته باید براساس شرایط واقعی سیستم ارزیابی شود و نباید هر SSTI را بدون بررسی معادل RCE در نظر گرفت.

مهم‌ترین راهکار دفاعی، طراحی صحیح معماری است: Template ثابت و مورد اعتماد باشد و اطلاعات کاربر فقط به‌عنوان Data وارد آن شوند.

اگر قابلیت Template سفارشی واقعاً یکی از نیازهای محصول است، باید آن را یک مرز امنیتی مهم در نظر گرفت. استفاده از Sandbox رسمی، Allowlist، محدود کردن Template Context، Least Privilege، محدودیت CPU و Memory، Isolation و Monitoring می‌توانند لایه‌های تکمیلی دفاع را تشکیل دهند.

از سوی دیگر، اتکا به HTML Escaping، WAF یا Blacklist چند Pattern خاص نمی‌تواند جایگزین اصلاح معماری شود.

تیم‌های توسعه بهتر است SSTI را از مرحله طراحی در Threat Modeling در نظر بگیرند، تمام محل‌های استفاده از Template Engine را Inventory کنند، مسیر Source-to-Sink داده را در Code Review بررسی کنند و SAST و تست‌های امنیتی را وارد CI/CD کنند.

در نهایت، مهم‌ترین سؤال هنگام بررسی هر سیستم Template این است:

«آیا این مقدار فقط داده است، یا کاربر می‌تواند کاری کند که موتور Template آن را به‌عنوان دستور تفسیر کند؟»

اگر پاسخ به بخش دوم مثبت باشد، طراحی سیستم باید از دید Server-Side Template Injection با دقت بررسی شود.

مطالب مرتبط