امنیت، هویت، استقرار و تابآوری · فصل ۲ — CSRF، CORS، CSP، Injection و Secrets · 84
XSS, SQL Injection و Input Validation
دانش فعلی دربارهی «XSS, SQL Injection و Input Validation» ممکن است checklist-محور باشد و threat/control boundary را به evidence قابل بازبینی تبدیل نکند. میتواند برای «XSS, SQL Injection و Input Validation» threat/trust boundary، کنترل و evidence را در یک سناریوی محدود تعریف و justify کند.
خلاصهٔ درس
دانش فعلی دربارهی «XSS, SQL Injection و Input Validation» ممکن است checklist-محور باشد و threat/control boundary را به evidence قابل بازبینی تبدیل نکند.
میتواند برای «XSS, SQL Injection و Input Validation» threat/trust boundary، کنترل و evidence را در یک سناریوی محدود تعریف و justify کند.
خروجی این درس
میتواند برای «XSS, SQL Injection و Input Validation» threat/trust boundary، کنترل و evidence را در یک سناریوی محدود تعریف و justify کند.
پیشنیازها
نتیجه محدود درس
عبارت «ورودی را sanitize کن» یک قانون امنیتی کافی نیست، چون دادهی untrusted در مسیرهای مختلف به interpreter یا sinkهای متفاوت میرسد. در این درس سه مرز از هم جدا میشوند: XSS که به context خروجی در مرورگر و sink مربوط است، SQL Injection که به مرز code/data در لایهی پایگاهداده مربوط میشود، و Input Validation که syntactic و semantic correctness را در مرز کسبوکار بررسی میکند اما جای دفاع اصلی دو مورد قبلی را نمیگیرد.
خروجی درس یک Injection Defense Boundary Matrix v1 است. این ماتریس ادعا نمیکند «کل برنامه امن است». فقط نشان میدهد برای یک fixture محدود و synthetic، داده از چه trust source میآید، چه business validation دارد، به چه sink یا interpreter میرسد، primary defense چیست و چه positive/negative evidence برای تصمیم محدود ثبت شده است.
شناسهی lab این درس SEC007-LAB1 است. تمام lab محلی و synthetic است. هیچ حساب واقعی، credential واقعی، external target، payload تهاجمی، persistence یا network action لازم نیست. markerها عمداً benign هستند تا learner بتواند دربارهی مرز دفاعی قضاوت کند بدون اینکه اجرای حمله بخشی از تمرین باشد.
1. قبل از انتخاب کنترل، مسیر داده را طبقهبندی کنید
یک مقدار میتواند از یک input field وارد شود اما در ادامه چند مقصد متفاوت داشته باشد. اگر همان مقدار در متن HTML، مقدار attribute، URL component، rich HTML یا query parameter استفاده شود، «کنترل درست» الزاماً یکی نیست. نقطهی شروع تحلیل این است:
- Trust Source: داده از کجا آمده و چرا untrusted فرض میشود؟
- Business Validation: چه syntax و semantic rule برای خود کسبوکار لازم است؟
- Destination Sink or Interpreter: داده در کجا مصرف میشود؟ مرورگر، data-access API یا یک identifier انتخابشده؟
- Primary Defense: چه کنترل مستقیماً مرز code/data یا data/executable interpretation را حفظ میکند؟
- Secondary Defense: چه کنترل مکمل است اما نباید بهعنوان primary defense معرفی شود؟
- Evidence: چه مشاهدهای نشان میدهد تصمیم محدود درست اجرا شده و چه negative probe نشان میدهد shortcut رد میشود؟
این تفکیک باعث میشود input validation با output encoding یا query parameterization مخلوط نشود.
2. XSS: context خروجی و safe sink تعیینکنندهاند
در XSS مسئله این نیست که یک رشته «ذاتاً امن» یا «ذاتاً ناامن» باشد. مسئله این است که داده در چه contextی به browser parser میرسد. OWASP برای contextهای متفاوت encodingهای متفاوت تعریف میکند و توصیه میکند تا جای ممکن از safe sinkهایی استفاده شود که داده را بهعنوان text نگه میدارند، نه markup یا executable content.
در fixture درس، display_label فقط با markerهای benign آزمایش میشود. برای html_text تصمیم طراحی، استفاده از یک text-oriented safe sink است. برای html_attribute فقط attributeهای از پیش مجاز و ثابت در نظر گرفته میشوند و داده باید در همان context به شکل مناسب encode شود. اگر نیاز محصول واقعاً rich HTML باشد، output encoding ساده functionality را از بین میبرد و باید sanitizer معتبر و نگهداریشده در مرز مخصوص آن قرار گیرد. این درس sanitizer واقعی شبکهای یا third-party را اجرا نمیکند؛ فقط تصمیم معماری را ثبت میکند.
چرا generic sanitizer کافی نیست؟
یک transform عمومی context مرورگر را نمیداند. چیزی که برای HTML text مناسب است ممکن است برای URL، JavaScript یا attribute مناسب نباشد. بنابراین ماتریس باید context را قبل از primary defense ثبت کند. اگر context عوض شد، learner موظف است تصمیم را دوباره بسازد، نه اینکه کنترل قبلی را کورکورانه reuse کند.
3. Safe sink از «پاک کردن ورودی» مهمتر است
یک safe sink تا حد امکان داده را از executable interpretation جدا میکند. این یک تصمیم در نقطهی مصرف است. در مقابل، تلاش برای پاککردن عمومی input در ابتدای pipeline ممکن است context مقصد را نبیند. پس برای free-form text، business validation باید به نیاز واقعی داده محدود بماند و دفاع XSS در sink/context اعمال شود.
در lab، خروجی واقعی HTML تولید نمیشود. تابع local فقط تصمیم دفاعی را برای context اعلام میکند و برای مسیر html_text از html.escape روی marker benign استفاده میکند تا نشان دهد data handling وابسته به context است. هیچ exploit string در fixture وجود ندارد.
4. SQL Injection: مرز code/data را در data-access layer نگه دارید
برای valueهای query، prepared statement یا parameterized query باعث میشود SQL structure جدا از parameter data تعریف شود. learner در lab یک query template ثابت و یک list از parameters میبیند. مسیر string_building عمداً قبل از execution رد میشود؛ حتی database واقعی هم وجود ندارد.
نکتهی مهم این است که parameter binding برای هر نوع SQL fragment یکسان نیست. برای مثال identifierهایی مثل نام column یا sort direction معمولاً باید از مجموعهی محدود و از پیش تعریفشده انتخاب شوند. این درس برای transfer فقط این rule را بهصورت design decision ثبت میکند و هیچ dynamic SQL علیه database واقعی اجرا نمیکند.
Negative Evidence
یک query design synthetic از حالت parameterized به string_building تغییر میکند. انتظار این نیست که learner آن را اجرا یا exploit کند. evidence gate باید قبل از execution آن design را با status مشخص رد کند. شواهد منفی در اینجا اثبات میکند که code/data boundary فقط یک توضیح نظری نیست و در تصمیم طراحی enforce میشود.
5. Input Validation: syntax و semantics، نه جایگزین injection defense
Input Validation باید زود انجام شود و برای هر field مشخص کند چه شکل و چه معنایی قابلقبول است. در fixture، report_days باید:
- از نظر syntactic یک integer باشد؛
- از نظر semantic در بازهی business تعریفشده قرار گیرد.
اگر مقدار از نظر syntax نامعتبر باشد، status مستقل REJECT_SYNTAX ثبت میشود. اگر integer باشد ولی خارج از business range باشد، status REJECT_SEMANTIC است. این دو نتیجه نباید با XSS یا SQL-injection defense یکی شوند.
مثلاً valid بودن یک عدد به این معنی نیست که query string concatenation امن شده است. همانطور، valid بودن یک display label به این معنی نیست که میتوان آن را در هر browser context بدون کنترل context-specific قرار داد.
6. Positive path محدود
سناریوی baseline شامل دو field است:
display_labelبا یک marker benign برای preview محلی؛report_daysبا مقدار عددی داخل range برای query design محلی.
Positive evidence زمانی قابلقبول است که سه observation مستقل داشته باشیم:
- business validation دلیل قبول داده را نشان دهد؛
- browser-output path context و primary defense درست را ثبت کند؛
- database path query template و parameter list را جدا نگه دارد.
این سه مشاهده کنار هم یک تصمیم محدود را پشتیبانی میکنند، نه امنیت کلی محصول را.
7. Negative Evidence اجباری است
فقط green path برای درس کافی نیست. سه negative probe ایمن و local داریم:
- context خروجی از
html_textبه یک context دیگر تغییر میکند و control decision باید reclassify شود؛ - query design به
string_buildingتغییر میکند و باید قبل از execution رد شود؛ - مقدار
report_daysاز نظر syntax درست ولی از نظر business semantics خارج از range میشود و باید با دلیل semantic رد شود.
هیچکدام از این probeها payload تهاجمی تولید نمیکنند. هدف این است که shortcutهای دفاعی را با evidence بشکنیم.
8. Injection Defense Boundary Matrix v1
هر ردیف ماتریس این ستونها را دارد:
| Input Field | Trust Source | Business Validation | Destination Sink or Interpreter | Primary Defense | Secondary Defense | Positive Evidence | Negative Evidence | Residual Boundary |
|---|---|---|---|---|---|---|---|---|
| display_label | synthetic user field | length/category rule | HTML text preview | safe text sink + context encoding | CSP/framework defaults | benign marker remains data | changed context forces reclassification | other sinks not proven |
| report_days | synthetic report field | integer + allowed range | parameterized data-access API | prepared/parameterized query | least privilege | fixed query structure + bound parameter | string-building design rejected | identifiers need separate allowlist |
در submission template مقدارهای نهایی evidence خالیاند. learner باید observed output را از inference جدا کند. owner acceptance نیز prefilled نیست.
9. Failure modeهای رایج
«همه چیز را sanitize میکنیم»
این جمله destination context را پنهان میکند. اصلاح: sink/interpreter را اول ثبت کنید.
«validation جلوی SQL Injection را میگیرد»
Validation برای data quality و business rules مهم است، اما primary code/data boundary برای values باید در query API حفظ شود. اصلاح: validation و parameterization را دو ستون جدا نگه دارید.
«CSP داریم، پس XSS حل است»
CSP defense in depth است و جای primary context-specific XSS defenses را نمیگیرد. این درس ownership CSP را از SEC-006 دوباره تدریس نمیکند؛ فقط آن را secondary defense مینامد.
«یک unit test سبز یعنی همه sinkها امناند»
یک test فقط fixture اعلامشده را پوشش میدهد. residual boundary باید explicit بماند.
10. Guided practice
ابتدا baseline fixture را اجرا کنید و برای display_label context، sink و primary defense را بنویسید. سپس report_days را از syntactic و semantic perspective بررسی کنید. بعد query design را inspect کنید و تأیید کنید SQL template از parameter data جداست.
در مرحله دوم یکی از mutationهای امن را اجرا کنید. مشاهده را بدون نتیجهگیری کلی ثبت کنید. سپس فقط کنترل همان مرز را repair یا reclassify کنید و probe را تکرار کنید.
11. Transfer: comments feature و report export
در changed-context transfer، دو نیاز جدید معرفی میشود:
- comments feature به rich content نیاز دارد؛ این دیگر همان
html_textساده نیست و decision باید به sanitization boundary منتقل شود؛ - report export به انتخاب
sort_keyاز چند identifier ثابت نیاز دارد؛ parameter binding برای identifier مسئله را بهتنهایی حل نمیکند، پس یک allowlist محدود از identifierهای مجاز لازم است.
learner باید ماتریس را از نو بسازد و دلیل reuse نکردن کنترل قبلی را توضیح دهد. پاسخ نهایی در starter وجود ندارد.
12. Evidence و residual risk
Evidence باید حداقل یک positive observation و یک negative observation برای هر مرز اصلی داشته باشد. observation با inference یکی نیست. «تابع status X برگرداند» observation است؛ «پس کل application در برابر XSS امن است» inference ناموجه است.
Residual Boundary باید صریحاً بگوید چه چیزی ثابت نشده است: contextهای دیگر، framework behavior واقعی، production database permissions، third-party sanitizer configuration و همهی sinkهای برنامه خارج از scope این lab هستند.
13. منابع و freshness
این درس فقط از سه source منجمد استفاده میکند: OWASP-XSS برای context-sensitive XSS defenses، safe sinks و sanitization؛ OWASP-SQLI برای prepared/parameterized queries و code/data separation؛ و OWASP-INPUT-VALIDATION برای syntactic/semantic validation و این هشدار که validation جای primary XSS/SQL Injection defense نیست.
در authoring این Query، هر سه منبع رسمی دوباره بررسی شدند و source جدیدی وارد authority نشد. review_due منجمد 2026-10-02 است؛ اگر guidance یا assumptions تغییر کند، freshness review باید دوباره اجرا شود.
14. Non-goals
این درس ادعا نمیکند:
- یک generic sanitization function برای همهی HTML، JavaScript، URL و SQL contextها کافی است؛
- input validation جای parameterized query را میگیرد؛
- CSP بهتنهایی XSS را حل میکند؛
- دادهای که business validation را گذرانده، برای هر sink یا interpreter امن است؛
- lab synthetic معادل production security assessment است.
جمعبندی تصمیم
قاعدهی قابل انتقال این است: داده را بر اساس destination interpreter/sink طبقهبندی کن، business validation را از injection defense جدا نگه دار، code/data boundary را با API مناسب حفظ کن، و برای هر تصمیم positive و Negative Evidence ثبت کن. اگر context عوض شد، matrix را دوباره بساز.
منابع و تازگی
فایلهای آزمایشگاه
رسانه و اسلایدهای درس
فایلهای آموزشی (دانلود)