---
title: 'Уеб атаки и защита: XSS, CSRF, SQLi, SSRF, IDOR и качване на файлове | DevSense'
description: 'Атаките, които ще срещнете най-често в уеб приложенията: инжектиране (SQL/command), XSS, CSRF, IDOR и грешки при контрол на достъпа, SSRF, опасни файлови качвания, clickjacking и конфигурационни капани. Практически защити, заглавия и списъци.'
faq:
    - { question: 'Защо санирането на HTML вход не е достатъчно за предотвратяване на SQL инжекции?', answer: 'SQL инжекцията възниква, когато недоверени данни се конкатенират директно в SQL заявки. Санирането на HTML премахва тагове като `<script>`, но не предотвратява знаци като кавички или точки и запетаи да променят структурата на SQL заявката. Единственото сигурно решение е използването на параметризирани заявки (подготвени изрази).' }
    - { question: 'Могат ли SameSite бисквитките напълно да заменят CSRF токените?', answer: 'Въпреки че `SameSite=Lax` или `Strict` защитава срещу крос-сайт заявки в съвременните браузъри, те не предоставят пълна гаранция за сигурност. По-старите браузъри може да не поддържат SameSite, а грешки или промени на състоянието чрез GET заявки могат да заобиколят тази защита. CSRF токените остават важна част от ешелонираната защита.' }
    - { question: 'Каква е разликата между SSRF и CSRF?', answer: 'CSRF принуждава браузъра на потребителя да изпрати заявка към приложение, в което потребителят е удостоверен. SSRF принуждава *сървъра* на приложението да изпраща неоторизирани заявки към вътрешни ресурси (като метаданни на облака или вътрешен Redis), които не са достъпни от публичния интернет.' }
    - { question: 'Защо проверката само на разширението на файла при качване е опасна?', answer: 'Атакуващите могат лесно да заобиколят проверката на разширението (например чрез двойни разширения или преименуване) или да експлоатират уязвимости, при които сървърът изпълнява файлове с правилно разширение, но с вредно съдържание (например PHP код вграден в PNG). Трябва да валидирате реалния тип на съдържанието (MIME тип) и да съхранявате файловете извън уеб корена.' }
published: '2026-05-31'
---
# Уеб атаки и методи за защита, които всеки разработчик трябва да знае

Вашето приложение работи безпроблемно, трафикът расте, а последното внедряване премина без нито един проблем. Но изведнъж една некоректна заявка от неидентифициран потребител изтрива таблица в базата данни, или вътрешна микроуслуга изтича лични данни на клиенти в интернет поради уязвимост в HTTP клиент. Сигурността почти винаги се проваля **по шевовете**: има валидация, но не и на границата; има авторизация, но един еднпойнт е пропуснат; данните се екранират, но на едно място в шаблона е използван raw HTML. Добрата новина е, че повечето реални инциденти попадат в повтарящи се класове грешки — което означава, че можете да ги предотвратите системно.

**Свързани ръководства:** [Наблюдаемост и мониторинг](observability-monitoring-laravel) · [Бази данни под натоварване](database-performance-and-scaling)

## Съдържание

* [Модел на заплахите: какво защитаваме и от кого](#threat-model)
* [Инжектиране: SQLi, command injection, template injection](#injection)
* [XSS: рефлектиран, съхраняван, DOM-based](#xss)
* [CSRF: защо „но това е GET“ не е защита](#csrf)
* [Автентификация и сесии: кражба на токени, фиксация, бисквитки](#auth-sessions)
* [Контрол на достъпа и IDOR: „това е просто id“](#idor)
* [Качване на файлове и пътища: качвания, траверсиране, RCE наблизо](#uploads)
* [SSRF: когато сървърът прави заявки към „грешното място“](#ssrf)
* [Небезопасна десериализация и подмяна на обекти](#deserialization)
* [Защити на браузъра: clickjacking, CORS, заглавки](#browser)
* [DoS и злоупотреби: ограничения на честотата, брутфорс, скъпи операции](#dos)
* [Чести грешки](#common-mistakes)
* [Контролен списък при издаване на версия](#checklist)
* [Тест за самопроверка](#self-test-quiz)

---

<a id="threat-model"></a>
## Модел на заплахите: какво защитаваме и от кого

Преди да пишем код за сигурност, трябва да зафиксираме параметрите на заплахите:

- **Атакуващ**: анонимен потребител, вписан потребител, партньор с API ключ, потребител във VPN, атакуващ с достъп до CI/CD.
- **Активи**: пари, лични данни, акаунти, админ панел, интеграции, тайни (secrets), достъп до вътрешната мрежа.
- **Повърхност на атаката**: форми и API, пренасочвания, уебхукове, импорт/експорт на данни, качване на файлове, външни интеграции (S3, SMTP, разплащания).

> [!NOTE]
> **Прагматично правило за сигурност**
> Винаги приемайте, че всеки вход от потребителя е злонамерен. Това включва заглавки, бисквитки, webhook payloads, URL параметри и съобщения, прочетени от опашки.

---

<a id="injection"></a>
## Инжектиране: SQLi, command injection, template injection

### SQL инжекция (SQLi)

SQLi обикновено започва като „само един суров SQL фрагмент“. Решението не е „екраниране“, а **параметризиране**.

**Лошо** (конкатенация):
```php
// app/Http/Controllers/UserController.php
$rows = DB::select("SELECT * FROM users WHERE email = '{$email}'");
```

**По-добре** (placeholder-и):
```php
// app/Http/Controllers/UserController.php
$rows = DB::select('SELECT * FROM users WHERE email = ?', [$email]);
```

Друг чест капан са **динамичните имена на колони / сортиране**. Параметрите не важат за SQL идентификатори, затова използвайте строг allowlist:
```php
// app/Http/Controllers/UserController.php
$allowed = ['created_at', 'email', 'id'];
$sort = in_array($request->get('sort'), $allowed, true) ? $request->get('sort') : 'created_at';

$users = User::query()->orderBy($sort, 'desc')->paginate();
```

### Command injection

Ако извиквате шел, правилото е: **никога не подавайте потребителски вход в командния ред**. Дори `escapeshellarg()` е предпазна мярка от краен случай, а не сигурен дизайн.

Ако се налага да използвате CLI инструменти (за конвертиране на файлове, генериране на прегледи):
- Предпочитайте библиотека пред `exec()`.
- Ако CLI е неизбежен — дефинирайте точно бинарния файл, аргументите и директориите и изпълнявайте в ограничена среда (контейнер/опашка/worker под отделен потребител).

### Template injection

Опасният случай е да позволите на потребителите да дефинират шаблони, които се изпълняват като Blade/Twig/Smarty.
- **Правило**: Потребителският шаблон трябва да се третира само като данни, най-добре през силно ограничен формат (например Markdown със строг allowlist и безопасно рендиране).

---

<a id="xss"></a>
## XSS: рефлектиран, съхраняван, DOM-based

XSS е изпълнение на JavaScript в контекста на вашия домен. Типични източници:
- Извеждане на данни „както са си“ (`{!! ... !!}` в Blade, `innerHTML` във фронтенда).
- Полета с форматиран текст, съхранявани без саниране.
- Вмъкване на данни в `<script>` или HTML атрибути без правилно енкодване.

### Основни защити

- **Екраниране по подразбиране**: в Blade използвайте `{{ $value }}`; избягвайте директен изход без валидна причина.
- **Разделяйте контекстите**: HTML срещу атрибути срещу JS низове срещу URL адреси — те имат различни правила за енкодване.
- **Саниране на HTML входа**: ако позволявате форматиране, използвайте allowlist (тагове/атрибути) и премахвайте `on*` манипулатори, `javascript:` URL-и и т.н.
- **CSP**: не поправя логиката, но драстично намалява щетите от XSS.

Стартов CSP (идеално — с nonces и без `'unsafe-inline'`):
```http
# /etc/nginx/nginx.conf
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'
```

---

<a id="csrf"></a>
## CSRF: защо „но това е GET“ не е защита

CSRF се случва, когато браузърът на потребителя изпрати заявка към вашия сайт с неговите бисквитки/сесия, тъй като друг сайт тригерира това (чрез форми, изображения, JS).

### Защити

- **CSRF токени** за променящи състоянието заявки (POST/PUT/PATCH/DELETE) — Laravel прави това по подразбиране.
- **`SameSite` бисквитки**: поне `Lax`; помислете за `Strict` за чувствителни потоци; за крос-сайт случаи използвайте `None; Secure`.
- **Проверки на Origin/Referer** за особено критични действия (смяна на имейл, плащания).
- **Никога не променяйте състоянието чрез GET**.

---

<a id="auth-sessions"></a>
## Автентификация и сесии: кражба на токени, фиксация, бисквитки

Какво обикновено се компрометира:
- Слаби пароли + липса на rate limiting → credential stuffing.
- Кражба на сесия чрез XSS; фиксация на сесия; липса на инвалидация при изход.
- Дълготрайни токени без ротация и без обвързване с устройство.

### Основни контроли

- **Rate limit** на вход/OTP/възстановяване на парола.
- **Хеширане на пароли** само с `password_hash` (bcrypt/argon2), без персонализирани схеми.
- **Бисквитки** на сесията: `HttpOnly`, `Secure`, `SameSite`, с кратък живот.
- **Ротация на session ID** след вход и промяна на правата.

---

<a id="idor"></a>
## Контрол на достъпа и IDOR: „това е просто id“

IDOR (Insecure Direct Object Reference) възниква, когато потребителят може да отгатне/обходи идентификатори и да чете или променя чужди данни.

Чести причини:
- Проверка „вписан потребител“ вместо проверка за собственост или роля.
- Авторизацията съществува в UI, но не и в API.
- Параметър в заявката управлява администраторско поведение.

### Защити

- **Политики/гейтове (Policies/gates)** за всеки ресурс и действие.
- При мулти-тенант приложения винаги филтрирайте по `tenant_id`/`account_id` на ниво заявка към БД.
- Не разчитайте на скриването на елементи в потребителския интерфейс.

```php
// app/Http/Controllers/OrderController.php
// Препоръчително е да филтрирате заявката според текущия потребител:
$order = auth()->user()->orders()->findOrFail($id);

// Вместо директно търсене по цялата таблица:
$order = Order::findOrFail($id);
```

---

<a id="uploads"></a>
## Качване на файлове и пътища: качвания, траверсиране, RCE наблизо

Качването на файлове е класическо място за RCE атаки в съседни директории.

### Какво да наложите

- Валидирайте **съдържанието**, а не само разширението. MIME типът от браузъра не е надежден.
- Лимити на размера и броя файлове.
- Съхранявайте файловете извън уеб корена (web-root); сервирайте ги чрез контролер или специален домен/CDN.
- Случайни имена на файловете (не се доверявайте на оригиналното име).
- Забрана за изпълнение на скриптове в директорията за качвания (на ниво уеб сървър).

```nginx
# /etc/nginx/conf.d/uploads.conf
location /uploads {
    location ~ \.php$ {
        deny all;
    }
}
```

Path traversal често се проявява като „изтегли файл по име“:
- Отхвърляйте `../`, `\`, нулиращи байтове (null bytes).
- Използвайте allowlist с реални файлове/ID-та, а не път от заявката.

---

<a id="ssrf"></a>
## SSRF: когато сървърът прави заявки към „грешното място“

SSRF се случва, когато приемате URL от потребителя и **правите заявка от името на сървъра** (импорт на аватар, webhook tester, линк преглед).

Рискове: достъп до **вътрешни услуги** (metadata endpoints на облачни платформи, Redis/Consul, админ панели), заобикаляне на мрежови контроли.

### Защити

- **Allowlist на домени/хостове**, а не blacklist.
- **Блокиране на частни IP диапазони** (127.0.0.0/8, 10.0.0.0/8, 169.254.0.0/16, 172.16.0.0/12, 192.168.0.0/16, ::1, fc00::/7).
- **Изключване на пренасочванията** или валидиране на всеки хоп.
- **Таймаути**, ограничение на размера на отговора, само https.

---

<a id="deserialization"></a>
## Небезопасная десериализация и подмяна на обекти

Ако десериализирате данни, контролирани от атакуващ (бисквитки, скрити полета, payloads от външни опашки, несигниран кеш), рискувате:
- Подмяна на роли или полета.
- Gadget chains и изпълнение на отдалечен код (RCE).

> [!NOTE]
> **Целостност на данните**
> Никога не съхранявайте сериализирани PHP/JS обекти в ненадеждни места. Използвайте подпис (HMAC) за токени, а за структурирани данни — JSON с 엄격на валидация по схема от сървъра.

---

<a id="browser"></a>
## Защити на браузъра: clickjacking, CORS, заглавки

### Clickjacking

Блокирайте рамкирането (framing):
```http
# /etc/nginx/nginx.conf
X-Frame-Options: DENY
Content-Security-Policy: frame-ancestors 'none'
```

### CORS

CORS не блокира заявки, а е правило на браузъра за четене на отговорите. Чести грешки:
- `Access-Control-Allow-Origin: *` заедно с бисквитки/credentials.
- Твърде широки позволени методи/заглавки.
- Доверие към `Origin` без строг списък.

### Базови заглавки за сигурност
```http
# /etc/nginx/nginx.conf
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: geolocation=(), microphone=(), camera=()
```

---

<a id="dos"></a>
## DoS и злоупотреби: ограничения на честотата, брутфорс, скъпи операции

В бизнес приложенията най-честият DoS е от евтини за атакуващия и много скъпи за вас заявки:
- Търсене без индекси, експорт на големи файлове, генериране на PDF.
- Липса на rate limit на критични точки (вход, изпращане на имейл/OTP, „проверка на промокод“).
- Сложни регулярни изрази върху огромни текстове.

### Контроли
- Rate limiting по IP + акаунт + API ключ.
- Опашки за скъпа работа.
- Таймаути, лимити на размера и ограничения на дълбочината на JSON.
- Кеширане на тежки публични отговори.

---

<a id="common-mistakes"></a>
## Чести грешки

1. **Доверие на валидацията от страна на клиента**: Прилагане на валидации само във формите на фронтенда и пропускане на серверната валидация, което позволява заобикаляне директно през API.
2. **Използване на суров SQL в ORDER BY**: Понеже плейсхолдърите не важат за имената на колони, разработчиците конкатенират параметри директно в заявката, създавайки уязвимост от SQL инжекция.
3. **Черни списъци с IP за SSRF**: Опит за блокиране само на `127.0.0.1` или `10.0.0.1`, като се забравят шестнадесетични формати (`0x7f.0.0.1`), осмични формати или атаки от типа DNS Rebinding.
4. **Небезопасно използване на unserialize()**: Съхранение на сериализирани PHP обекти в бисквитка на потребителя с надеждата, че той няма да ги промени, което води до PHP Object Injection.

---

<a id="checklist"></a>
## Контролен списък при издаване на версия

### Вход и данни
- [ ] Валидация на границата на системата (форми/API/webhooks), нормализиране на типовете.
- [ ] Allowlist за сортиране/филтри/полета, които се превръщат в идентификатори в SQL заявки.
- [ ] Без промяна на състоянието чрез GET.

### Рендиране и браузър
- [ ] Екраниране по подразбиране, без неоправдан raw HTML.
- [ ] CSP/`frame-ancestors`, защита от clickjacking.
- [ ] HSTS, `nosniff`, адекватен `Referrer-Policy`.

### Достъп
- [ ] Сървърна авторизация за всяко действие (policy/gate), не само в потребителския интерфейс (UI).
- [ ] Без IDOR: заявките се филтрират според собственика/tenant-а.
- [ ] Одит логове за чувствителни действия.

### Интеграции
- [ ] Контрол на SSRF: allowlist на домени, блокиране на вътрешни IP адреси, лимити и таймаути.
- [ ] Webhooks: проверка на подпис, защита срещу replay атаки, идемпотентност.

### Качвания
- [ ] Проверки на тип и размер, съхраняване извън web-root, забрана за изпълнение.
- [ ] Случайни имена, без използване на пътища от потребителския вход.

---

## Извод

Сигурността не е краен продукт, а поддържане на инварианти по границите на системата. Входните данни винаги се проверяват на входа, изходът се екранира по подразбиране, правата се проверяват от сървъра при всяко действие, а външните интеграции се защитават с подписи и лимити.

---

<a id="self-test-quiz"></a>
## Тест за самопроверка

### Въпрос 1: Какъв е основният проблем със сигурността в следния код?
```php
// app/Http/Controllers/DownloadController.php
return response()->download(storage_path('reports/' . $request->get('file')));
```
- А) SQL инжекция.
- Б) Cross-Site Scripting (XSS).
- В) Path Traversal (Произволно изтегляне на файлове).

<details>
<summary>Кликнете, за да видите отговора</summary>

**Отговор: В**
Тъй като входът `$request->get('file')` се конкатенира директно в пътя без проверка за `../`, атакуващият може да подаде `file=../../.env` за да прочете тайни конфигурационни файлове.
</details>

### Въпрос 2: Защо са необходими CSRF токени за POST заявки, ако сесийната бисквитка е маркирана със `SameSite=Lax`?
- А) `SameSite=Lax` не предотвратява POST заявки, стартирани от навигация от най-високо ниво или скриптове на по-стари браузъри.
- Б) CSRF токените предотвратяват SQL инжекции.
- В) Без CSRF токен сесийната бисквитка изобщо не може да бъде прочетена.

<details>
<summary>Кликнете, за да видите отговора</summary>

**Отговор: А**
Атрибутите SameSite са добра защита, но те не гарантират 100% сигурност поради проблеми със съвместимостта на някои браузъри, уязвимости в поддомени или промяна на състояние чрез GET заявки.
</details>