HTTP از دید یک توسعهدهنده و متخصص امنیت؛ معماری Request/Response، Headerها، Cookieها و نقاط حمله
وقتی یک کاربر آدرس یک وبسایت را در مرورگر وارد میکند، اتفاقی بسیار بیشتر از نمایش یک صفحه HTML رخ میدهد. مرورگر و سرور از طریق مجموعهای از پیامها با یکدیگر ارتباط برقرار میکنند؛ پیامهایی که در دنیای وب معمولاً با پروتکل HTTP منتقل میشوند.
برای یک توسعهدهنده، HTTP فقط مجموعهای از متدهای GET و POST نیست. برای یک متخصص امنیت نیز HTTP صرفاً راهی برای انتقال اطلاعات محسوب نمیشود؛ بلکه سطح بزرگی از حملات وب در همین لایه شکل میگیرد. درک دقیق Request، Response، Headerها، Cookieها، Status Codeها و نحوه پردازش آنها، یکی از پایههای مهم توسعه وب امن است.
در این مقاله HTTP را از دو زاویه بررسی میکنیم: ابتدا مانند یک توسعهدهنده یاد میگیریم که ارتباط مرورگر و سرور چگونه ساخته و پردازش میشود و سپس با نگاه امنیتی بررسی میکنیم که همین اجزا چگونه میتوانند به نقطهای برای سوءاستفاده تبدیل شوند.
فهرست مطالب
HTTP چیست؟
HTTP مخفف HyperText Transfer Protocol است و یکی از پروتکلهای اصلی ارتباط در وب محسوب میشود. وظیفه HTTP تعریف نحوه ارسال درخواست از سمت Client و نحوه پاسخگویی Server است.
وقتی وارد یک وبسایت میشوید، مرورگر شما در نقش Client قرار میگیرد و برای دریافت منابع موردنیاز مانند HTML، CSS، JavaScript، تصویر یا دادههای API، درخواستهایی را به Server ارسال میکند. Server نیز پس از پردازش درخواست، یک Response برمیگرداند.
نکته مهم این است که HTTP خودش مسئول همه چیز نیست. DNS میتواند نام دامنه را به IP تبدیل کند، TCP یا QUIC مسئول انتقال داده در لایههای پایینتر هستند و TLS در حالت HTTPS وظیفه ایجاد ارتباط رمزنگاریشده را بر عهده دارد. HTTP بیشتر مشخص میکند که پیام وب چه ساختاری داشته باشد و Client و Server چگونه درباره منابع و عملیات با یکدیگر صحبت کنند.
یک مثال ساده
فرض کنید کاربر آدرس زیر را باز میکند:
https://example.com/products
مرورگر ابتدا باید مقصد را پیدا کند و سپس یک ارتباط مناسب با سرور برقرار کند. در ادامه یک درخواست
HTTP برای مسیر /products ارسال میشود. سرور این درخواست را دریافت کرده، آن را پردازش
میکند و در نهایت Response مناسب را برمیگرداند.
این Response ممکن است شامل HTML باشد، یا در یک Web API شامل JSON، یا حتی یک Status Code مانند
404 یا 500 باشد.
معماری ارتباط HTTP چگونه است؟
یکی از مهمترین مفاهیمی که یک توسعهدهنده وب باید بهخوبی درک کند، مدل Client → Request → Server → Response → Client است.
در سادهترین حالت، Client یک درخواست ایجاد میکند. درخواست به Server میرسد، Server آن را پردازش میکند و نتیجه را در قالب Response ارسال میکند.
Client
```
|
| HTTP Request
v
Server
|
| HTTP Response
v
Client
```
اما در پروژههای واقعی، معماری معمولاً پیچیدهتر است. ممکن است درخواست ابتدا به CDN، Reverse Proxy، Load Balancer یا Web Application Firewall برسد و سپس به Application Server منتقل شود.
Browser
```
|
v
DNS
|
v
CDN / Reverse Proxy
|
v
Load Balancer
|
v
Web Application
|
+------> Database
|
+------> Cache
|
+------> External API
```
این موضوع از دید امنیت اهمیت زیادی دارد؛ زیرا هر لایه ممکن است Headerها را تغییر دهد، درخواست را فیلتر کند، اطلاعاتی به آن اضافه کند یا حتی تصمیم بگیرد که درخواست اصلاً به Application نرسد.
HTTP Stateless است؛ یعنی چه؟
HTTP بهصورت ذاتی یک پروتکل Stateless است. یعنی هر Request بهطور مستقل از Request قبلی در نظر گرفته میشود و پروتکل HTTP بهتنهایی حافظهای از وضعیت Client نگه نمیدارد.
اما برنامههای وب معمولاً Stateful به نظر میرسند؛ برای مثال وقتی وارد حساب کاربری خود میشوید، در صفحات مختلف همچنان شناسایی میشوید.
این وضعیت معمولاً با مکانیزمهایی مانند Cookie، Session، Token و سایر روشهای مدیریت هویت ایجاد میشود؛ موضوعی که در ادامه مقاله از نظر امنیتی بررسی خواهیم کرد.
```Request و Response دقیقاً چه هستند؟
اگر بخواهیم HTTP را در سادهترین شکل ممکن توضیح دهیم، باید دو مفهوم اصلی آن را بشناسیم: Request و Response.
HTTP Request
Request پیامی است که Client برای درخواست یک منبع یا انجام یک عملیات به Server ارسال میکند. این پیام میتواند مشخص کند که چه متدی استفاده شده، چه مسیری درخواست شده، چه Headerهایی وجود دارند و آیا دادهای در Body ارسال شده است یا خیر.
HTTP Response
Response پاسخی است که Server در مقابل Request ارسال میکند. این پاسخ معمولاً شامل Status Code، Headerها و در بسیاری از موارد Body است.
برای مثال، اگر Client درخواست دریافت صفحه اصلی را ارسال کند، Server ممکن است پاسخی مانند زیر تولید کند:
HTTP/1.1 200 OK
```
Content-Type: text/html
Welcome
```
در این مثال 200 OK نشان میدهد که درخواست با موفقیت پردازش شده و
Content-Type نوع داده موجود در Response Body را مشخص میکند.
ساختار یک HTTP Request
برای اینکه بتوانیم رفتار HTTP را تحلیل کنیم، باید Request را از نزدیک بررسی کنیم. یک HTTP Request معمولاً از بخشهای زیر تشکیل میشود:
- Request Line
- HTTP Headers
- خط خالی برای جدا کردن Headerها از Body
- Request Body در صورت نیاز
یک نمونه Request ساده:
GET /products?id=15 HTTP/1.1
```
Host: example.com
User-Agent: Mozilla/5.0
Accept: application/json
Accept-Language: fa-IR
Connection: keep-alive
```
Request Line
خط اول مشخص میکند که Client چه عملیاتی را روی چه Resourceای درخواست کرده و از چه نسخهای از HTTP استفاده میکند.
GET /products?id=15 HTTP/1.1
- GET متد درخواست است.
- /products?id=15 مسیر و Query String است.
- HTTP/1.1 نسخه پروتکل است.
Query String چیست؟
بخش بعد از علامت ? معمولاً Query String نام دارد.
/products?id=15&sort=price
در این مثال دو پارامتر به سرور ارسال شدهاند:
id=15sort=price
از دید توسعهدهنده، Query String برای فیلتر، جستوجو، مرتبسازی و موارد مشابه بسیار کاربردی است. اما از دید امنیتی نباید تصور کرد که داده موجود در URL قابل اعتماد است.
هر چیزی که Client ارسال میکند، از جمله Query Parameter، باید ورودی غیرقابل اعتماد (Untrusted Input) در نظر گرفته شود.
مثال امنیتی
GET /profile?id=15 HTTP/1.1
برنامه نباید صرفاً بر اساس مقدار id تصمیم بگیرد که کاربر اجازه مشاهده اطلاعات
چه حسابی را دارد.
فرض کنید کاربر فعلی صاحب حساب شماره 15 است و برنامه این URL را میپذیرد:
/profile?id=15
اگر کاربر مقدار را به شکل زیر تغییر دهد:
/profile?id=16
Application باید علاوه بر معتبر بودن ID، مجوز دسترسی کاربر فعلی به Resource شماره 16 را نیز بررسی کند.
اینجا یک اصل مهم امنیتی مطرح میشود: Authentication بهتنهایی کافی نیست؛ Authorization نیز باید در سمت Server اعمال شود.
```ساختار یک HTTP Response
Response نیز ساختار مشخصی دارد و معمولاً از Status Line، Headerها و Body تشکیل میشود.
HTTP/1.1 200 OK
```
Content-Type: application/json
Content-Length: 48
{
"id": 15,
"name": "Ali"
}
```
Status Line
اولین خط Response معمولاً شامل نسخه HTTP، کد وضعیت و عبارت توضیحی آن است.
HTTP/1.1 200 OK
مهمترین بخش این خط برای توسعهدهنده معمولاً Status Code است.
Response Body
Body حاوی دادهای است که Server قصد دارد به Client برگرداند. این داده میتواند HTML، JSON، XML، فایل، تصویر یا نوع دیگری از محتوا باشد.
برای مثال یک API ممکن است Response زیر را برگرداند:
HTTP/1.1 200 OK
```
Content-Type: application/json
{
"success": true,
"user": {
"id": 15,
"name": "Ali"
}
}
```
نکته امنیتی مهم این است که Response نیز میتواند اطلاعات حساسی را افشا کند. برای مثال ارسال اطلاعات داخلی سیستم، Stack Trace، مسیر فایلها، Connection String یا جزئیات بیش از حد درباره خطاها میتواند به مهاجم برای شناسایی ساختار برنامه کمک کند.
```متدهای HTTP و کاربرد آنها
HTTP Method مشخص میکند Client چه نوع عملیاتی را از Server درخواست کرده است. متدها صرفاً نامهایی مانند GET و POST نیستند؛ انتخاب صحیح Method روی طراحی API، Cache، رفتار مرورگر و حتی امنیت برنامه تأثیر میگذارد.
GET
GET معمولاً برای دریافت Resource استفاده میشود.
GET /api/products/15 HTTP/1.1
```
Host: example.com
```
در طراحی صحیح، GET نباید باعث تغییر وضعیت مهم یا عملیات مخرب روی Server شود.
POST
POST معمولاً برای ارسال داده یا ایجاد یک عملیات در سمت Server استفاده میشود.
POST /api/users HTTP/1.1
```
Host: example.com
Content-Type: application/json
{
"name": "Ali",
"email": "[ali@example.com](mailto:ali@example.com)"
}
```
PUT
PUT معمولاً برای ایجاد یا جایگزینی کامل یک Resource در یک URI مشخص استفاده میشود. معنای دقیق آن به طراحی API نیز وابسته است.
PATCH
PATCH معمولاً برای اعمال تغییرات جزئی روی یک Resource استفاده میشود.
PATCH /api/users/15 HTTP/1.1
```
Content-Type: application/json
{
"name": "Reza"
}
```
DELETE
DELETE برای درخواست حذف یک Resource استفاده میشود.
DELETE /api/users/15 HTTP/1.1
HEAD
HEAD مشابه GET است، با این تفاوت که Server معمولاً Body را ارسال نمیکند و اطلاعات مربوط به Response را از طریق Headerها در اختیار Client قرار میدهد.
OPTIONS
OPTIONS برای دریافت اطلاعاتی درباره قابلیتها و متدهای پشتیبانیشده توسط یک Resource کاربرد دارد و در سازوکار CORS نیز نقش مهمی دارد.
نکته امنیتی درباره HTTP Methodها
یکی از اشتباهات رایج این است که توسعهدهنده تصور کند استفاده از POST بهتنهایی یک عملیات را امن میکند. امنیت عملیات به کنترل دسترسی، اعتبارسنجی ورودی، مدیریت Session، CSRF Protection و سایر کنترلهای امنیتی وابسته است، نه صرفاً به نام Method.
```HTTP Status Codeها و مفهوم آنها
Status Code به Client اعلام میکند که نتیجه پردازش Request چه بوده است. این کدها در پنج گروه اصلی قرار میگیرند.
| گروه | مفهوم |
|---|---|
| 1xx | اطلاعاتی |
| 2xx | موفقیت |
| 3xx | Redirect |
| 4xx | خطای سمت Client یا درخواست نامعتبر |
| 5xx | خطای سمت Server |
200 OK
درخواست با موفقیت پردازش شده است.
201 Created
معمولاً زمانی استفاده میشود که یک Resource جدید ایجاد شده باشد.
204 No Content
درخواست با موفقیت پردازش شده اما Response Body محتوایی ندارد.
301 و 302
این Status Codeها برای Redirect استفاده میشوند و تفاوتهای معنایی و رفتاری مهمی دارند. در طراحی امنیتی، Redirectها باید با دقت کنترل شوند.
400 Bad Request
Server نتوانسته Request را بهعنوان یک درخواست معتبر پردازش کند.
401 Unauthorized
معمولاً زمانی استفاده میشود که Client برای دسترسی به Resource نیاز به احراز هویت دارد یا اعتبارنامه ارائهشده معتبر نیست.
403 Forbidden
Server درخواست را درک کرده اما اجازه انجام عملیات یا دسترسی به Resource را نمیدهد.
404 Not Found
Resource موردنظر پیدا نشده است.
405 Method Not Allowed
Method مورد استفاده برای Resource موردنظر مجاز نیست.
429 Too Many Requests
معمولاً برای زمانی استفاده میشود که Client در یک بازه زمانی تعداد زیادی درخواست ارسال کرده و Rate Limiting فعال شده است.
500 Internal Server Error
Server در پردازش درخواست با یک خطای داخلی مواجه شده است.
502 Bad Gateway و 503 Service Unavailable
این کدها در معماریهای چندلایه و سرویسهای توزیعشده اهمیت زیادی دارند و میتوانند نشانهای از مشکل در سرویس بالادستی یا در دسترس نبودن موقت سرویس باشند.
```Headerهای HTTP چیستند؟
Headerها یکی از مهمترین قسمتهای HTTP هستند. آنها اطلاعاتی درباره Request یا Response منتقل میکنند و میتوانند روی نحوه پردازش، Cache، Content Negotiation، Authentication، امنیت مرورگر و بسیاری از رفتارهای دیگر تأثیر بگذارند.
یک Header معمولاً ساختاری شبیه زیر دارد:
Header-Name: Header-Value
برای مثال:
Content-Type: application/json
در اینجا Server اعلام میکند محتوای Body از نوع JSON است.
Host
Header مربوط به Host مشخص میکند درخواست برای کدام Host ارسال شده است و در HTTP/1.1 بخش مهمی از Request محسوب میشود.
Host: example.com
User-Agent
User-Agent معمولاً اطلاعاتی درباره Client یا نرمافزاری که Request را ارسال کرده ارائه میدهد.
User-Agent: Mozilla/5.0
نکته امنیتی مهم: User-Agent را نباید یک هویت قابل اعتماد یا مکانیزم احراز هویت در نظر گرفت؛ Client میتواند مقدار آن را تغییر دهد.
Accept
این Header مشخص میکند Client چه نوع Contentهایی را ترجیح میدهد.
Accept: application/json
Content-Type
Content-Type نوع داده موجود در Body را مشخص میکند.
Content-Type: application/json
این Header در APIها اهمیت زیادی دارد؛ زیرا Server باید داده ورودی را بر اساس نوع محتوای مورد انتظار پردازش کند و در صورت نیاز، دادههای نامعتبر را رد کند.
Authorization
Authorization معمولاً برای ارسال Credential یا Token به Server استفاده میشود.
Authorization: Bearer eyJhbGciOi...
Tokenهای احراز هویت باید مانند اطلاعات حساس در نظر گرفته شوند. ثبت کردن آنها در Log، نمایش آنها در URL یا ارسال آنها از طریق کانال ناامن میتواند پیامدهای جدی داشته باشد.
Referer
این Header میتواند اطلاعاتی درباره صفحهای که درخواست از آنجا ایجاد شده ارائه کند. مقدار آن در بعضی شرایط ممکن است شامل URL یا بخشی از اطلاعات مسیر باشد؛ بنابراین نباید اطلاعات حساس را بدون توجه در URL قرار داد.
```HTTP از دید یک متخصص امنیت
یک متخصص امنیت به HTTP فقط بهعنوان یک پروتکل انتقال داده نگاه نمیکند. تقریباً هر بخشی از Request و Response میتواند بخشی از Attack Surface یک برنامه باشد.
مهاجم میتواند Request را مشاهده و در محیطهای مجاز تست امنیتی تغییر دهد، پارامترها را دستکاری کند، Headerهای مختلف را آزمایش کند و رفتار Application را در شرایط غیرعادی بررسی کند.
بنابراین یک اصل مهم در توسعه امن وجود دارد:
هر دادهای که از Client وارد Server میشود، بالقوه غیرقابل اعتماد است.
این دادهها فقط شامل Form Input نیستند. موارد زیر نیز باید در مدل تهدید در نظر گرفته شوند:
- Query Parameter
- Path Parameter
- Request Body
- HTTP Header
- Cookie
- File Upload
- Authentication Token
- اطلاعات ارسالشده توسط Client
یک مثال مهم از اعتماد اشتباه به Header
تصور کنید Application بر اساس یک Header سفارشی تصمیم بگیرد کاربر داخلی است:
X-Internal-User: true
اگر Server مستقیماً به مقدار این Header اعتماد کند، مهاجم میتواند همان Header را در Request قرار دهد و در صورت نبود کنترل مناسب، مسیر امنیتی برنامه را دور بزند.
Headerهایی که از سمت Client دریافت میشوند، بهصورت پیشفرض قابل اعتماد نیستند. اگر معماری برنامه به Header خاصی اعتماد میکند، باید مشخص باشد این Header توسط چه مؤلفهای تولید شده، در چه مرزی معتبر است و چگونه از جعل آن جلوگیری میشود.
مرز اعتماد یا Trust Boundary
در یک معماری واقعی ممکن است Request از چندین مؤلفه عبور کند. برای مثال:
Internet
```
↓
Reverse Proxy
↓
Load Balancer
↓
Application
↓
Database
```
یکی از پرسشهای مهم امنیتی این است که Application به کدام اطلاعاتی که از لایههای قبلی دریافت میکند اعتماد دارد.
برای نمونه Headerهایی مانند X-Forwarded-For یا
X-Forwarded-Proto در معماریهای پشت Proxy کاربرد زیادی دارند، اما نحوه اعتماد به
آنها باید متناسب با معماری و تنظیمات Proxy انجام شود.
سه اصل مهم برای تحلیل HTTP در توسعه امن
۱. Client را قابل اعتماد فرض نکنید
Client تحت کنترل کامل شما نیست. حتی اگر درخواست از مرورگر رسمی برنامه شما آمده باشد، کاربر یا ابزارهای تست میتوانند Request را تغییر دهند.
۲. Validation و Authorization را از هم جدا کنید
Validation بررسی میکند داده از نظر شکل و قوانین قابل قبول است یا خیر؛ Authorization بررسی میکند آیا این کاربر اجازه انجام عملیات موردنظر را دارد یا خیر.
۳. خطاها را بیش از حد افشا نکنید
خطای مناسب برای کاربر همیشه همان اطلاعاتی نیست که برای توسعهدهنده مفید است. نمایش Stack Trace، مسیر فایلها، نام کلاسها یا جزئیات داخلی Database در محیط Production میتواند اطلاعات ارزشمندی در اختیار مهاجم قرار دهد.
```









