# Wbudowane funkcje bezpieczeństwa PHP

> Funkcje bezpieczeństwa PHP w skrócie: hasła, losowość, maskowanie, kryptografia, sesje i granice ich skuteczności przy lukach takich jak PHP2Shell.

Źródło: https://phpsos.de/pl/php/eingebaute-sicherheitsfunktionen/  
Stan: 25.10.2026  
Dostawca: PHP SOS, Pomoc awaryjna PHP i bezpieczeństwo serwerów. Natychmiastowa pomoc przez WhatsApp: https://wa.me/491736494914?text=Dzie%C5%84%20dobry%2C%20PHP%20SOS%2C%20potrzebujemy%20pomocy%20z%20naszym%20serwerem%20PHP.%20Firma%3A%20%E2%80%A6%20Strona%20internetowa%3A%20%E2%80%A6

**Krótko:** PHP dostarcza gotowe, sprawdzone funkcje do najczęstszych zadań bezpieczeństwa: `password_hash()` dla haseł, `random_bytes()` i `random_int()` dla tokenów, `htmlspecialchars()` przeciw cross-site scriptingowi, przygotowane zapytania z PDO przeciw SQL injection, `hash_equals()` dla bezpiecznych porównań i rozszerzenie Sodium dla kryptografii. Kto konsekwentnie używa tych elementów, unika większości luk w aplikacjach. Przed błędami w samym interpreterze PHP, jak w PHP2Shell, nie chronią; tam pomaga tylko aktualizacja.

## Dlaczego wbudowane funkcje bezpieczeństwa PHP?

Samodzielne pisanie kodu bezpieczeństwa jest podatne na błędy. Własny hash hasła, samodzielnie zbudowany generator tokenów albo własny filtr dla danych wyjściowych HTML często wyglądają poprawnie, a mimo to nie są. Wbudowane funkcje są udokumentowane, przetestowane i utrzymywane wraz z aktualizacjami PHP.

Dla osób podejmujących decyzje oznacza to: niech Państwo nie pytają agencji ani zespołu deweloperskiego, czy funkcje bezpieczeństwa zbudowano samodzielnie, lecz czy używane są standardowe funkcje języka. Tabela daje przegląd.

| Zadanie | Funkcja | Dostępna od | Ważna uwaga |
|---|---|---|---|
| Przechowywanie haseł | `password_hash()`, `password_verify()` | PHP 5.5 | kolumna do 255 znaków; bcrypt ucina do 72 bajtów |
| Losowe tokeny | `random_bytes()`, `random_int()` | PHP 7.0 | nigdy `rand()` ani `mt_rand()` dla sekretów |
| Losowość obiektowo | `Random\Randomizer` | PHP 8.2 | to samo bezpieczeństwo, elastyczniejszy interfejs |
| Maskowanie wyjścia HTML | `htmlspecialchars()` | od zawsze | domyślne flagi od 8.1 maskują także apostrofy |
| Porównanie w stałym czasie | `hash_equals()` | PHP 5.6 | dane od użytkownika jako drugi argument |
| Nowoczesna kryptografia | Sodium (`sodium_*`) | PHP 7.2 | zamiast własnego szyfrowania |
| Sekrety w stacktrace | `#[\SensitiveParameter]` | PHP 8.2 | wartość nie pojawia się w trace |
| Sprawdzanie danych wejściowych | `filter_var()` | PHP 5.2 | sprawdza format, nie zastępuje maskowania |

## Hasła i tokeny

`password_hash()` tworzy zasolony hash, `password_verify()` go sprawdza. Z `PASSWORD_DEFAULT` PHP używa obecnie bcrypt; od PHP 8.4 domyślny współczynnik kosztu wynosi według podręcznika 12 zamiast 10. Ponieważ domyślny algorytm może się zmienić, podręcznik zaleca kolumnę w bazie danych na 255 znaków. W bcrypt hasła są ucinane po 72 bajtach, co trzeba uwzględnić przy bardzo długich frazach.

```php
<?php
// Rejestracja
$hash = password_hash($passwort, PASSWORD_DEFAULT);

// Logowanie, z automatycznym uaktualnieniem starych hashy
if (password_verify($eingabe, $hash)) {
    if (password_needs_rehash($hash, PASSWORD_DEFAULT)) {
        $hash = password_hash($eingabe, PASSWORD_DEFAULT); // zapisać na nowo
    }
}

// Token dla linku do resetu hasła
$token = bin2hex(random_bytes(32));
```

Do porównywania sekretów, na przykład podpisu, należy używać `hash_equals()`. Zwykłe porównanie z `===` może według podręcznika zdradzić przez czas działania, od którego miejsca dwie wartości się różnią. Szerzej: [Bezpieczne przechowywanie haseł w PHP](https://phpsos.de/pl/blog/passwoerter-in-php-speichern/) oraz [bezpieczne liczby losowe i tokeny](https://phpsos.de/pl/blog/sichere-tokens-php/).

## Maskowanie wyjścia i bezpieczne zapytania do bazy danych

Cross-site scripting powstaje, gdy dane od użytkownika trafiają do HTML bez filtrowania. `htmlspecialchars()` zamienia znaki specjalne na encje HTML. Od PHP 8.1 domyślnymi flagami są `ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401`; wcześniej apostrofy nie były zamieniane. Kto musi obsługiwać starsze wersje, podaje flagi wprost.

SQL injection zapobiegają przygotowane zapytania. Wartości są przekazywane oddzielnie od tekstu SQL i nie mogą zmienić zapytania:

```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');
```

Szczegóły znajdują się w artykule [Zapobieganie cross-site scriptingowi w PHP](https://phpsos.de/pl/ratgeber/xss-php/) oraz na stronie o SQL injection.

Sprawdzanie danych wejściowych to drugi, oddzielny krok. `filter_var()` stwierdza, czy wartość ma prawidłowy format, na przykład adres e-mail lub liczbę całkowitą w dozwolonym zakresie. Nie zastępuje to jednak maskowania na wyjściu ani przygotowanego zapytania, ponieważ także formalnie prawidłowe wartości mogą zawierać znaki specjalne.

## Trzymanie sekretów z dala od komunikatów o błędach

Niedocenianym wyciekiem danych są stacktrace. Gdy w funkcji wystąpi błąd, PHP zapisuje w logu łańcuch wywołań wraz z argumentami. Jeśli znajduje się tam hasło lub klucz API, trafia do logu. Od PHP 8.2 atrybut `#[\SensitiveParameter]` oznacza takie parametry; ich wartość pojawia się wtedy w trace tylko jako obiekt `SensitiveParameterValue`.

```php
<?php
function anmelden(string $benutzer, #[\SensitiveParameter] string $passwort): bool
{
    // ... sprawdzenie ...
    throw new RuntimeException('Datenbank nicht erreichbar');
}
```

Według uwagi w podręczniku atrybut działa tylko w konkretnej implementacji, a nie w metodzie interfejsu. Proszę go więc ustawiać tam, gdzie kod faktycznie działa.

## Sesje: bezpieczne ustawienia i nowe standardy

Sesje są częstym celem ataków. Trzy ustawienia są kluczowe: `session.use_strict_mode=1` odrzuca identyfikatory sesji, których serwer sam nie wygenerował; `session.cookie_httponly=1` uniemożliwia dostęp do ciasteczka sesji przez JavaScript; `session.cookie_samesite=Lax` utrudnia dołączanie go na obcych stronach. Według przyjętego RFC właśnie te trzy wartości staną się w PHP 8.6 domyślne. Proszę ustawić je samodzielnie do tego czasu, a także później wprost, aby konfiguracja nie zależała od ustawień domyślnych.

```ini
session.use_strict_mode = 1
session.cookie_httponly = 1
session.cookie_samesite = Lax
session.cookie_secure = 1
```

Więcej w artykule [Zabezpieczanie sesji w PHP](https://phpsos.de/pl/ratgeber/session-sicherheit-php/).

## Czego wbudowane funkcje nie zapewniają

Projekt PHP jest w swojej polityce bezpieczeństwa wyraźny: PHP nie jest sandboxem. Obejścia `open_basedir` lub `disable_functions`, złośliwe dane przekazywane do `unserialize()` i niesprawdzone argumenty funkcji takich jak `mysqli_query()` nie są uznawane za luki bezpieczeństwa PHP. Dla operatorów oznacza to: te ustawienia są użytecznym utwardzaniem, ale nie granicą bezpieczeństwa, a `unserialize()` nie ma nic wspólnego z obcymi danymi.

Drugi punkt dotyczy PHP2Shell. CVE-2026-109618 i CVE-2026-109619 umożliwiają według php.net wykonanie kodu, zanim lub gdy działa Państwa aplikacja; w przypadku mod_php pokazano exploit, zanim w ogóle zostanie wykonany kod aplikacji. Żadna funkcja w Państwa kodzie nie może tego przechwycić. Bezpieczne programowanie i aktualna wersja PHP to dwa osobne obowiązki, a oba muszą być spełnione.

## Jak konkretnie pomaga PHP SOS?

W [audycie bezpieczeństwa aplikacji PHP](https://phpsos.de/pl/leistungen/sicherheitsaudit-penetrationstest/) sprawdzamy celowo:

- **Obsługa haseł i tokenów:** Czy używane są `password_hash()` i `random_bytes()`, czy są rozwiązania własne?
- **Wyjście i zapytania:** Gdzie dane wejściowe trafiają bez filtrowania do HTML, SQL lub poleceń powłoki?
- **Konfiguracja sesji:** Czy Strict Mode, HttpOnly, SameSite i Secure są ustawione i nie da się ich nadpisać?
- **Środowisko uruchomieniowe:** Czy działa wspierana wersja PHP z poprawkami z 21.10.2026?


## Częste pytania

**Jak prawidłowo przechowywać hasła w PHP?**  
Za pomocą password_hash() i PASSWORD_DEFAULT, a sprawdza się je przez password_verify(). Kolumna w bazie danych powinna według podręcznika mieścić do 255 znaków, ponieważ domyślny algorytm może się w przyszłości zmienić.

**Czy rand() nadaje się do tokenów?**  
Nie. Do tokenów, kluczy i linków do resetu hasła należy używać random_bytes() lub random_int(). Według podręcznika dostarczają one kryptograficznie bezpiecznych wartości losowych.

**Od kiedy Sodium jest częścią PHP?**  
Rozszerzenie Sodium do nowoczesnej kryptografii jest częścią PHP od wersji 7.2.0. Starsze wersje mogły je doinstalować tylko przez PECL.

**Czy te funkcje chronią przed PHP2Shell?**  
Nie. Chronią przed błędami w Państwa aplikacji. PHP2Shell tkwi w samym interpreterze i jest zamykane wyłącznie aktualizacją PHP, po której następuje restart wszystkich procesów PHP.

**Czy standardy sesji zmienią się w PHP 8.6?**  
Tak, według przyjętego RFC session.use_strict_mode i session.cookie_httponly zostaną domyślnie włączone, a session.cookie_samesite ustawione na Lax. Istniejące konfiguracje powinni Państwo mimo to ustawić sami, wprost.

## Źródła

- [Podręcznik PHP: password_hash()](https://www.php.net/manual/en/function.password-hash.php)
- [Podręcznik PHP: random_bytes()](https://www.php.net/manual/en/function.random-bytes.php)
- [Podręcznik 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/)
