# Funções de segurança integradas do PHP

> Funções de segurança do PHP: palavras-passe, aleatoriedade, escape, criptografia e sessões, e onde estão os limites perante vulnerabilidades como o PHP2Shell.

Fonte: https://phpsos.de/pt/php/eingebaute-sicherheitsfunktionen/  
Atualizado em: 25/10/2026  
Prestador: PHP SOS, Assistência de emergência PHP e segurança de servidores. Ajuda imediata por WhatsApp: https://wa.me/491736494914?text=Ol%C3%A1%2C%20PHP%20SOS%2C%20precisamos%20de%20ajuda%20com%20o%20nosso%20servidor%20PHP.%20Empresa%3A%20%E2%80%A6%20Site%3A%20%E2%80%A6

**Em resumo:** O PHP traz funções prontas e testadas para as tarefas de segurança mais comuns: `password_hash()` para palavras-passe, `random_bytes()` e `random_int()` para tokens, `htmlspecialchars()` contra o cross-site scripting, consultas preparadas com PDO contra a SQL injection, `hash_equals()` para comparações seguras e a extensão Sodium para criptografia. Quem usa estes blocos de forma consistente evita a maior parte das vulnerabilidades de aplicação. Contra erros no próprio interpretador PHP, como no PHP2Shell, não ajudam; aí só ajuda a atualização.

## Porquê funções de segurança integradas no PHP?

Escrever código de segurança por conta própria é propenso a erros. Um hash de palavras-passe feito à medida, um gerador de tokens caseiro ou um filtro improvisado para saídas HTML parecem muitas vezes corretos e não o são. As funções integradas estão documentadas, testadas e são mantidas com as atualizações do PHP.

Para quem decide, isto significa: não pergunte à sua agência ou equipa de desenvolvimento se as funções de segurança foram construídas à medida, mas se são usadas as funções padrão da linguagem. A tabela dá uma visão geral.

| Tarefa | Função | Disponível desde | Nota importante |
|---|---|---|---|
| Guardar palavras-passe | `password_hash()`, `password_verify()` | PHP 5.5 | coluna até 255 caracteres; o bcrypt trunca aos 72 bytes |
| Tokens aleatórios | `random_bytes()`, `random_int()` | PHP 7.0 | nunca `rand()` nem `mt_rand()` para segredos |
| Aleatoriedade orientada a objetos | `Random\Randomizer` | PHP 8.2 | mesma segurança, interface mais flexível |
| Escapar a saída HTML | `htmlspecialchars()` | desde sempre | as flags predefinidas desde o 8.1 escapam também as aspas simples |
| Comparação em tempo constante | `hash_equals()` | PHP 5.6 | entrada do utilizador como segundo argumento |
| Criptografia moderna | Sodium (`sodium_*`) | PHP 7.2 | em vez de cifragem própria |
| Segredos em stack traces | `#[\SensitiveParameter]` | PHP 8.2 | o valor não aparece no trace |
| Verificar entradas | `filter_var()` | PHP 5.2 | verifica o formato, não substitui o escape |

## Palavras-passe e tokens

O `password_hash()` gera um hash com salt, o `password_verify()` verifica-o. Com `PASSWORD_DEFAULT`, o PHP usa atualmente o bcrypt; desde o PHP 8.4, o fator de custo predefinido é, segundo o manual, 12 em vez de 10. Como o algoritmo predefinido pode mudar, o manual recomenda uma coluna de base de dados com 255 caracteres. No bcrypt, as palavras-passe são truncadas aos 72 bytes, o que há que ter em conta em frases-passe muito longas.

```php
<?php
// Registo
$hash = password_hash($passwort, PASSWORD_DEFAULT);

// Início de sessão, incluindo a melhoria automática de hashes antigos
if (password_verify($eingabe, $hash)) {
    if (password_needs_rehash($hash, PASSWORD_DEFAULT)) {
        $hash = password_hash($eingabe, PASSWORD_DEFAULT); // guardar de novo
    }
}

// Token para uma ligação de reposição de palavra-passe
$token = bin2hex(random_bytes(32));
```

Para comparações de segredos, por exemplo de uma assinatura, deve usar-se o `hash_equals()`. Uma comparação normal com `===` pode, segundo o manual, revelar pelo tempo de execução a partir de que posição dois valores diferem. Com mais detalhe: [Guardar palavras-passe em PHP em segurança](https://phpsos.de/pt/blog/passwoerter-in-php-speichern/) e [números aleatórios e tokens seguros](https://phpsos.de/pt/blog/sichere-tokens-php/).

## Escapar saídas e consultar a base de dados em segurança

O cross-site scripting surge quando entradas do utilizador chegam sem filtragem ao HTML. O `htmlspecialchars()` converte caracteres especiais em entidades HTML. Desde o PHP 8.1, as flags predefinidas são `ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401`; antes, as aspas simples não eram convertidas. Quem tem de suportar versões mais antigas indica as flags expressamente.

A SQL injection é impedida por consultas preparadas. Os valores são transmitidos separadamente do texto SQL e não podem alterar a consulta:

```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');
```

Os detalhes estão em [Evitar o cross-site scripting em PHP](https://phpsos.de/pt/ratgeber/xss-php/) e na página sobre SQL injection.

Verificar entradas é um segundo passo, separado. O `filter_var()` determina se um valor tem um formato válido, por exemplo um endereço de correio eletrónico ou um número inteiro num intervalo permitido. Isso não substitui, porém, o escape na saída nem uma consulta preparada, porque também valores formalmente válidos podem conter caracteres especiais.

## Manter segredos fora das mensagens de erro

Uma fuga de dados subestimada são os stack traces. Quando ocorre um erro numa função, o PHP regista a cadeia de chamadas com os argumentos. Se nela constar uma palavra-passe ou uma chave de API, vai parar ao registo. Desde o PHP 8.2, o atributo `#[\SensitiveParameter]` marca esses parâmetros; o seu valor aparece então no trace apenas como objeto `SensitiveParameterValue`.

```php
<?php
function anmelden(string $benutzer, #[\SensitiveParameter] string $passwort): bool
{
    // ... verificação ...
    throw new RuntimeException('Datenbank nicht erreichbar');
}
```

Segundo uma nota do manual, o atributo só atua na implementação concreta, não no método de uma interface. Defina-o por isso onde o código realmente corre.

## Sessões: definições seguras e novas predefinições

As sessões são um alvo frequente de ataques. Três definições são centrais: `session.use_strict_mode=1` rejeita IDs de sessão que o servidor não gerou ele próprio; `session.cookie_httponly=1` impede o acesso por JavaScript ao cookie de sessão; `session.cookie_samesite=Lax` dificulta o envio em conjunto em sites alheios. Segundo um RFC aprovado, são precisamente estes três valores que passam a predefinição com o PHP 8.6. Defina-os por si até lá, e também depois, de forma expressa, para que a configuração não dependa da predefinição.

```ini
session.use_strict_mode = 1
session.cookie_httponly = 1
session.cookie_samesite = Lax
session.cookie_secure = 1
```

Mais sobre isto em [Proteger sessões em PHP](https://phpsos.de/pt/ratgeber/session-sicherheit-php/).

## O que as funções integradas não fazem

O projeto PHP é claro na sua política de segurança: o PHP não é uma sandbox. Contornamentos do `open_basedir` ou do `disable_functions`, entradas maliciosas passadas ao `unserialize()` e argumentos não verificados passados a funções como `mysqli_query()` não são consideradas vulnerabilidades do PHP. Para os operadores, isto significa: estas definições são um hardening útil, mas não uma fronteira de segurança, e o `unserialize()` não tem nada a ver com dados alheios.

O segundo ponto diz respeito ao PHP2Shell. A CVE-2026-109618 e a CVE-2026-109619 permitem, segundo o php.net, a execução de código antes ou durante a execução da sua aplicação; no mod_php foi demonstrado um exploit antes de sequer ser executado código da aplicação. Nenhuma função no seu código consegue apanhar isso. A programação segura e a versão atual do PHP são duas obrigações distintas, e ambas têm de ser cumpridas.

## Como ajuda concretamente a PHP SOS?

Na [auditoria de segurança para aplicações PHP](https://phpsos.de/pt/leistungen/sicherheitsaudit-penetrationstest/), verificamos de forma dirigida:

- **Tratamento de palavras-passe e tokens:** são usados `password_hash()` e `random_bytes()`, ou há soluções caseiras?
- **Saídas e consultas:** onde chegam entradas sem filtragem ao HTML, ao SQL ou a comandos de shell?
- **Configuração de sessões:** estão definidos strict mode, HttpOnly, SameSite e Secure, e não podem ser sobrepostos?
- **Tempo de execução:** corre uma versão suportada do PHP com as correções de 21/10/2026?


## Perguntas frequentes

**Como se guardam corretamente palavras-passe em PHP?**  
Com password_hash() e PASSWORD_DEFAULT; a verificação faz-se com password_verify(). Segundo o manual, a coluna da base de dados deve comportar até 255 caracteres, porque o algoritmo predefinido pode mudar no futuro.

**O rand() é adequado para tokens?**  
Não. Para tokens, chaves e ligações de palavras-passe devem usar-se random_bytes() ou random_int(). Segundo o manual, devolvem valores aleatórios criptograficamente seguros.

**Desde quando o Sodium está incluído no PHP?**  
A extensão Sodium, para criptografia moderna, faz parte do PHP desde o PHP 7.2.0. Nas versões mais antigas só podia ser instalada posteriormente através do PECL.

**Estas funções protegem do PHP2Shell?**  
Não. Protegem de erros na sua aplicação. O PHP2Shell está no próprio interpretador e só se fecha com uma atualização do PHP, seguida do reinício de todos os processos PHP.

**As predefinições de sessão mudam no PHP 8.6?**  
Sim. Segundo um RFC aprovado, o session.use_strict_mode e o session.cookie_httponly passam a estar ativados por predefinição e o session.cookie_samesite passa a Lax. Deve, ainda assim, definir expressamente as configurações existentes.

## Fontes

- [Manual do PHP: password_hash()](https://www.php.net/manual/en/function.password-hash.php)
- [Manual do PHP: random_bytes()](https://www.php.net/manual/en/function.random-bytes.php)
- [Manual do 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/)
