مدت زمان مطالعه:
0

حمله Cross-Site Request Forgery یا CSRF زمانی رخ میدهد که مهاجم مرورگر یک کاربر احراز هویتشده را فریب میدهد تا بدون اطلاع او، در یک وبسایت معتبر درخواست ناخواستهای ارسال کند. چون مرورگر معمولاً کوکی نشست را بهصورت خودکار همراه درخواست میفرستد، برنامه آسیبپذیر ممکن است درخواست جعلی را مانند درخواست واقعی کاربر پردازش کند.
FortiWeb برای کاهش این ریسک، روی صفحات مشخصشده یک اسکریپت قرار میدهد تا پارامتر ضد CSRF با نام tknfv به لینکها، فرمها و در صورت فعالبودن قابلیت مربوطه، درخواستهای XMLHttpRequest اضافه شود. سپس FortiWeb در URLهای حساس، وجود و درستی این توکن را با اطلاعات نشست کاربر بررسی میکند.
این مقاله از مرحله شناخت حمله تا طراحی Rule، پیکربندی در GUI و CLI، تست، عیبیابی و انتقال امن از حالت مانیتورینگ به حالت Block را توضیح میدهد تا برای ادمینهای تازهکار و کارشناسان باتجربه قابل استفاده باشد.
این مقاله بر اساس FortiWeb 7.6 نوشته شده است. در نسخههای دیگر ممکن است مسیرهای GUI، نام فیلدها یا رفتار برخی قابلیتها متفاوت باشد.
tknfv به درخواستهای مبتنی بر XMLHttpRequest است.
مروری بر این مقاله
فرض کنید کاربر وارد پنل بانکی، سامانه سازمانی یا پرتال مدیریت شده و کوکی نشست معتبر در مرورگر او وجود دارد. مهاجم لینکی برای کاربر ارسال میکند یا کدی را در یک سایت دیگر قرار میدهد که مرورگر قربانی را وادار میکند در پسزمینه درخواستی به سامانه هدف ارسال کند. اگر برنامه فقط به کوکی نشست اعتماد کند و منشأ یا توکن اختصاصی درخواست را بررسی نکند، ممکن است عملیات ناخواسته اجرا شود.
بر اساس راهنمای OWASP، دفاع اصلی باید در خود برنامه شامل توکن ضد CSRF، کنترل مجدد مجوزها و طراحی صحیح نشست باشد. FortiWeb یک لایه دفاعی تکمیلی در جلوی برنامه ایجاد میکند و نباید جایگزین کنترلهای امنیتی داخل Application در نظر گرفته شود.
قابلیت CSRF Protection در FortiWeb بر اساس ارتباط میان دو فهرست کار میکند:
| فهرست | وظیفه | نمونه |
|---|---|---|
| Page List Table | صفحاتی که FortiWeb باید اسکریپت افزودن توکن را در پاسخ HTML آنها قرار دهد. | /account/profile |
| URL List Table | URLهایی که درخواست به آنها باید دارای توکن معتبر tknfv باشد. |
/api/account/email |
هنگامی که کاربر صفحهای از Page List را دریافت میکند، FortiWeb در پاسخ HTML اسکریپتی قرار میدهد که مقدار tknfv را به لینکها و فرمهای صفحه اضافه میکند. مقدار توکن با کوکی صادرشده توسط Client Management مرتبط است. وقتی مرورگر درخواستی به یکی از URLهای موجود در URL List ارسال میکند، FortiWeb مقدار توکن و نشست را بررسی میکند.
اگر توکن وجود نداشته باشد یا با مقدار مورد انتظار نشست تطبیق نکند، FortiWeb بر اساس Action تنظیمشده میتواند فقط Log ایجاد کند، درخواست را مسدود کند، بدون Log آن را رد کند یا برای یک بازه زمانی Client را Block کند.
در FortiWeb 7.6 امکان افزودن توکن به درخواستهای JavaScript مبتنی بر XMLHttpRequest وجود دارد. برای این کار باید گزینه JS Request Status یا Ajaxcheck Status فعال باشد. مستند رسمی بهطور مشخص از تابع بومی XMLHttpRequest نام میبرد؛ بنابراین در برنامههایی که از fetch، کتابخانههای سفارشی، WebSocket، Mobile Client یا API Clientهای بدون مرورگر استفاده میکنند، حتماً رفتار واقعی برنامه را آزمایش کنید.
طبق مستند Fortinet، این قابلیت در حالتهای Offline Protection و Transparent Inspection پشتیبانی نمیشود. علت عملیاتی این محدودیت آن است که FortiWeb برای این مکانیزم باید پاسخ HTML را تغییر دهد و کوکی نشست موردنیاز Client Management را مدیریت کند.
مهمترین بخش کانفیگ، شناخت Flow واقعی برنامه است. قبل از ساخت Rule مشخص کنید هر عملیات حساس از کدام صفحه آغاز میشود و به کدام Endpoint درخواست میفرستد.
| سؤال طراحی | پاسخ موردنیاز |
|---|---|
| کاربر از کدام صفحه عملیات را شروع میکند؟ | این URL معمولاً باید در Page List قرار بگیرد. |
| فرم یا JavaScript درخواست را به کدام URL میفرستد؟ | این Endpoint معمولاً باید در URL List قرار بگیرد. |
| آیا صفحه و Endpoint یک URL مشترک دارند؟ | از Parameter Filter برای تفکیک درخواست نمایش صفحه و درخواست عملیاتی استفاده کنید. |
| آیا Endpoint توسط Mobile App یا API Client نیز مصرف میشود؟ | Scope را با Host، URL و Parameter Filter محدود کنید یا Flow جداگانهای طراحی کنید. |
| آیا درخواست با XMLHttpRequest ارسال میشود؟ | JS Request Status یا Ajaxcheck Status را فعال و نتیجه را در Browser DevTools بررسی کنید. |
برای URLهای مشخص و ثابت از Simple String استفاده کنید. استفاده بیدلیل از Regular Expression میتواند Scope Rule را بیش از حد گسترده کند و احتمال False Positive را افزایش دهد. Regular Expression زمانی مناسب است که ساختار URL متغیر است و الگوی آن دقیقاً شناخته شده باشد.
در این سناریو، کاربر از صفحه پروفایل وارد فرم تغییر ایمیل میشود و فرم یک درخواست POST به Endpoint تغییر ایمیل ارسال میکند:
| مورد | مقدار نمونه |
|---|---|
| دامنه برنامه | portal.example.com |
| صفحه آغاز عملیات | /account/profile |
| Endpoint حساس | /api/account/email |
| نام Rule | PARTIAN-CSRF |
| اقدام اولیه | Alert |
| اقدام پس از Tune | Alert & Deny |
در مرحله اول Rule را روی Alert قرار میدهیم تا درخواستهای واقعی، Endpointهای فراموششده و Clientهای غیرمرورگری مشخص شوند. پس از بررسی Logها و رفع False Positiveها، Action به Alert & Deny تغییر میکند.
در داخل Rule و در بخش Page List Table روی Create New کلیک کنید و مقادیر زیر را وارد کنید:
| فیلد | مقدار پیشنهادی سناریو |
|---|---|
| Host Status | در صورت وجود چند Host روی یک Policy فعال شود؛ در سناریوی ساده میتواند غیرفعال باشد. |
| Host | portal.example.com یا نام Protected Host از قبل ساختهشده |
| Request Type | Simple String |
| Full URL | /account/profile |
| Parameter Filter | برای این سناریو غیرفعال |
در بخش URL List Table روی Create New کلیک کنید:
| فیلد | مقدار پیشنهادی سناریو |
|---|---|
| Host Status | مشابه Page List و متناسب با معماری Host |
| Request Type | Simple String |
| Full URL | /api/account/email |
| Parameter Filter | در صورت نیاز برای محدودکردن Match فعال شود. |
config waf csrf-protection
edit "PARTIAN-CSRF"
set action alert
set severity Medium
set ajaxcheck enable
config csrf-page-list
edit 1
set request-url "/account/profile"
set request-type plain
next
end
config csrf-url-list
edit 1
set request-url "/api/account/email"
set request-type plain
next
end
next
end
در CLI مقدار plain معادل Simple String و مقدار regular معادل Regular Expression است. گزینه ajaxcheck enable برای افزودن توکن به درخواستهای XMLHttpRequest استفاده میشود.
config waf web-protection-profile inline-protection
edit "PARTIAN-INLINE-PROFILE"
set client-management enable
set csrf-protection "PARTIAN-CSRF"
next
end
نام PARTIAN-INLINE-PROFILE را با نام واقعی Web Protection Profile متصل به Server Policy جایگزین کنید.
اگر یک Profile برای چند دامنه استفاده میشود، بهتر است Page List و URL List را به Protected Host مشخص محدود کنید. نام Host باید از قبل در Protected Host Names تعریف شده باشد.
config waf csrf-protection
edit "PARTIAN-CSRF"
config csrf-page-list
edit 1
set host-status enable
set host "portal.example.com"
set request-url "/account/profile"
set request-type plain
next
end
config csrf-url-list
edit 1
set host-status enable
set host "portal.example.com"
set request-url "/api/account/email"
set request-type plain
next
end
next
end
config waf csrf-protection
edit "PARTIAN-CSRF"
set action alert_deny
next
end
| مقدار CLI | رفتار |
|---|---|
| alert | درخواست پذیرفته میشود و در صورت فعالبودن Log یا Alert، رویداد ثبت میشود. |
| alert_deny | درخواست Block میشود و Log یا Alert تولید میشود. |
| deny_no_log | درخواست بدون تولید Log رد میشود. |
| block-period | Client برای بازه 1 تا 3600 ثانیه Block میشود؛ مقدار پیشفرض CLI برای Block Period برابر 600 ثانیه است. |
گاهی URL نمایش صفحه و URL دریافت فرم یکسان است. برای مثال درخواست GET به /post.asp صفحه را نمایش میدهد و درخواست POST به همان URL فایل را آپلود میکند. در این وضعیت FortiWeb باید تشخیص دهد کدام درخواست برای تزریق JavaScript و کدام درخواست برای بررسی توکن است.
Parameter Filter امکان میدهد Match علاوه بر URL، بر اساس یک پارامتر موجود در Query String یا HTTP Body انجام شود. در مثال زیر، وجود پارامتر SUB1 با هر مقداری نشان میدهد که درخواست مربوط به Submit فرم است:
config waf csrf-protection
edit "PARTIAN-CSRF-UPLOAD"
set action alert
config csrf-page-list
edit 1
set request-url "/post.asp"
set request-type plain
next
end
config csrf-url-list
edit 1
set request-url "/post.asp"
set request-type plain
set parameter-filter enable
set parameter-name "SUB1"
set parameter-value-type regular
set parameter-value "*"
next
end
next
end
tknfv را در Query String یا Request Body بررسی کنید.tknfv یا با مقدار تغییرکرده ارسال کنید.| نشانه | علت محتمل | اقدام پیشنهادی |
|---|---|---|
| توکن tknfv به درخواست اضافه نمیشود. | صفحه با Page List Match نشده، Client Management غیرفعال است یا پاسخ HTML شرایط لازم را ندارد. | URL، Host، نوع Match و فعالبودن Client Management را بررسی کنید. |
| فرم سالم پس از فعالکردن Block قطع میشود. | Endpoint در URL List است اما صفحه مبدأ در Page List وجود ندارد یا کاربر Endpoint را مستقیم فراخوانی میکند. | Flow را کامل Mapping کنید و Rule را با Host یا Parameter Filter محدود کنید. |
| درخواست AJAX بدون توکن است. | JS Request Status/Ajaxcheck غیرفعال است یا برنامه از سازوکاری غیر از native XMLHttpRequest استفاده میکند. | گزینه را فعال و نوع واقعی Request API را در DevTools بررسی کنید. |
| FortiWeb اسکریپت را در صفحه قرار نمیدهد. | پاسخ HTML معتبر نیست، تگهای <html> وجود ندارند، Status Code برابر 200 نیست یا پاسخ فشرده است. | ساختار پاسخ، کد 200 و Uncompress Policy را بررسی کنید. |
| صفحه بزرگ محافظت نمیشود. | مقدار Maximum Body Cache Size از اندازه صفحه کوچکتر است. | اندازه پاسخ را اندازهگیری و مقدار Body Cache را متناسب تنظیم کنید. |
| روی یک دامنه درست و روی دامنه دیگر False Positive وجود دارد. | Profile مشترک است و Rule فقط بر اساس URL Match میشود. | Host Status را فعال و Protected Host صحیح را انتخاب کنید. |
| API Client یا Mobile App Block میشود. | Client غیرمرورگری صفحه HTML را دریافت نمیکند و در نتیجه توکن FortiWeb را ندارد. | Endpoint مشترک را از Scope عمومی خارج نکنید؛ ابتدا معماری را تفکیک یا Match را دقیقتر کنید. |