Cómo agregar firmas de seguridad PDF en Python
Aspose.PDF FOSS para Python incluye un detector de compromiso de firmas que inspecciona un PDF ya firmado en busca de un patrón de manipulación específico: bytes significativos añadidos después del rango de bytes firmado de una firma, un riesgo único de los archivos PDF actualizados incrementalmente. Esta guía añade esa comprobación a un flujo de trabajo Python utilizando las clases SignaturesCompromiseDetector y CompromiseCheckResult. Crear o aplicar nuevas firmas digitales es una parte separada de la biblioteca y no se cubre aquí. La biblioteca se instala con el siguiente comando.
Guía paso a paso
Paso 1: Instalar el paquete
Instalar el paquete FOSS Aspose.PDF:
git clone https://github.com/aspose-pdf-foss/Aspose-PDF-FOSS-for-Python.git
cd Aspose-PDF-FOSS-for-Python
pip install -e .Verifique la instalación importando SignaturesCompromiseDetector y mostrando un mensaje de confirmación:
from aspose_pdf import SignaturesCompromiseDetector
print("aspose-pdf-foss-for-python is ready.")Paso 2: Importar clases requeridas
from aspose_pdf import CompromiseCheckResult, SignaturesCompromiseDetectorPaso 3: Preparar un objeto que exponga una lista de firmas
SignaturesCompromiseDetector no analiza un PDF por sí mismo — su constructor acepta cualquier objeto que exponga un atributo signatures: una lista de entradas de firma, cada una con valid, byte_range y reference_data. PdfSignature — una clase simple, directamente instanciable — coincide con esa forma, por lo que es útil para ver cómo se comporta la comprobación antes de conectarla a su propio objeto de documento:
from types import SimpleNamespace
from aspose_pdf import PdfSignature
with open("signed.pdf", "rb") as handle:
pdf_bytes = handle.read()
signature = PdfSignature(
name="Signature1",
contents=b"...", # PKCS#7 signed-data blob from the signature dictionary
byte_range=[0, 1024, 1040, len(pdf_bytes) - 1040],
reference_data=pdf_bytes,
)
signed_document = SimpleNamespace(signatures=[signature])Reemplace signed_document por su propio objeto de documento una vez que exponga una lista signatures con la misma forma — cualquier objeto con ese atributo funciona.
Paso 4: Ejecutar la Compromise Check
from aspose_pdf import SignaturesCompromiseDetector
detector = SignaturesCompromiseDetector(signed_document)
result = detector.check()
print(result.compromised) # bool
print(result.has_compromised_signatures) # bool -- same value as compromised
print(result.signatures_coverage) # int -- number of signatures inspected
print(result.reasons) # list[str] -- human-readable findingscheck() recorre cada firma en signed_document.signatures, buscando contenido no firmado añadido después del rango de bytes firmado de cada firma. Un CompromiseCheckResult resume el resultado: compromised y has_compromised_signatures informan el mismo booleano bajo dos nombres, signatures_coverage indica cuántas firmas fueron examinadas, y reasons enumera una explicación legible para cada problema encontrado.
Paso 5: Manejar un documento sin firmas
Una lista signatures vacía o ausente no es una condición de error — se informa de la misma manera que un documento sin nada que comprobar:
from types import SimpleNamespace
from aspose_pdf import SignaturesCompromiseDetector
unsigned_document = SimpleNamespace(signatures=[])
detector = SignaturesCompromiseDetector(unsigned_document)
result = detector.check()
print(result.compromised) # False
print(result.reasons) # ["unsigned document"]Pasar SignaturesCompromiseDetector(None) — el valor predeterminado del constructor — se comporta de la misma manera.
Problemas comunes y soluciones
compromised is False para un PDF que sabes que fue editado después de la firma
SignaturesCompromiseDetector busca específicamente bytes sin firmar añadidos después del rango de bytes firmado de una firma — un patrón típico de manipulación ingenua de actualización incremental. No realiza una verificación completa de la firma criptográfica. Para eso, llama a validate() sobre el objeto PdfSignature individual.
compromised and has_compromised_signatures parecen redundantes
Tienen el mismo valor: compromised es una propiedad calculada que devuelve has_compromised_signatures. Usa el nombre que se lea mejor en tu código.
No se lanza ninguna excepción cuando el documento no tiene signatures atributo alguno
SignaturesCompromiseDetector trata un documento sin atributo signatures, o document=None, de la misma manera que un documento no firmado — check() devuelve un resultado con has_compromised_signatures=False y reasons=["unsigned document"] en lugar de generar una excepción.
Un malformado PdfSignature no se marca
check() omite cualquier firma cuyo byte_range no sea una lista de 4 elementos, o cuyo reference_data no sea bytes/bytearray, en lugar de generar una excepción o reportarla como comprometida. Una firma construida con la forma incorrecta se excluye silenciosamente de la verificación, no se marca.
Confundir este detector con la creación de firmas
SignaturesCompromiseDetector y CompromiseCheckResult solo inspeccionan firmas que ya existen en un documento — no tienen método para crear, aplicar o incrustar una nueva firma.
Preguntas frecuentes
¿Qué se considera exactamente “comprometido” aquí?
Bytes significativos, que no son espacios en blanco, añadidos al PDF después del rango de bytes firmado de una firma — con dos excepciones que el detector ya tiene en cuenta: una firma o sello de tiempo posterior que cubre esos bytes, y una actualización incremental que solo agrega material de validación (como un /DSS) sin superponer contenido nuevo como anotaciones.
¿Verifica esto la validez criptográfica de la firma en sí?
No. SignaturesCompromiseDetector verifica los patrones de manipulación alrededor del rango de bytes firmado. La validez criptográfica es una comprobación separada, disponible a través de PdfSignature.validate().
¿Qué me dice signatures_coverage?
El número de firmas que la comprobación examinó realmente en el documento proporcionado — útil para confirmar que el detector vio las firmas que esperabas antes de confiar en un resultado limpio.
¿Puedo comprobar un documento con múltiples firmas a la vez?
Sí. check() recorre cada entrada en signed_document.signatures y devuelve un CompromiseCheckResult agregado que cubre todas ellas.
¿Necesito crear objetos PdfSignature yo mismo en el uso normal?
No — La construcción del PdfSignature del Paso 3 es para explorar el comportamiento del detector directamente. En un flujo de trabajo real, pasa cualquier objeto que tu código de carga de documentos ya produzca, siempre que exponga una lista signatures de entradas con forma PdfSignature.