# Вградените функции за сигурност на PHP

> Функциите за сигурност на PHP накратко: пароли, случайност, екраниране, криптография, сесии и къде са границите им при уязвимости като PHP2Shell.

Източник: https://phpsos.de/bg/php/eingebaute-sicherheitsfunktionen/  
Актуалност: 25.10.2026  
Доставчик: PHP SOS, Спешна помощ за PHP и сигурност на сървъри. Незабавна помощ по WhatsApp: https://wa.me/491736494914?text=%D0%97%D0%B4%D1%80%D0%B0%D0%B2%D0%B5%D0%B9%D1%82%D0%B5%2C%20PHP%20SOS%2C%20%D0%B8%D0%BC%D0%B0%D0%BC%D0%B5%20%D0%BD%D1%83%D0%B6%D0%B4%D0%B0%20%D0%BE%D1%82%20%D0%BF%D0%BE%D0%BC%D0%BE%D1%89%20%D1%81%20%D0%BD%D0%B0%D1%88%D0%B8%D1%8F%20PHP%20%D1%81%D1%8A%D1%80%D0%B2%D1%8A%D1%80.%20%D0%A4%D0%B8%D1%80%D0%BC%D0%B0%3A%20%E2%80%A6%20%D0%A3%D0%B5%D0%B1%D1%81%D0%B0%D0%B9%D1%82%3A%20%E2%80%A6

**Накратко:** За най-честите задачи по сигурността PHP носи готови, проверени функции: `password_hash()` за пароли, `random_bytes()` и `random_int()` за токени, `htmlspecialchars()` срещу cross-site scripting, подготвени заявки с PDO срещу SQL инжекция, `hash_equals()` за сигурни сравнения и разширението Sodium за криптография. Който използва последователно тези градивни елементи, избягва повечето пробиви в приложенията. Срещу грешки в самия интерпретатор на PHP, както при PHP2Shell, те не помагат; там помага само актуализацията.

## Защо вградени функции за сигурност в PHP?

Да се пише код за сигурност сам, е податливо на грешки. Собствен хеш на пароли, самостоятелно направен генератор на токени или домашно измайсторен филтър за HTML изход често изглеждат правилни, а не са. Вградените функции са документирани, тествани и се поддържат с актуализациите на PHP.

За вземащите решения това означава: питайте Вашата агенция или Вашия екип за разработка не дали функциите за сигурност са писани сами, а дали се използват стандартните функции на езика. Таблицата дава преглед.

| Задача | Функция | Налична от | Важна бележка |
|---|---|---|---|
| Съхраняване на пароли | `password_hash()`, `password_verify()` | PHP 5.5 | колона до 255 знака; bcrypt съкращава до 72 байта |
| Случайни токени | `random_bytes()`, `random_int()` | PHP 7.0 | никога `rand()` или `mt_rand()` за тайни |
| Случайност обектно-ориентирано | `Random\Randomizer` | PHP 8.2 | същата сигурност, по-гъвкав интерфейс |
| Екраниране на HTML изход | `htmlspecialchars()` | открай време | флаговете по подразбиране от 8.1 екранират и единични кавички |
| Сравнение с постоянно време | `hash_equals()` | PHP 5.6 | въвеждането от потребителя като втори аргумент |
| Съвременна криптография | Sodium (`sodium_*`) | PHP 7.2 | вместо собствено криптиране |
| Тайни в stack trace | `#[\SensitiveParameter]` | PHP 8.2 | стойността не се появява в trace |
| Проверка на въвеждани данни | `filter_var()` | PHP 5.2 | проверява формата, не замества екранирането |

## Пароли и токени

`password_hash()` създава осолен хеш, `password_verify()` го проверява. С `PASSWORD_DEFAULT` PHP използва в момента bcrypt; от PHP 8.4 коефициентът на разходите по подразбиране според ръководството е 12 вместо 10. Тъй като алгоритъмът по подразбиране може да се промени, ръководството препоръчва колона в базата данни с 255 знака. При bcrypt паролите се отрязват след 72 байта, което трябва да се има предвид при много дълги пропозиции за парола.

```php
<?php
// Регистрация
$hash = password_hash($passwort, PASSWORD_DEFAULT);

// Вход, включително автоматично обновяване на стари хешове
if (password_verify($eingabe, $hash)) {
    if (password_needs_rehash($hash, PASSWORD_DEFAULT)) {
        $hash = password_hash($eingabe, PASSWORD_DEFAULT); // съхраняване наново
    }
}

// Токен за връзка за възстановяване на парола
$token = bin2hex(random_bytes(32));
```

За сравнения на тайни, например на подпис, трябва да се използва `hash_equals()`. Обикновеното сравнение с `===` според ръководството може да издаде чрез времето за изпълнение от кое място две стойности се различават. По-подробно: [Сигурно съхраняване на пароли в PHP](https://phpsos.de/bg/blog/passwoerter-in-php-speichern/) и [сигурни случайни числа и токени](https://phpsos.de/bg/blog/sichere-tokens-php/).

## Екраниране на изхода и сигурни заявки към базата данни

Cross-site scripting възниква, когато въвеждани от потребители данни попаднат нефилтрирани в HTML. `htmlspecialchars()` превръща специалните знаци в HTML ентитита. От PHP 8.1 флаговете по подразбиране са `ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401`; преди това единичните кавички не се преобразуваха. Който трябва да поддържа по-стари версии, задава флаговете изрично.

SQL инжекцията се предотвратява с подготвени заявки. Стойностите се предават отделно от SQL текста и не могат да променят заявката:

```php
<?php
$stmt = $pdo->prepare('SELECT id, name FROM kunden WHERE email = :email');
$stmt->execute(['email' => $email]);
$kunde = $stmt->fetch();

echo htmlspecialchars($kunde['name'] ?? '', ENT_QUOTES, 'UTF-8');
```

Подробностите са в [Предотвратяване на cross-site scripting в PHP](https://phpsos.de/bg/ratgeber/xss-php/) и на страницата за SQL инжекция.

Проверката на въвеждани данни е втора, отделна стъпка. `filter_var()` установява дали една стойност има валиден формат, например имейл адрес или цяло число в разрешен диапазон. Това обаче не замества нито екранирането при изхода, нито подготвената заявка, защото и формално валидни стойности могат да съдържат специални знаци.

## Тайните да не попадат в съобщенията за грешки

Подценявано изтичане на данни са stack trace. Ако във функция възникне грешка, PHP записва веригата от извиквания заедно с аргументите. Ако там има парола или API ключ, той попада в лога. От PHP 8.2 атрибутът `#[\SensitiveParameter]` отбелязва такива параметри; стойността им в trace се появява тогава само като обект `SensitiveParameterValue`.

```php
<?php
function anmelden(string $benutzer, #[\SensitiveParameter] string $passwort): bool
{
    // ... проверка ...
    throw new RuntimeException('Datenbank nicht erreichbar');
}
```

Според бележка в ръководството атрибутът действа само върху конкретната реализация, не върху метода на интерфейс. Затова го задавайте там, където кодът действително се изпълнява.

## Сесии: сигурни настройки и нови стандарти

Сесиите са често срещана цел на атаки. Три настройки са централни: `session.use_strict_mode=1` отхвърля идентификатори на сесии, които сървърът не е създал сам; `session.cookie_httponly=1` предотвратява достъпа до бисквитката на сесията чрез JavaScript; `session.cookie_samesite=Lax` затруднява изпращането ѝ към чужди сайтове. Според приетия RFC точно тези три стойности стават стандарт с PHP 8.6. Задайте ги сами дотогава, а и след това изрично, за да не зависи конфигурацията от стойността по подразбиране.

```ini
session.use_strict_mode = 1
session.cookie_httponly = 1
session.cookie_samesite = Lax
session.cookie_secure = 1
```

Повече има в [Защита на сесиите в PHP](https://phpsos.de/bg/ratgeber/session-sicherheit-php/).

## Какво вградените функции не постигат

Проектът PHP в политиката си за сигурност е ясен: PHP не е sandbox. Заобикалянето на `open_basedir` или `disable_functions`, злонамерените входни данни към `unserialize()` и непроверените аргументи към функции като `mysqli_query()` не се считат за уязвимости на PHP. За операторите това означава: тези настройки са полезно заздравяване, но не граница на сигурността, а `unserialize()` няма работа с чужди данни.

Втората точка засяга PHP2Shell. CVE-2026-109618 и CVE-2026-109619 според php.net позволяват изпълнение на код, преди или докато приложението Ви работи; при mod_php е показан експлойт, преди изобщо да се изпълни код на приложението. Никоя функция във Вашия код не може да го улови. Сигурното програмиране и актуалната версия на PHP са две отделни задължения и и двете трябва да бъдат изпълнени.

## Как помага PHP SOS конкретно?

В [одита на сигурността за PHP приложения](https://phpsos.de/bg/leistungen/sicherheitsaudit-penetrationstest/) проверяваме целенасочено:

- **Работа с пароли и токени:** Използват ли се `password_hash()` и `random_bytes()`, или има собствени разработки?
- **Изходи и заявки:** Къде въвежданите данни попадат нефилтрирани в HTML, SQL или команди на шела?
- **Конфигурация на сесиите:** Зададени ли са Strict Mode, HttpOnly, SameSite и Secure и не могат ли да се презаписват?
- **Среда за изпълнение:** Работи ли поддържана версия на PHP с корекциите от 21.10.2026 г.?


## Често задавани въпроси

**Как се съхраняват правилно паролите в PHP?**  
С password_hash() и PASSWORD_DEFAULT, а проверката е с password_verify(). Колоната в базата данни според ръководството трябва да побира до 255 знака, защото алгоритъмът по подразбиране може да се промени в бъдеще.

**rand() подходящ ли е за токени?**  
Не. За токени, ключове и връзки за парола трябва да се използват random_bytes() или random_int(). Според ръководството те дават криптографски сигурни случайни стойности.

**Откога Sodium е част от PHP?**  
Разширението Sodium за съвременна криптография е част от PHP от версия 7.2.0. По-старите версии можеха да го добавят само чрез PECL.

**Тези функции защитават ли от PHP2Shell?**  
Не. Те защитават от грешки във Вашето приложение. PHP2Shell се намира в самия интерпретатор и се затваря само чрез актуализация на PHP, последвана от рестартиране на всички PHP процеси.

**Променят ли се стандартите за сесии в PHP 8.6?**  
Да, според приетия RFC session.use_strict_mode и session.cookie_httponly се включват по подразбиране, а session.cookie_samesite се задава на Lax. Съществуващите конфигурации все пак трябва сами да зададете изрично.

## Източници

- [Ръководство на PHP: password_hash()](https://www.php.net/manual/en/function.password-hash.php)
- [Ръководство на PHP: random_bytes()](https://www.php.net/manual/en/function.random-bytes.php)
- [Ръководство на PHP: hash_equals()](https://www.php.net/manual/en/function.hash-equals.php)
- [PHP RFC: Secure Session Configuration Defaults](https://wiki.php.net/rfc/session_security_defaults)
- [OWASP Cheat Sheet Series](https://cheatsheetseries.owasp.org/)
