Boas Práticas de Segurança
Este guia fornece recomendações de segurança acionáveis para implantar o TCPDF-Next em ambientes de produção. Seguir estas práticas garante que seu pipeline de geração de PDF atenda aos padrões de segurança enterprise.
Validação de Entrada (Sanitização HTML Antes de writeHtml)
Ao gerar PDFs a partir de HTML fornecido pelo usuário, sempre sanitize a entrada antes de passá-la para o renderizador HTML. O HtmlRenderer do TCPDF-Next faz parse e renderiza HTML fielmente, o que significa que markup malicioso pode ser explorado se não sanitizado.
use YeeeFang\TcpdfNext\Html\HtmlRenderer;
// DANGEROUS: Never pass raw user input directly
// $renderer->writeHtml($userInput);
// SAFE: Sanitize first with a dedicated library
$clean = \HTMLPurifier::getInstance()->purify($userInput);
$renderer->writeHtml($clean);Regras-chave:
- Remova tags
<script>,<iframe>,<object>,<embed>e<link>antes da renderização. - Remova esquemas de URI
javascript:edata:dos atributoshrefesrc. - Limite propriedades CSS permitidas àquelas necessárias para layout (sem
position: fixed, semurl()em valores CSS). - Valide a codificação de caracteres -- garanta que a entrada é UTF-8 válido antes de passar para o renderizador.
Gerenciamento de Certificados (Armazenamento Seguro e Rotação)
Hierarquia de Armazenamento
| Método | Nível de Segurança | Caso de Uso |
|---|---|---|
| Hardware Security Module (HSM) | Mais alto | Ambientes de produção, indústrias reguladas |
| Cloud KMS (AWS KMS, Azure Key Vault, GCP KMS) | Alto | Implantações cloud-native |
| Arquivo PKCS#12 com passphrase forte | Médio | Implantações pequenas |
| Arquivo PEM (criptografado) | Médio-Baixo | Desenvolvimento, testes |
| Arquivo PEM (não criptografado) | Mais baixo | Nunca em produção |
Política de Rotação
- Renove certificados pelo menos 30 dias antes do vencimento.
- Monitore vencimento com alertas automatizados nos limiares de 30, 14, 7 e 1 dia.
- Revogue certificados comprometidos imediatamente via a CA emissora.
- Mantenha um log de auditoria assinado de todas as operações de ciclo de vida do certificado.
use YeeeFang\TcpdfNext\Certificate\CertificateStore;
$store = new CertificateStore();
$store->loadFromDirectory('/etc/tcpdf-next/certs/', '*.pem');
$activeCert = $store->getActiveCertificate('document-signing');
if ($activeCert->getExpirationDate() < new \DateTimeImmutable('+30 days')) {
$logger->warning('Signing certificate expires soon', [
'subject' => $activeCert->getSubject(),
'expires' => $activeCert->getExpirationDate()->format('Y-m-d'),
]);
}DANGER
Nunca armazene chaves privadas em repositórios de código-fonte, arquivos não criptografados em sistemas de arquivos compartilhados, colunas de banco de dados sem criptografia em repouso ou arquivos de log.
Manipulação de Senhas (SASLprep e Senhas Fortes)
Ao definir senhas de criptografia PDF, aplique normalização Unicode via SASLprep (RFC 4013) para garantir processamento consistente de senhas entre plataformas:
// TCPDF-Next automatically applies SASLprep to passwords
$pdf->setEncryption()
->setAlgorithm(EncryptionAlgorithm::AES256)
->setUserPassword('pässwörd-with-ünïcöde') // SASLprep normalized internally
->setOwnerPassword($strongOwnerPassword)
->apply();Recomendações de política de senha:
- Mínimo de 12 caracteres para senhas de usuário, 20 caracteres para senhas de proprietário.
- Use um gerador aleatório criptograficamente seguro para senhas de proprietário (
random_bytes()). - Nunca codifique senhas hard-coded no código-fonte -- carregue de variáveis de ambiente ou gerenciadores de segredos.
- Limpe senhas da memória após o uso com
sodium_memzero().
Prevenção de SSRF (Validação de URL para Imagens, TSA, OCSP)
O TCPDF-Next bloqueia SSRF por padrão, mas você deve configurar allowlists para recursos externos legítimos:
use YeeeFang\TcpdfNext\Security\NetworkPolicy;
$networkPolicy = NetworkPolicy::create()
->denyPrivateNetworks() // Block 10.x, 172.16.x, 192.168.x
->denyLoopback() // Block 127.0.0.1
->denyLinkLocal() // Block 169.254.x
->allowDomain('cdn.yourcompany.com') // Images
->allowDomain('timestamp.digicert.com') // TSA
->allowDomain('ocsp.digicert.com') // OCSP
->setMaxRedirects(3)
->setRequestTimeout(10);
$pdf = PdfDocument::create()
->setNetworkPolicy($networkPolicy)
->build();Checklist:
- Valide todas as URLs antes de buscar (esquema, host, porta).
- Faça allowlist explícito de domínios de TSA e OCSP responder.
- Bloqueie esquemas
file://,gopher://,ftp://e outros não-HTTP(S). - Registre em log todas as requisições bloqueadas para monitoramento de segurança.
Validação de Caminho de Arquivo (Prevenir Path Traversal)
Ao aceitar caminhos de arquivo fornecidos pelo usuário (ex.: para arquivos de fonte, imagens ou destinos de saída):
use YeeeFang\TcpdfNext\Security\ResourcePolicy;
$resourcePolicy = ResourcePolicy::strict()
->allowLocalDirectory('/app/public/assets/')
->allowLocalDirectory('/app/storage/fonts/')
->denyAllRemote();
$pdf = PdfDocument::create()
->setResourcePolicy($resourcePolicy)
->build();Regras:
- Nunca concatene entrada do usuário diretamente em caminhos de arquivo.
- Resolva caminhos para forma canônica absoluta e valide contra diretórios permitidos.
- Rejeite caminhos contendo
.., null bytes ou caracteres não imprimíveis. - Use
ResourcePolicy::strict()em produção -- nega todo acesso por padrão.
Segurança de Implantação (Docker e Permissões de Arquivo)
Configuração Docker
FROM php:8.5-fpm-alpine
# Run as non-root user
RUN addgroup -S tcpdf && adduser -S tcpdf -G tcpdf
USER tcpdf
# Disable dangerous PHP functions
RUN echo "disable_functions = exec,passthru,shell_exec,system,proc_open,popen" \
>> /usr/local/etc/php/conf.d/security.ini
# Read-only filesystem (mount writable volumes explicitly)
# docker run --read-only --tmpfs /tmp ...Permissões de Arquivo
# Certificate directory: readable only by the web server user
chown -R www-data:www-data /etc/tcpdf-next/certs/
chmod 700 /etc/tcpdf-next/certs/
chmod 600 /etc/tcpdf-next/certs/*.p12
chmod 600 /etc/tcpdf-next/certs/*.pem
# Output directory: writable only by the web server user
chown -R www-data:www-data /var/lib/tcpdf-next/output/
chmod 700 /var/lib/tcpdf-next/output/
# Temporary directory: writable, not world-readable
chown -R www-data:www-data /tmp/tcpdf-next/
chmod 700 /tmp/tcpdf-next/Content Security Policy para PDFs Exibidos no Navegador
Ao servir PDFs inline no navegador, defina cabeçalhos HTTP apropriados para prevenir ataques de embedding:
return response($pdf->toString(), 200, [
'Content-Type' => 'application/pdf',
'Content-Disposition' => 'inline; filename="document.pdf"',
'Content-Security-Policy' => "default-src 'none'; plugin-types application/pdf",
'X-Content-Type-Options' => 'nosniff',
'X-Frame-Options' => 'DENY',
'Cache-Control' => 'no-store, no-cache, must-revalidate',
]);Para PDFs contendo dados sensíveis, prefira Content-Disposition: attachment para forçar download em vez de renderização no navegador.
Recomendações de Audit Logging
Configure logging de auditoria abrangente para todas as operações de PDF sensíveis à segurança:
use YeeeFang\TcpdfNext\Security\AuditLogger;
AuditLogger::configure([
'channel' => 'tcpdf-security',
'log_signing' => true,
'log_encryption' => true,
'log_validation' => true,
'log_key_access' => true,
'log_tsa_requests' => true,
'log_resource_access' => true, // Log image/font loading
'log_blocked_requests' => true, // Log SSRF blocks
'redact_sensitive' => true, // Redact passwords/keys from logs
]);Monitore:
- Tentativas de validação de assinatura falhadas (possível adulteração de documento).
- Avisos de vencimento de certificado.
- Falhas de comunicação com TSA.
- Volume incomum de assinaturas (possível comprometimento de chave).
- Tentativas de SSRF bloqueadas (possível sondagem de ataque).
- Carregamento de recursos de caminhos inesperados.
Princípio de Menor Privilégio para Permissões PDF
Ao definir permissões de documento PDF, conceda apenas o acesso mínimo necessário:
use YeeeFang\TcpdfNext\Encryption\Permissions;
// RESTRICTIVE: Read-only document
$pdf->setEncryption()
->setPermissions(Permissions::ACCESSIBILITY) // Only screen reader access
->setUserPassword('reader')
->setOwnerPassword($strongOwnerPassword)
->apply();
// MODERATE: Printable document
$pdf->setEncryption()
->setPermissions(
Permissions::PRINT_HIGH_QUALITY
| Permissions::ACCESSIBILITY
)
->apply();
// AVOID: Granting all permissions defeats the purpose of encryption
// Permissions::ALL is available but should rarely be usedDiretrizes de permissão:
- Nunca conceda
MODIFY_CONTENTSa menos que o destinatário precise editar o documento. - Sempre conceda
ACCESSIBILITYpara compatibilidade com leitores de tela (requisito legal em muitas jurisdições). - Use
PRINT_HIGH_QUALITYem vez dePRINT_LOW_QUALITYa menos que tenha um motivo específico. - Documente a justificativa para cada permissão concedida em seu código.
Leitura Adicional
- Visão Geral de Segurança -- Arquitetura de segurança e filosofia de design
- PAdES B-LTA -- Níveis de assinatura e implementação
- Criptografia Avançada -- Requisitos de algoritmo