Ir al contenido

Seguridad y operaciones de compat-legacy

El adaptador hereda el modelo de seguridad del motor NextPDF y añade un conjunto reducido de refuerzos deliberados sobre TCPDF heredado 6.2.13. Esta página describe con precisión qué está disponible y qué no, sin exagerarlo. Conviene leer la sección de firmas con atención: su alcance está delimitado deliberadamente.

Tres comportamientos históricos de TCPDF 6.2.13 se modifican por seguridad y no se pueden volver a configurar a la forma insegura:

AspectoTCPDF heredado 6.2.13Adaptador
Manejo de erroresError() invoca die() y termina el procesoError() lanza RuntimeException. Es observable y capturable, sin terminación silenciosa del proceso.
Ejecución de HTMLUna vía de escape permitía ejecutar PHP desde el marcadoLa constante K_TCPDF_CALLS_IN_HTML está fijada en false; el marcado no puede desencadenar la ejecución de PHP.
Salida directaOutput() escribe en el búfer de salida activoLa salida se enruta a través de un puente de destino seguro. No contamina ningún búfer de salida controlado por el llamador.

El cambio en el manejo de errores sigue el principio de que el código llamador debe poder observar un fallo, en vez de que el proceso desaparezca. OWASP ASVS 5.0 §16.5.3 indica que una aplicación debe fallar de forma controlada y segura, y evitar condiciones de fail-open. Lanzar una excepción en lugar de finalizar el proceso aplica ese principio. El refuerzo de HTML elimina un punto de ejecución de código. Cualquier código heredado que dependiera del comportamiento anterior debe tratarse como un defecto que corregir durante /integrations/tcpdf-compat/migration/. El resumen de cláusulas fijado está en el front-matter de la página, en citations.

El adaptador expone el método SetProtection() de TCPDF. Delega en el controlador de seguridad estándar del motor NextPDF.

  • El controlador estándar usa AES-256. El parámetro heredado $mode se acepta por compatibilidad con la firma del método y se ignora: no hay forma de seleccionar un cifrado más débil mediante este método. Con el modo estricto activado, un $mode distinto del predeterminado lanza una excepción, de modo que la migración queda obligada a reconocerlo (comprobado en tests/Unit/Compat/Tcpdf/TcpdfStrictModeTest.php).
  • Si no se proporciona una contraseña de propietario, el adaptador genera una contraseña de propietario aleatoria y criptográficamente fuerte, en lugar de reutilizar la contraseña de usuario. Esto impide que quienes tienen acceso de nivel de usuario obtengan control de nivel de propietario sobre el documento.
  • El cifrado basado en certificados (clave pública) no se realiza a través de SetProtection(); su parámetro $pubkeys se ignora. Se debe usar el punto de entrada moderno de cifrado de clave pública expuesto por el adaptador (setPublicKeyEncryption()), que delega en el motor.

El comportamiento de cifrado refleja el controlador de seguridad estándar descrito en ISO 32000-2 §7. Esa cláusula define las entradas del diccionario de cifrado y el controlador estándar AES-256 que usa el motor. Esta documentación no afirma que la salida sea «segura por defecto» ni «a prueba de manipulaciones». Solo indica el cifrado utilizado y el comportamiento de la contraseña de propietario, que es lo que implementa el código. El resumen de cláusulas fijado está en el front-matter de la página, en citations.

examples/security-encryption.php
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\TCPDF;
$pdf = new TCPDF();
$pdf->AddPage();
$pdf->SetFont('helvetica', '', 12);
$pdf->Cell(0, 10, 'Encrypted document');
// User password set; owner password auto-generated (strong, random).
$pdf->SetProtection([], 'user-secret');
$pdf->Output(__DIR__ . '/encrypted.pdf', 'F');

Leer esta sección al pie de la letra: es deliberadamente conservadora.

  • Los métodos heredados de TCPDF setSignature() y addEmptySignatureAppearance() están sin implementar en el adaptador basado en el motor central. No hacen nada en el modo predeterminado y lanzan TcpdfNotImplementedException en el modo estricto.
  • La firma digital no es una capacidad de la distribución central a través de este adaptador. El soporte de firma de referencia está restringido a una edición comercial de NextPDF.
  • Cuando hay una edición comercial presente, el adaptador expone un punto de entrada de firma moderno (setSignatureV2()) que delega en el motor. Su perfil predeterminado es el perfil de referencia (B-B).
  • Esta documentación no afirma que ninguna edición produzca perfiles de firma con marca de tiempo, de validación a largo plazo o de archivo a través de este adaptador. En concreto, no afirma el comportamiento B-T, B-LT ni B-LTA. La especificación de referencia PAdES §6.1 define cuatro niveles de referencia distintos —B-B, B-T, B-LT y B-LTA—, cada uno con sus propios requisitos. B-B es el nivel de referencia y los niveles superiores (marca de tiempo, largo plazo, archivo) son perfiles independientes y más exigentes. Solo el nivel de referencia B-B entra en el alcance de la documentación de esta capa de compatibilidad. Los niveles superiores quedan explícitamente fuera del alcance y no se declaran para ninguna edición aquí. El resumen de cláusulas fijado está en el front-matter de la página, en citations.
  • En ningún punto se afirma que una firma sea «certificada», «garantizada», «legalmente válida» ni «cualificada según eIDAS». La corrección de la firma, la política de anclas de confianza y la validez legal son responsabilidad de la edición de firma y de la PKI del llamador, no de esta capa de compatibilidad.

Si la migración requiere firma, tratarla como un flujo de trabajo independiente: adoptar la API de firma moderna en una edición comercial y validar la firma producida con un verificador independiente. No depender de la llamada setSignature() de TCPDF: aquí no hace nada.

El método heredado setTimeStamp() se acepta por compatibilidad con la firma del método y emite un aviso; no produce una firma con marca de tiempo a través de este adaptador.

El indicador pdfa del constructor se acepta por compatibilidad con la firma del constructor. La conformidad de archivo PDF/A requiere una edición comercial de NextPDF. El adaptador expone enablePdfA(), que delega en el motor, y el motor devuelve un error de configuración accionable cuando falta la edición requerida. El adaptador no produce en silencio un archivo no conforme mientras declara PDF/A.

La salida siempre es PDF 2.0 (ISO 32000-2). ISO 32000-2 §7.5.2 especifica que un escritor conforme identifica la versión del documento como 2.0 y no la rebaja a una versión anterior al guardar. Por tanto, setPDFVersion() no puede apuntar a una versión anterior (véase /integrations/tcpdf-compat/method-coverage/ §4). El resumen de cláusulas fijado está en el front-matter de la página, en citations.

  • Sin terminación del proceso. Dado que Error() lanza una excepción en lugar de die(), envolver los puntos de entrada de renderizado en try/catch y asignar los fallos al contrato de errores de la aplicación. No asumir que un renderizado fallido finaliza la solicitud.
  • Seguridad del búfer de salida. Output() con S devuelve bytes; con F escribe un archivo; con E devuelve un cuerpo MIME en base64; con I/D se enruta por la ruta de salida del motor. Preferir S o F en los workers y los gestores HTTP para controlar directamente la respuesta; véase /integrations/tcpdf-compat/production-usage/.
  • El modo estricto no es una configuración de producción. Reservarlo para un trabajo de CI/auditoría. Una excepción en una ruta de renderizado de producción es peor que un parámetro degradado silenciosamente.
  • Higiene de constantes. Definir las constantes PDF_* / K_* antes de la primera construcción del adaptador. Los dos indicadores reforzados (K_TCPDF_CALLS_IN_HTML, K_TCPDF_THROW_EXCEPTION_ERROR) no se pueden relajar; no intentar relajarlos.
  • Contraseñas de propietario aleatorias. Si se depende de una contraseña de propietario determinista, establecerla de forma explícita. De lo contrario, se genera una aleatoria fuerte por documento y no es recuperable.
  • Para los métodos de imagen, una ruta de envoltorio de flujo se rechaza antes de cualquier lectura del sistema de archivos. La detección del tipo de imagen (TcpdfImages::getImageFileType) trata cualquier ruta scheme://phar://, php:// y otros envoltorios de flujo de PHP— como un envoltorio y omite la sonda file_get_contents / getimagesize, recurriendo a la inferencia basada solo en la extensión. Esto cierra un vector de deserialización de metadatos de phar en el objetivo de retroportabilidad de PHP 7.4; la propia incrustación de la ruta del envoltorio es rechazada por el motor.
  • Por lo demás, el adaptador no valida ni sanea las rutas de archivo pasadas a los métodos de imagen o de salida más allá de lo que hace el motor. Tratar las rutas y las URL proporcionadas por el llamador como no confiables en el límite de la aplicación.
  • El HTML pasado a los métodos de HTML lo renderiza el motor, no un analizador de HTML de TCPDF. El punto heredado de ejecución de PHP está cerrado, pero el HTML proporcionado por el llamador debe seguir tratándose como entrada no confiable.
  • El cifrado protege la confidencialidad del documento en reposo según el controlador estándar. No sustituye a la seguridad del transporte ni al control de acceso en su aplicación.
  • /integrations/tcpdf-compat/method-coverage/ — comportamiento exacto de SetProtection(), setSignature()
  • /integrations/tcpdf-compat/configuration/ — los dos indicadores reforzados y no configurables
  • /integrations/tcpdf-compat/production-usage/ — workers, búferes, manejo de fallos
  • docs/TCPDF_COVERAGE.md — matriz de cobertura autorizada
  • NOTICE del paquete — declaración de implementación independiente