برای اینکه بتوانید دربارهی امنیت سامانهی خود تصمیم بگیرید — چه بودجهای بگذارید، چه سؤالی از پیمانکار بپرسید، کدام یافتهی گزارش را جدی بگیرید — نیازی نیست پنتستر شوید. اما به یک مدل ذهنی درست از سازوکار وب نیاز دارید. امنیت وب چیزی جدا از معماری وب نیست؛ مجموعهای از پیامدهای مستقیم همان معماری است. این مقاله همان مدل ذهنی را از پایه میسازد، بدون فرض دانش قبلی.
در یک نگاه
- وب بر پایهی HTTP کار میکند: پروتکلی بیحالت که هر درخواست را مستقل میبیند. تمام سازوکار «ورود کاربر» چیزی است که روی این بیحالتی ساخته شده.
- HTTPS فقط مسیر انتقال را رمزنگاری میکند. دربارهی درستی کد شما هیچ چیز نمیگوید.
- احراز هویت یعنی «تو کی هستی» و مجوزدهی یعنی «اجازهی چه کاری داری». اکثر رخنههای جدی از خرابی دومی میآیند.
- سیاست هممبدأ بنیادیترین مرز امنیتی مرورگر است؛ CORS آن را شل میکند، نه محکمتر.
- قاعدهای که همهچیز به آن برمیگردد: هیچ دادهای که از کلاینت میآید قابل اعتماد نیست — نه فیلد مخفی، نه اعتبارسنجی جاوااسکریپت، نه هدر.
امنیت وب چیست؟ یک تعریف کاربردی
امنیت وب یعنی حفظ سه ویژگی برای سامانه و دادهی شما:
- محرمانگی: فقط کسی که مجاز است، داده را ببیند. فاکتور مشتری الف نباید برای مشتری ب قابل مشاهده باشد.
- یکپارچگی: داده و کد فقط توسط افراد مجاز و از راههای مجاز تغییر کند. قیمت محصول نباید از سمت مرورگر کاربر قابل تغییر باشد.
- دسترسپذیری: سامانه در دسترس بماند و یک درخواست بدشکل کل سرویس را از پا نیندازد.
نکتهی مهم این است که هر سهی اینها را کد و پیکربندی خود شما تأمین میکند، نه یک محصول جانبی. یک برنامهی وب در ذات خود یک درِ باز به دنیاست: شما عمداً به میلیونها کاربر ناشناس اجازه میدهید کد شما را اجرا کنند و به پایگاهدادهی شما کوئری بزنند — البته با محدودیتهایی که خودتان تعریف کردهاید. امنیت وب، مهندسیِ همان محدودیتهاست.
در ادامه، هر لایه از این معماری را میبینیم و در هر لایه مشخص میکنیم چه چیزی میتواند خراب شود.
HTTP: پروتکلی که هیچچیز را به یاد نمیآورد
هر تعامل با یک سایت، یک درخواست (Request) از مرورگر و یک پاسخ (Response) از سرور است. شکل سادهشدهی یک درخواست:
GET /account/invoices HTTP/1.1
Host: example.com
Cookie: session=a1b2c3...
User-Agent: Mozilla/5.0 ...سه بخش را ببینید: متد (اینجا GET؛ متدهای دیگر POST، PUT، DELETE)، مسیر، و هدرها. پاسخ هم یک کد وضعیت دارد (۲۰۰ موفق، ۴۰۳ ممنوع، ۵۰۰ خطای سرور) بههمراه هدرها و بدنه.
حالا ویژگیای که همهچیز از آن نتیجه میشود: HTTP بیحالت (stateless) است. سرور بهطور طبیعی هیچ حافظهای از درخواست قبلی ندارد. از دید HTTP، درخواست دومِ همان کاربر یک غریبهی کامل است.
پس «کاربر وارد شده است» چطور کار میکند؟ با یک قطعه داده که مرورگر در هر درخواست دوباره ارسال میکند — همان که در مثال بالا در هدر Cookie دیدید. تمام امنیت نشست، از همین یک نقطه شروع میشود.
نکتهی عملی برای مدیران: هر چیزی که کاربر میفرستد — مسیر، پارامتر، هدر، کوکی، بدنه — کاملاً در کنترل اوست. مرورگر تنها یکی از راههای ساختن یک درخواست HTTP است. یک ابزار خط فرمان مثل curl یا یک پروکسی میانگیر میتواند هر درخواستی را با هر مقداری بسازد. این جمله بدیهی بهنظر میرسد اما ریشهی بخش بزرگی از آسیبپذیریهای واقعی است.
HTTPS و TLS: چه چیزی را محافظت میکنند و چه چیزی را نه
HTTP بهتنهایی متن روشن است؛ هر کسی در مسیر میتواند آن را بخواند و تغییر دهد. HTTPS همان HTTP است که داخل TLS پیچیده شده. TLS سه چیز میدهد:
- رمزنگاری: ناظر مسیر محتوا را نمیبیند.
- یکپارچگی: اگر کسی در مسیر داده را تغییر دهد، تشخیص داده میشود.
- هویت سرور: گواهی، تأیید میکند که شما با
example.comحرف میزنید نه با کسی که خود را جای آن زده است.
خط پایهی امروزی: TLS 1.3 فعال، TLS 1.2 فقط برای سازگاری و آن هم محدود به مجموعهرمزهای ECDHE با AEAD، و TLS 1.0 و 1.1 کاملاً غیرفعال — این دو رسماً منسوخ شدهاند و مذاکرهی آنها ممنوع است. هر چیزی با نام SSL از دو دهه پیش منسوخ است؛ اصطلاح «گواهی SSL» فقط یک نام تجاری جامانده است.
«سایت ما HTTPS دارد پس امن است.» قفل سبز مرورگر فقط میگوید مسیر رمزنگاری شده و هویت دامنه تأییدشده است. دربارهی اینکه کد شما تزریق SQL دارد یا نه، اینکه کنترل دسترسی درست است یا نه، یا اینکه پنل مدیریت با رمز admin باز میشود یا نه، هیچ چیز نمیگوید. یک سایت فیشینگ هم میتواند HTTPS داشته باشد. اگر با خطای گواهی روبهرو شدهاید، راهنمای خطای گواهی SSL علتهای رایج را توضیح میدهد.
یک تکمیل مهم: HTTPS داشتن کافی نیست، باید اجباری باشد. هدر Strict-Transport-Security (یعنی HSTS) به مرورگر میگوید این دامنه را همیشه با HTTPS باز کن — و همین جلوی حملهی تنزل به HTTP را میگیرد که یکی از سناریوهای رسمی سرقت کوکی نشست است.
کوکی و نشست: کلید خانهی کاربر
بعد از ورود موفق، سرور یک شناسهی نشست تصادفی میسازد، آن را در سمت خود به حساب کاربر گره میزند، و در قالب یک کوکی به مرورگر میدهد. از آن پس مرورگر آن کوکی را در هر درخواست به همان دامنه میفرستد. عملاً آن رشته، کلید خانهی کاربر است: هر کسی آن را داشته باشد، همان کاربر است.
پس سه چیز اهمیت حیاتی دارد: شناسه باید غیرقابل حدس باشد، در مسیر نشت نکند، و از سمت سرور قابل ابطال باشد. صفتهای کوکی ابزار همین کارند:
| صفت کوکی | کاری که میکند | چه چیزی را جلوگیری میکند |
|---|---|---|
Secure | کوکی فقط روی HTTPS ارسال میشود | نشت کوکی روی اتصال متنروشن |
HttpOnly | جاوااسکریپت به کوکی دسترسی ندارد | سرقت نشست از طریق XSS |
SameSite=Lax یا Strict | محدود کردن ارسال کوکی در درخواستهای بینسایتی | بخشی از CSRF — نه همهی آن |
پیشوند __Host- | کوکی را به دقیقاً همان دامنه و مسیر ریشه مقید میکند | تزریق کوکی از یک زیردامنه |
| انقضای کوتاه + ابطال سمت سرور | عمر مفید کلید دزدیدهشده را کم میکند | استفادهی طولانیمدت از نشست ربودهشده |
«همهی مرورگرها امروز بهصورت پیشفرض SameSite=Lax اعمال میکنند، پس CSRF حل شده است.» کروم این کار را میکند، اما فایرفاکس نه — موزیلا این تغییر را پس از مشاهدهی خرابی گستردهی وب کنار گذاشت و باگ مربوطه با وضعیت WONTFIX بسته شد. سافاری هم سازوکار متفاوتی دارد. نتیجه: توکن CSRF سمت سرور همچنان الزامی است، و صفت SameSite را باید صریحاً خودتان تعیین کنید نه اینکه به پیشفرض مرورگر کاربر تکیه کنید.
احراز هویت در برابر مجوزدهی: تفاوتی که همهچیز است
این دو مفهوم مدام با هم اشتباه گرفته میشوند، در حالی که تفاوتشان مرز میان یک برنامهی سالم و یک رخنهی داده است.
- احراز هویت (Authentication) پاسخ به «تو کی هستی؟» است. ورود با رمز عبور، کد یکبارمصرف، ورود با گوگل — همه احراز هویتاند.
- مجوزدهی (Authorization) پاسخ به «اجازهی انجام این کار روی این داده را داری؟» است. و این پرسش باید در هر درخواست و برای هر رکورد پرسیده شود.
خطای کلاسیک این است که برنامه فقط اولی را انجام دهد: «کاربر وارد شده است، پس اجازه دارد». نتیجهاش این میشود که کاربر ثبتنامشدهی الف با تغییر یک شماره در آدرس، دادهی کاربر ب را میبیند. نام فنی این خانواده IDOR است و زیرمجموعهی کنترل دسترسی شکسته است — که در فهرست OWASP Top 10:2025 رتبهی یک را دارد و OWASP گزارش میکند در دادهی این نسخه، ۱۰۰٪ برنامههای آزمودهشده نوعی نقص کنترل دسترسی داشتهاند.
دو نکته که مدیران باید از این بخش با خود ببرند. اول: پنهان کردن دکمه در رابط کاربری، مجوزدهی نیست. دوم: شناسههای تصادفی و طولانی هم مجوزدهی نیستند — UUID فقط هزینهی حدس زدن را بالا میبرد و هیچ بررسی دسترسی اضافه نمیکند. مجوزدهی درست یعنی کوئری شما ذاتاً محدود به مالک باشد، نه اینکه بعد از خواندن رکورد چیزی چک شود.
همینجا روشن میشود چرا هیچ اسکنر خودکاری این دسته را پیدا نمیکند: ابزار نمیداند کاربر شمارهی ۵ باید رکورد شمارهی ۷ را ببیند یا نه. این تشخیص به فهم قواعد کسبوکار نیاز دارد و همین است که تست نفوذ دستی را از اسکن جدا میکند.
سیاست هممبدأ: مرز امنیتی مرورگر
مرورگر شما در همان لحظه چند سایت را باز دارد. چه چیزی مانع میشود که یک تب مخرب، محتوای تب بانک شما را بخواند؟ پاسخ: سیاست هممبدأ (Same-Origin Policy یا SOP).
«مبدأ» ترکیب سه چیز است: پروتکل، دامنه و پورت. یعنی https://example.com و http://example.com و https://api.example.com سه مبدأ متفاوت هستند. قاعدهی SOP این است: جاوااسکریپتِ یک مبدأ نمیتواند پاسخ درخواست به مبدأ دیگر را بخواند. توجه کنید که ارسال درخواست معمولاً ممکن است؛ چیزی که ممنوع میشود خواندن پاسخ است. همین تفکیک ظریف، دلیل وجود CSRF است: درخواست میرود و اثرش را میگذارد، حتی اگر مهاجم پاسخ را نبیند.
گاهی لازم است این محدودیت را عمداً شل کنید — مثلاً وقتی برنامهی تکصفحهای شما روی یک دامنه است و API روی دامنهی دیگر. سازوکار استاندارد این کار CORS است: سرور با هدرهایی مثل Access-Control-Allow-Origin اعلام میکند کدام مبدأها اجازهی خواندن پاسخ را دارند.
«CORS یک قابلیت امنیتی است که از API ما محافظت میکند.» دقیقاً برعکس. CORS سیاست هممبدأ را شل میکند؛ هرگز چیزی به امنیت اضافه نمیکند. یک تنظیم سهلانگارانهی CORS محافظت را برمیدارد. بدترین حالت رایج، سروری است که هر مبدأیی را که در درخواست بیاید بازتاب میدهد و در کنارش Access-Control-Allow-Credentials: true میفرستد — این یعنی هر سایتی میتواند دادهی احراز هویتشدهی کاربران شما را بخواند.
مرز اعتماد: هیچچیزی از کلاینت قابل اعتماد نیست
اگر از این مقاله فقط یک جمله را به یاد بسپارید، این باشد: هر چیزی که از سمت کلاینت میآید، دادهی تحت کنترل مهاجم است. جاوااسکریپت شما روی دستگاه کاربر اجرا میشود و کاربر مالک آن دستگاه است. بنابراین همهی این موارد قابل تغییرند:
- مقدار فیلدهای فرم، از جمله فیلدهای
hiddenوdisabled. - هر اعتبارسنجی سمت کلاینت —
maxlength، الگوی regex در HTML، بررسی جاوااسکریپتی فرم. - هدرها، از جمله
User-Agent،Refererو هدرهای سفارشی برنامه. - کوکیهایی که با
HttpOnlyمحافظت نشدهاند، و هر چیزی درlocalStorage. - ترتیب و توالی درخواستها — مهاجم میتواند مرحلهی دو را بدون مرحلهی یک صدا بزند.
- قیمت، تخفیف، شناسهی کاربر و نقش، اگر در بدنهی درخواست ارسال میشوند.
پیامد عملی این قاعده در طراحی: هر اعتبارسنجی سمت کلاینت فقط برای تجربهی کاربری است و باید عیناً در سمت سرور تکرار شود. اگر منطق «مبلغ نهایی» در مرورگر محاسبه و به سرور فرستاده میشود، سرور باید آن را دور بیندازد و خودش محاسبه کند. اگر «نقش کاربر» در توکن یا فیلد فرم میآید، سرور باید نقش را از پایگاهدادهی خودش بخواند.
همینجا مفهوم سطح حمله (Attack Surface) معنا پیدا میکند: هر نقطهای که دادهی بیرونی وارد سامانه میشود. فرمها، پارامترهای URL، APIها، آپلود فایل، وبهوکها، هدرها، و حتی نام فایلی که کاربر آپلود میکند. برای هر یک از این نقاط، این پرسش را بپرسید: «اگر این مقدار چیزی جز آنچه انتظار دارم باشد، چه میشود؟» — که تعریف عملی مدلسازی تهدید است. برای درک تفاوت باگ معمولی و آسیبپذیری، آسیبپذیری چیست را ببینید.
هدرهای امنیتی: دستورهایی که به مرورگر میدهید
بخشی از دفاع، در مرورگر کاربر اجرا میشود — بهشرط اینکه سرور شما به مرورگر بگوید چه کار کند. این کار با هدرهای پاسخ انجام میشود:
| هدر | چه میکند | یادداشت عملی |
|---|---|---|
Strict-Transport-Security | مرورگر را مجبور میکند همیشه HTTPS استفاده کند | با max-age طولانی؛ پیش از فعالسازی مطمئن شوید همهی زیردامنهها HTTPS دارند |
Content-Security-Policy | مشخص میکند کدام اسکریپتها اجازهی اجرا دارند | مؤثرترین شکلش CSP بر پایهی nonce است، نه فهرست دامنه |
X-Content-Type-Options: nosniff | جلوی حدس زدن نوع محتوا توسط مرورگر را میگیرد | ارزان و بدون عارضه؛ همیشه فعال کنید |
Referrer-Policy | محدود میکند چه بخشی از آدرس به سایتهای بیرونی نشت کند | مانع نشت توکن یا شناسه از طریق آدرس |
frame-ancestors در CSP | جلوی جاسازی صفحه در iframe سایت دیگر را میگیرد | جانشین مدرن X-Frame-Options برای Clickjacking |
یک هشدار مهم دربارهی CSP: نوشتن سیاستی که فهرستی از دامنههای مجاز باشد، در عمل تقریباً همیشه قابل دور زدن است. پژوهش گوگل روی سیاستهای واقعی نشان داد ۱۴ دامنه از ۱۵ دامنهی پرکاربرد در فهرستهای مجاز، اندپوینت ناامن داشتند و اکثریت قاطع سیاستهای بررسیشده قابل دور زدن بودند. شکل درست، سیاست بر پایهی nonce همراه با strict-dynamic است. و مهمتر: CSP یک کاهندهی اثر است، نه اصلاح آسیبپذیری. اگر XSS دارید، CSP آسیب را کم میکند اما باگ سر جایش است.
مدل ذهنی نهایی و قدم بعدی
همهی مطالب بالا را میتوان در پنج جمله خلاصه کرد که بقیهی مباحث امنیت وب روی آنها ساخته میشوند:
- HTTP بیحالت است؛ نشست چیزی است که خودتان روی آن ساختهاید و باید از آن مثل کلید خانه محافظت کنید.
- HTTPS مسیر را ایمن میکند، برنامه را نه.
- احراز هویت کافی نیست؛ مجوزدهی باید در هر درخواست و برای هر رکورد بررسی شود.
- سیاست هممبدأ مرز مرورگر است؛ CORS آن را شل میکند.
- هیچ دادهای از کلاینت قابل اعتماد نیست — سرور مرجع نهایی است.
با این مدل ذهنی، بقیهی مباحث معنا پیدا میکنند. برای دیدن اینکه این مفاهیم در ده دستهی رسمی ریسک چطور دستهبندی میشوند، راهنمای امنیت وب اپلیکیشن را بخوانید. اگر مالک سایت هستید و بهدنبال کارهای عملی هستید، راهنمای امنیت سایت نقطهی شروع مناسبتری است. و برای مرور اصطلاحات فنی، دانشنامهی پیهانتر — از CSRF و CORS تا TLS — هر مفهوم را جداگانه توضیح میدهد.
اگر میخواهید بدانید این مفاهیم در سامانهی خودتان چقدر درست پیاده شدهاند، مشاورهی اولیه نقطهی شروع بدون هزینهای است و میتوانید سؤالهای همین مقاله را مبنای گفتگو قرار دهید.
پرسشهای متداول
امنیت وب چیست و شامل چه چیزهایی میشود؟
امنیت وب یعنی حفظ محرمانگی، یکپارچگی و دسترسپذیری برنامهی وب و دادهی آن. در عمل شامل امنسازی کد برنامه، مدیریت نشست و احراز هویت، کنترل دسترسی، پیکربندی درست سرور و TLS، هدرهای امنیتی مرورگر، مدیریت وابستگیها، و ثبت رخداد و پایش میشود.
آیا HTTPS داشتن به این معنی است که سایت من امن است؟
نه. HTTPS فقط مسیر انتقال داده را رمزنگاری میکند و هویت دامنه را تأیید میکند. اگر کد شما تزریق SQL دارد، پنل مدیریت رمز ضعیف دارد، یا کنترل دسترسی درست پیاده نشده، HTTPS هیچ کمکی نمیکند. سایتهای فیشینگ هم HTTPS دارند.
تفاوت احراز هویت و مجوزدهی چیست؟
احراز هویت مشخص میکند کاربر کیست (ورود با رمز، کد یکبارمصرف). مجوزدهی مشخص میکند آن کاربر اجازهی چه کاری روی چه دادهای را دارد. اکثر رخنههای جدی از خرابی مجوزدهی میآید — کاربری که درست وارد شده اما به دادهی دیگران دسترسی پیدا میکند.
سیاست هممبدأ چیست و چرا مهم است؟
سیاست هممبدأ قاعدهی بنیادی مرورگر است که مانع میشود جاوااسکریپت یک سایت، پاسخ درخواستها به سایت دیگر را بخواند. مبدأ ترکیب پروتکل، دامنه و پورت است. این سیاست دلیل آن است که یک تب مخرب نمیتواند محتوای تب بانک شما را بخواند. CORS سازوکاری برای شل کردن کنترلشدهی همین سیاست است.
چرا میگویند نباید به دادهی سمت کلاینت اعتماد کرد؟
چون جاوااسکریپت شما روی دستگاه کاربر اجرا میشود و کاربر مالک آن دستگاه است. فیلد مخفی، اعتبارسنجی فرم، هدرها و حتی ترتیب درخواستها همه قابل تغییرند — با ابزارهایی مثل curl یا یک پروکسی میتوان هر درخواستی با هر مقداری ساخت. پس هر اعتبارسنجی و هر محاسبهی حساس باید در سمت سرور تکرار شود.
بهعنوان مدیری که برنامهنویس نیست، از کجا شروع کنم؟
سه پرسش را از تیم فنی بپرسید و پاسخ مکتوب بگیرید: آیا کنترل دسترسی در سمت سرور و برای هر رکورد بررسی میشود؟ آیا همهی پنلهای مدیریت احراز هویت چندعاملی دارند؟ آیا فهرست کتابخانههای استفادهشده و نسخههایشان را داریم و چه کسی CVEها را رصد میکند؟ پاسخ این سه سؤال وضعیت کلی شما را نشان میدهد.
