ارزش یک تست نفوذ به اندازه‌ی گزارش آن است. خودِ تست چند روز طول می‌کشد؛ اما گزارش همان چیزی است که تیم فنی ماه‌ها با آن کار می‌کند، ممیز آن را می‌خواند و مدیریت بر اساس آن تصمیم می‌گیرد که هزینه درست خرج شده یا نه. با این حال بیشتر گزارش‌هایی که برای بازبینی به ما می‌رسند یکی از دو مشکل را دارند: یا خروجی خام اسکنر با یک صفحه‌ی جلد هستند، یا روایتی آن‌قدر محافظه‌کارانه که هیچ‌کس نمی‌فهمد اول باید چه چیزی را درست کند.

این ساختاری است که گزارش‌های خودمان را با آن می‌سنجیم و پیشنهاد می‌کنیم آن را در درخواست پیشنهاد (RFP) بعدی‌تان بنویسید.

یک گزارش را سه گروه می‌خوانند و هر کدام از جای دیگری شروع می‌کنند:

گزارش، به ترتیب بخش‌ها مدیریت تیم فنی ممیز ۱. محدوده‌ی واقعاً آزمون‌شده ۲. روش‌شناسی و نگاشت پوشش ۳. خلاصه‌ی مدیریتی ۴. یافته‌ها با قالب ثابت ۵. زنجیره‌ها و اثر بر کسب‌وکار ۶. آنچه امتحان شد و جواب نداد ۷. شرایط آزمون مجدد ۸. پیوست‌ها و خروجی ماشین‌خوان
یک گزارش، سه خواننده. بخشی که به کار هیچ‌کدام نیاید، فقط حجم گزارش را بیشتر می‌کند.

۱. محدوده‌ی واقعاً آزمون‌شده، نه محدوده‌ی برنامه‌ریزی‌شده

صفحه‌ی اول باید دقیقاً بگوید چه چیزی در محدوده بوده و چه چیزی واقعاً آزمون شده است: نام دامنه‌ها، بازه‌های IP، نسخه‌ی برنامه‌ها، نقش‌های کاربری، محیط‌ها (عملیاتی، آزمایشی، نسخه‌ی کپی) و تاریخ‌ها. اگر سامانه‌ای در محدوده بوده ولی امکان آزمون آن فراهم نشده (سرویس از دسترس خارج بوده، اطلاعات ورود نرسیده، یا WAF آزمونگر را مسدود کرده و تنظیم نشده) گزارش باید صریحاً بنویسد. در غیر این صورت «نتیجه‌ی پاک» برای آن سامانه یک اطمینان کاذب است.

آنچه باید بخواهید: فهرست دارایی‌های آزمون‌شده با تاریخ آزمون هر یک، و فهرست استثناها با دلیل.

۲. روش‌شناسی و استاندارد

روش‌شناسی را نام ببرید و به آن پایبند بمانید. برای برنامه‌های وب معمولاً راهنمای OWASP WSTG و برای عمق بیشتر استاندارد ASVS؛ برای APIها فهرست OWASP API Security Top 10 و همان فصل‌های ASVS؛ برای زیرساخت، PTES یا مراحل NIST 800-115. ارزش این کار در خودِ نام اختصاری نیست؛ در این است که یک چک‌لیست نام‌دار به خواننده اجازه می‌دهد ببیند چه چیزی پیدا نشده، نه فقط چه چیزی پیدا شده.

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

این همان صفحه برای یک اپلیکیشن وب است، نگاشته به دوازده دسته‌ی WSTG. پروژه ساختگی است و تا پایان این مقاله همین پروژه را دنبال می‌کنیم.

دسته‌ی WSTG وضعیت یافته‌ها
INFO، گردآوری اطلاعات آزمون‌شده F-03
CONF، پیکربندی و استقرار خارج از محدوده: بستر ارائه‌دهنده‌ی میزبانی ندارد
IDNT، مدیریت هویت آزمون‌شده، چیزی پیدا نشد ندارد
ATHN، احراز هویت آزمون‌شده، چیزی پیدا نشد (بخش ۶) ندارد
ATHZ، مجوزدهی آزمون‌شده F-04 تا F-08
SESS، مدیریت نشست آزمون‌شده، چیزی پیدا نشد ندارد
INPV، اعتبارسنجی ورودی آزمون‌شده F-01
ERRH، مدیریت خطا آزمون‌شده F-02
CRYP، رمزنگاری آزمون‌شده، چیزی پیدا نشد ندارد
BUSL، منطق کسب‌وکار آزمون‌شده F-09
CLNT، سمت کلاینت آزمون‌شده، چیزی پیدا نشد ندارد
APIT، آزمون API آزمون‌شده F-04 و F-05

ردیف‌هایی که می‌گویند «چیزی پیدا نشد» به اندازه‌ی ردیف‌های یافته‌دار ارزش دارند، چون همین ردیف‌ها به ممیز نشان می‌دهند که آن بخش واقعاً بررسی شده است.

۳. خلاصه‌ی مدیریتی که یک مدیر بتواند بر اساس آن اقدام کند

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

۴. یافته‌ها، هر کدام در یک صفحه و با قالب ثابت

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

فیلد باید شامل چه باشد
عنوان خودِ ضعف، نه هشدار ابزار («جست‌وجوی سفارش، سفارش‌های مشتریان دیگر را نشان می‌دهد»، نه «IDOR پیدا شد»)
شدت یک درجه و دلیل آن، با یک طرح منتشرشده (امتیاز پایه‌ی CVSS v4 همراه با رشته‌ی بردار، یا رتبه‌بندی ریسک OWASP)
دارایی‌های متأثر نشانی‌ها، پارامترها، میزبان‌ها و نسخه‌های دقیق؛ آن‌قدر که بدون پرسیدن بتوان بازتولید کرد
بازتولید گام به گام، همراه با درخواست و پاسخ، و پنهان‌سازی فقط در جای لازم
اثر مهاجم واقعاً چه به دست می‌آورد: کدام داده، کدام حساب، کدام سامانه؛ با ادبیات کسب‌وکار مشتری
علت ریشه‌ای کنترل غایب، نه نشانه («مجوزدهی فقط سمت کلاینت بررسی می‌شود»)
رفع یک اصلاح مشخص و در صورت لزوم یک اقدام موقت؛ پیوند به استاندارد، نه پاراگرافی که از آن کپی شده
شواهد اسکرین‌شات یا ثبت ترافیکی که یافته را روی همان سامانه‌ی آزمون‌شده اثبات کند

یک یافته‌ی نمونه

یک یافته با همین قالب، از همان پروژه‌ی ساختگی روی API یک فروشگاه:

فیلد محتوا
شناسه و عنوان F-04 · جست‌وجوی سفارش، سفارش‌های مشتریان دیگر را برمی‌گرداند
شدت بالا، امتیاز پایه‌ی CVSS v4 برابر ۷٫۱: CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N. هر مشتریِ واردشده می‌تواند سفارش هر مشتری دیگری را (نام، نشانی، اقلام) بخواند؛ یکپارچگی و دسترس‌پذیری آسیبی نمی‌بینند
دارایی‌های متأثر GET https://shop.example/api/v2/orders/{order_id}، پارامتر order_id، نسخه‌ی ۴٫۲٫۱ API، نسخه‌ی کپی محیط آزمایشی، آزمون‌شده در روز سوم
بازتولید با حساب مشتری آزمایشی الف (مشتری ۵۵۳۱) وارد شوید و شناسه‌ی سفارشی را درخواست کنید که مال مشتری دیگری است؛ کل سفارش برمی‌گردد. شناسه‌ی سفارش‌ها پشت سر هم است، پس همه‌ی سفارش‌ها را می‌شود یکی‌یکی خواند
اثر داده‌ی شخصی همه‌ی مشتریانی که تا امروز سفارش داده‌اند: نام، نشانی تحویل و سابقه‌ی خرید
علت ریشه‌ای این مسیر API بررسی می‌کند که درخواست نشست معتبر دارد، نه اینکه سفارش مال مشتریِ همان نشست است
رفع مالکیت هر رکوردی که API برمی‌گرداند سمت سرور بررسی شود (علت ریشه‌ای را پایین‌تر ببینید). اقدام موقت: محدودیت نرخ برای جست‌وجوی سفارش، و هشدار وقتی یک نشست سفارش‌هایی جز سفارش‌های خودش را می‌خواند
شواهد درخواست و پاسخ زیر، ثبت‌شده روی همان سامانه‌ی آزمون‌شده
آزمون مجدد رفع‌شده: همان درخواست حالا 404 برمی‌گرداند
GET /api/v2/orders/100482 HTTP/1.1
Host: shop.example
Authorization: Bearer eyJ… (test customer A, customer_id 5531)

HTTP/1.1 200 OK
Content-Type: application/json

{"order_id": 100482, "customer_id": 5537, "name": "[redacted]",
 "address": "[redacted]", "items": 3, "total": 1840000}

نکته: داده‌ی شخصی را در شواهد پنهان کنید، اما هرگز بخشی را که یافته را اثبات می‌کند. این‌جا نام و نشانی پنهان شده‌اند و customer_id مانده است: ۵۵۳۷ همان ۵۵۳۱ درخواست‌کننده نیست و همین تفاوت، خودِ یافته است.

دو چیز گزارش قابل اقدام را از گزارش غیرقابل اقدام جدا می‌کند. نخست، شدت باید استدلال شود، نه اعلام: «بالا» بدون بردار هیچ معنایی ندارد. دوم، علت ریشه‌ای باید نام برده شود: پنج یافته با یک علت مشترک، یک اصلاح هستند و گزارش باید این را بگوید.

پنج یافته F-04 جست‌وجوی سفارش F-05 تغییر ایمیل F-06 دانلود فاکتور F-07 ویرایش نشانی F-08 لغو مرجوعی یک علت ریشه‌ای API بررسی می‌کند کاربر وارد شده، نه اینکه رکورد مال اوست یک اصلاح بررسی مالکیت سمت سرور در لایه‌ی دسترسی به داده، با یک آزمون برای هر API
پنج یافته، یک علت، یک اصلاح. گزارشی که این را بگوید، چهار تیکت جداگانه را از کار تیم کم می‌کند.

۵. زنجیره‌ها و اثر بر کسب‌وکار

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

یک نمونه از همان پروژه. آزمونگر کار را با یک حساب مشتری عادی شروع کرد:

نقطه‌ی شروع یک حساب مشتری عادی F-03 لینک معرفی، شناسه‌ی داخلی مشتری را لو می‌دهد پایین · ۲٫۳ F-05 تغییر ایمیل با شناسه‌ی هر مشتری پذیرفته می‌شود متوسط · ۶٫۰ تصاحب حساب بازنشانی گذرواژه به ایمیل مهاجم می‌رود زنجیره: بالا · ۸٫۵ امتیازها CVSS v4 پایه‌اند؛ بردار هر یافته در گزارش آمده است
دو یافته که هر کدام به‌تنهایی کوچک به نظر می‌رسند؛ با هم، حساب هر مشتری.

F-03 به‌تنهایی پایین است (CVSS v4 برابر ۲٫۳): لینک معرفی‌ای که مشتری با دیگران به اشتراک می‌گذارد، شناسه‌ی داخلی او را در خود دارد. F-05 به‌تنهایی متوسط است (۶٫۰): مسیری که ایمیل مشتری را عوض می‌کند شناسه‌ی هر مشتری را می‌پذیرد، ولی این شناسه‌ها حدس‌زدنی نیستند. کنار هم، شناسه‌ی لورفته به تغییر ایمیل می‌رسد، بازنشانی گذرواژه به نشانی مهاجم می‌رود و حساب تصاحب می‌شود: ۸٫۵، بالا، با امتیازدهی کل زنجیره. امتیاز هیچ‌کدام از این دو یافته به‌تنهایی به خلاصه‌ی مدیریتی نمی‌رسید؛ زنجیره می‌رسد.

۶. آنچه امتحان شد و جواب نداد

آزمونگری که یک روز روی جریان احراز هویت وقت گذاشته و چیزی پیدا نکرده، شاهد تولید کرده است. این باید در قالب بخشی کوتاه از نتایج منفی در گزارش بیاید: کدام دسته از حملات روی کدام اجزا امتحان شد. بدون آن، مشتری نمی‌تواند «امن» را از «بررسی‌نشده» تشخیص دهد.

۷. شرایط آزمون مجدد

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

در پروژه‌ی ساختگی، صفحه‌ی آزمون مجدد این شکل را دارد:

یافته وضعیت در آزمون مجدد توضیح
F-04 جست‌وجوی سفارش رفع‌شده همان درخواست 404 برمی‌گرداند
F-05 تغییر ایمیل رفع‌شده مالکیت بررسی می‌شود، پس زنجیره با F-03 شکسته است
F-06 دانلود فاکتور تا حدی رفع‌شده مالکیت بررسی می‌شود، ولی لینک‌های دانلودی که پیش از اصلاح صادر شده‌اند تا ۲۴ ساعت معتبر می‌مانند
F-03 لینک معرفی ریسک پذیرفته‌شده مالک: مدیر تجارت الکترونیک؛ با رفع F-05، شش ماه دیگر دوباره بررسی می‌شود

۸. پیوست‌هایی که در وقت صرفه‌جویی می‌کنند

خروجی اسکنرها، لاگ کامل درخواست‌ها، ابزارها و نسخه‌های استفاده‌شده، و یک خروجی ماشین‌خوان از یافته‌ها (CSV یا JSON) تا تیم فنی بتواند آن‌ها را به سامانه‌ی پیگیری خود وارد کند، نه این‌که دوباره تایپ کند. نسخه‌ی ماشین‌خوان لطف نیست؛ همان چیزی است که باعث می‌شود گزارش واقعاً پیگیری شود.

پرسش‌هایی که پیش از امضا باید بپرسید

۱. آیا گزارش می‌نویسد چه چیزی قابل آزمون نبود و چرا؟ ۲. پوشش آزمون به کدام استاندارد نگاشت می‌شود و آیا آن نگاشت را می‌بینم؟ ۳. آیا هر یافته شدتِ امتیازدهی‌شده با بردار، علت ریشه‌ای و مراحل بازتولید دارد؟ ۴. آیا آزمون مجدد وجود دارد و وضعیت‌ها چگونه گزارش می‌شوند؟ ۵. آیا یافته‌ها را در قالبی دریافت می‌کنم که سامانه‌ی پیگیری من بتواند وارد کند؟

پیمانکاری که به هر پنج پرسش بی‌درنگ پاسخ می‌دهد، دارد گزارشی را توصیف می‌کند که می‌توانید بر اساس آن اقدام کنید. اگر پاسخ هر کدام «می‌توانیم اضافه کنیم» بود، اول یک نمونه‌ی محرمانه‌زدایی‌شده بخواهید.