flawopen.com/Desserialização insegura/PHP unserialize()
unserialize() do PHP é seguro para entrada não confiável?
Não passe entrada não confiável a unserialize(), mesmo ao definir allowed_classes. O PHP pode restaurar objetos e chamar __unserialize() ou __wakeup(); um atacante pode explorar classes disponíveis à aplicação ou ao autoloader. Use JSON para dados não confiáveis. Com decodificação associativa, objetos JSON viram arrays e não instanciam classes da aplicação com comportamento de métodos mágicos.
<?php // Cookie content is controlled by the client. $input = $_COOKIE['prefs'] ?? ''; $data = unserialize($input); // Restoring an object may invoke its // __unserialize() or __wakeup() method. // Later object destruction may invoke __destruct(). // The risk depends on available classes, // their serialized state, and reachable behavior.
<?php
$input = $_POST['prefs'] ?? null;
if (!is_string($input)) {
http_response_code(400);
exit;
}
try {
$data = json_decode(
$input,
true,
512,
JSON_THROW_ON_ERROR
);
} catch (JsonException $e) {
http_response_code(400);
exit;
}
if (!is_array($data)) {
http_response_code(400);
exit;
}
// Validate required keys and value types here.
O que uma cadeia de injeção de objetos PHP exige
O risco de injeção de objetos não significa execução automática de código. O valor serializado precisa nomear uma classe que o PHP consiga resolver, permitida pelas opções de desserialização; a restauração ou o uso posterior também deve alcançar um comportamento com impacto de segurança. O PHP pode chamar __unserialize() ou __wakeup() ao restaurar o objeto; __destruct() pode rodar quando ele for destruído, e __toString() apenas quando usado em contexto de string.
Uma cadeia Property-Oriented Programming (POP) liga comportamentos já presentes na aplicação ou nas dependências carregadas. A explorabilidade depende das classes reais, das propriedades serializadas, do caminho de chamadas e das condições de execução. É preciso demonstrar uma cadeia de gadgets para o alvo; a presença de unserialize() por si só não a comprova.
Por que filtrar a string ou usar allowed_classes não é correção completa
Bloquear um marcador como O:, filtrar nomes de classes ou limitar o tamanho da string não valida com segurança a serialização PHP. Mais importante: o PHP alerta explicitamente para não passar entrada não confiável a unserialize(), independentemente de allowed_classes. Se uma classe não for permitida, o PHP cria um objeto __PHP_Incomplete_Class; a estrutura continua sendo analisada. Para dados legados confiáveis, valide a forma resultante e limite a profundidade. Prefira JSON para estado vindo do cliente.
Perguntas frequentes
Não. A opção impede a restauração normal de classes da aplicação; objetos não permitidos viram __PHP_Incomplete_Class. O PHP ainda alerta para não passar dados não confiáveis a unserialize(), mesmo com essa opção. Use-a apenas como defesa em profundidade para dados legados confiáveis, valide o resultado e defina max_depth limitado. O manual do PHP informa que esta opção não afeta enums.
Pode comprovar a integridade de dados gerados pela aplicação se a chave permanecer secreta e hash_equals() validar a assinatura antes da desserialização. Rejeite assinaturas inválidas antes de analisar os dados. HMAC não cifra nem impede repetição; use expiração ou nonce quando for necessário garantir atualidade. Não use assinatura para legitimar dados serializados arbitrários do usuário.
Eles compartilham o risco amplo de restaurar objetos de dados serializados, mas formatos, hooks, regras de resolução de classes e mitigação diferem. Avalie cada runtime e suas classes disponíveis separadamente; não presuma que uma cadeia de gadgets de uma plataforma funcione em outra.
Referências
- Manual do PHP — unserialize()
- Manual do PHP — métodos mágicos
- Manual do PHP — decodificação JSON
- Manual do PHP — __PHP_Incomplete_Class
- OWASP — injeção de objetos PHP
- CWE-502 — desserialização de dados não confiáveis
- Python pickle é seguro para dados não confiáveis?
- Java ObjectInputStream é seguro com dados não confiáveis?