Skip to content

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.

php
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: e data: dos atributos href e src.
  • Limite propriedades CSS permitidas àquelas necessárias para layout (sem position: fixed, sem url() 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étodoNível de SegurançaCaso de Uso
Hardware Security Module (HSM)Mais altoAmbientes de produção, indústrias reguladas
Cloud KMS (AWS KMS, Azure Key Vault, GCP KMS)AltoImplantações cloud-native
Arquivo PKCS#12 com passphrase forteMédioImplantações pequenas
Arquivo PEM (criptografado)Médio-BaixoDesenvolvimento, testes
Arquivo PEM (não criptografado)Mais baixoNunca 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.
php
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:

php
// 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:

php
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):

php
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

dockerfile
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

bash
# 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:

php
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:

php
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:

php
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 used

Diretrizes de permissão:

  • Nunca conceda MODIFY_CONTENTS a menos que o destinatário precise editar o documento.
  • Sempre conceda ACCESSIBILITY para compatibilidade com leitores de tela (requisito legal em muitas jurisdições).
  • Use PRINT_HIGH_QUALITY em vez de PRINT_LOW_QUALITY a menos que tenha um motivo específico.
  • Documente a justificativa para cada permissão concedida em seu código.

Leitura Adicional

Distribuído sob a licença LGPL-3.0-or-later.