💡 Plně funkční příklad je k dispozici na GitHubu:
pdf-signing-certificate-checks-python

Úvod

Služba každou noc podepisuje nahrané PDF soubory. Jednoho rána certifikát, který používá, překročil datum platnosti, a nic se nezdálo změnit: úloha běží, soubory jsou zapisovány, log vypadá normálně. O několik týdnů později někdo otevře jeden z těch dokumentů v Acrobat a uvidí varovný banner, protože podpis vytvořený s prošlým certifikátem není slabší podpis – je to podpis, který validátory označují za neplatný. Dokumenty, které vypadají schválené, mají menší hodnotu než nepodepsané, protože lidé jim věřili.

Toto odmítnutí má název. Kontrola platnosti certifikátu je chování GroupDocs.Signature pro Python, které odmítá podepisovat, jakmile uplyne platnost certifikátu, nebo dříve, než začne. Objevilo se ve verzi 26.9 spolu se dvěma změnami stejného tvaru: SHA‑256 se stal výchozím otiskem pro PDF podpisy a SignatureSettings.log_level začal filtrovat místo toho, aby byl tiše ignorován. Každá z nich vezme výsledek, který dříve proběhl tiše, a přenese jej před vás.

Tento článek porovnává tato tři ovládání tak, jak se chovají z Pythonu přes .NET – co každé mění ve výstupu, kdy jej použít a které dva detaily vazby lidem stojí odpoledne. Každý citovaný výsledek pochází ze spuštění ukázky na jednostránkovém PDF.

Proč je to důležitější než poznámka k verzi

Tři změny mají společnou vlastnost, kterou stojí pojmenovat: všechny převádějí selhání, které byste objevili později, na selhání, které objevíte nyní.

  • Prošlé certifikáty: volání podpisu selže, kde může někdo certifikát obnovit, místo aby vytvářelo dokumenty, které po distribuci selžou při validaci
  • Výchozí otisky: nové podpisy používají SHA‑256, aniž by si někdo musel pamatovat, že má požádat, takže slabá volba vyžaduje rozhodnutí místo nepozornosti
  • Úrovně logování: služba, která konfiguruje pouze varování, nyní dostává jen varování, což činí varování čitelnými, což znamená, že jsou skutečně přečtena

Poslední bod je méně kosmetický, než zní. Celá hodnota varování o prošlém certifikátu spočívá v tom, že ho někdo uvidí, a varování ukryté mezi deseti trace zprávami na každé podepisovací operaci je varování, které nikdo nevidí.

Požadavky

Před zahájením se ujistěte, že máte:

  • Python 3.9 nebo novější na 64‑bitovém interpreteru – balíček obsahuje zabalený .NET runtime a nemá 32‑bitové kolo
  • GroupDocs.Signature pro Python přes .NET 26.10.0, s bezplatnou dočasnou licencí, pokud chcete odstranit omezení hodnocení
  • PDF soubor k podepsání a balíček cryptography, pokud chcete vytvářet jednorázové testovací certifikáty, jak ukázka dělá

Instalace

pip install groupdocs-signature-net cryptography

Ovládání 1 – Digest zapisovaný do podpisu

hash_algorithm na DigitalSignOptions vybírá otisk. Výchozí od verze 26.9 je SHA‑256, ve formátu adbe.pkcs7.detached, který současní validátoři očekávají; předtím byly nové podpisy SHA‑1.

with signature.Signature(source_path) as sign:
    options = DigitalSignOptions()
    options.certificate_stream = io.BytesIO(pfx)
    options.password = PASSWORD
    options.hash_algorithm = HashAlgorithm.SHA512
    options.reason = "Approved"

    result = sign.sign(output_path, options)
    return len(result.succeeded)

Dva detaily stojí za vyzdvihnutí. Certifikát přichází přes certificate_stream jako io.BytesIO místo cesty k souboru, což je způsob, jakým PKCS#12 vytvořený v paměti dosáhne knihovny, aniž by byl kdykoli zapsán na disk – ukázka na to spoléhá, aby vůbec nezasílala soukromý klíč. A HashAlgorithm nabízí AUTO, SHA1, SHA256, SHA384 a SHA512, kde časové razítko, pokud jej přidáte, použije otisk, který byl použit v podpisu.

V praxi je to ovládání, které používáte nejméně. Výchozí hodnota je již správná, SHA384 a SHA512 existují pro případy, kdy je to vyžaduje politika podpisu, a SHA1 je nastavení kompatibility pro validátory, které nemůžete změnit.

Ovládání 2 – Zastaví vás neplatný certifikát

Bez jakýchkoli přepsání způsobí podepisování certifikátem, jehož platnost skončila – nebo ještě nezačala – vyhození GroupDocsSignatureException a nic se nezapíše.

try:
    sign.sign(output_path, options)
    return True
except signature.GroupDocsSignatureException as error:
    print(f"Rejected: {str(error).splitlines()[0]}")
    return False

Zpráva uvádí název certifikátu, datum jeho expirace, otisk a vlastnost, která by mu umožnila pokračovat, což stačí aplikaci k tomu, aby operátorovi řekla, co má obnovit. V Pythonu je důležité vzít jen první řádek: text výjimky pokračuje .NET stack trace z vazby a to není něco, co byste chtěli ukazovat uživateli.

Když skutečně potřebujete podepsat i tak – test proti archivovanému certifikátu nebo dávku, která musí běžet dnes večer, zatímco se obnovuje – přepínač se nastavuje na úrovni volání:

settings = signature.SignatureSettings(ConsoleLogger())
settings.log_level = LogLevel.WARNING | LogLevel.ERROR

with signature.Signature(source_path, settings=settings) as sign:
    options.allow_expired = True
    result = sign.sign(output_path, options)

allow_not_yet_valid má stejný tvar pro certifikát vydaný na pozdější datum a oba příznaky jsou nezávislé: povolení prošlého certifikátu neumožňuje povolit předčasný. Předčasný certifikát obvykle znamená, že je špatně nastavený čas stroje, spíše než že je certifikát neobvyklý, a špatný čas způsobí, že každý podpis, který stroj vytvoří, je pochybný, takže to zkontrolujte před tím, než něco přepíšete.

Oba přepínače emitují varování místo tichého průchodu, což je část, která spojuje s třetím ovládáním.

Ovládání 3 – Zjistí to někdo

SignatureSettings.log_level je hodnota příznaků. Ukázka podepisuje stejný dokument třikrát, pod LogLevel.NONE, LogLevel.WARNING | LogLevel.ERROR a LogLevel.ALL, a počítá, co přijde:

logger = CollectingLogger()
settings = signature.SignatureSettings(logger)
settings.log_level = level

with signature.Signature(source_path, settings=settings) as sign:
    options.allow_expired = True
    sign.sign(output_path, options)

Počty vyjdou jako nic, pak jedno varování, pak to varování plus deset trace zpráv. Před verzí 26.9 by všechny tři řádky byly identické, protože úroveň byla přijata a ignorována – což je užitečná informace, pokud jste někdy nastavili úroveň, neviděli žádnou změnu a usoudili, že jste špatně přečetli vlastní kód.

Dva detaily vazby mě stály odpoledne, takže je stojí uvést přímo. SignatureSettings.logger je jen pro čtení, takže logger je argument konstruktoru a přiřazení k němu vyvolá AttributeError; log_level se nastavuje normálně poté. A vlastní logger nesmí dědit z groupdocs.signature.logging.ILogger – tato základní třída obaluje nativní objekt, jehož konstruktor potřebuje handle, který knihovna vlastní, takže dědičnost vyvolá TypeError. Vazba přenáší libovolný obyčejný objekt, který poskytuje tři metody:

class StdlibLogger:
    def error(self, message, exception=None):
        logging.getLogger("groupdocs").error(message, exc_info=exception)

    def warning(self, message, exception=None):
        logging.getLogger("groupdocs").warning(message)

    def trace(self, message):
        logging.getLogger("groupdocs").debug(message)

Dejte metodám error a warning volitelný parametr exception. Knihovna ne vždy předá výjimku a logger, který ji vyžaduje, selže u zpráv, kde není.

Porovnání tří: Kdy použít který

Ovládání Nejvhodnější pro Klíčové výhody Omezení
hash_algorithm splnění politiky, která určuje otisk jednorázové nastavení; stejná velikost výstupu zbytečné, pokud je samotný certifikát nedůvěryhodný
kontrola platnosti a přepsání vše, co se podepisuje pro jiné osoby selhání dopadne tam, kde jej lze opravit přepsání vytvoří soubor, ale ne důvěryhodný
log_level služby, jejichž logy jsou již vytížené jedenáct zpráv se zredukuje na jednu filtruje jen logování, nikdy ne výjimky

Nejsou to alternativy – jedno podepisovací volání používá všechna tři. Pořadí, ve kterém o nich přemýšlet, je pořadí důsledků: kontrola platnosti rozhoduje, zda soubor existuje, otisk rozhoduje, co je uvnitř, a úroveň logu rozhoduje, kdo to ví.

Mění úroveň protokolu, které výjimky dostanu?

Ne. Rozhoduje, které zprávy dorazí do vašeho loggeru a nic víc. Prošlý certifikát stále vyvolá GroupDocsSignatureException při LogLevel.NONE a allow_expired stále podepisuje při LogLevel.ALL; návratové hodnoty a výjimky jsou napříč všemi úrovněmi identické. To, co se mění, je to, zda varování, které vysvětluje pochybný podpis, někdo vůbec přečte.

Ověřování posunuto stejným směrem

Stojí za zmínku, protože je to druhá polovina stejného vydání. verify s prázdným DigitalVerifyOptions nyní kryptograficky kontroluje každý digitální podpis v PDF, takže dokument upravený po podpisu se vrátí jako neplatný místo pouhého neobjasněného stavu:

with signature.Signature(signed_path) as sign:
    result = sign.verify(DigitalVerifyOptions())
    return result.is_valid

Pouze dva řádky a stojí za přidání do jakéhokoli pipeline, která podepisuje a pak ukládá. Všimněte si, co True neslibuje: říká, že podpis odpovídá dokumentu, ne že vydavatel je důvěryhodný. Ukázkové samopodepsané certifikáty zde projdou ověřením, ale PDF čtečkou jsou stále odmítnuty, což samostatně odpovídá otázce důvěry.

Nejlepší postupy a tipy

  • Nechte odmítnutí jako výchozí ve všem, co podepisuje jménem uživatelů, a přepisujte jen na úrovni volání, ne globálně. Výjimka je levná; dávka neplatných podpisů není.
  • Logujte text varování, ne jen čítač. Uvádí název certifikátu a datum, což je jediná část, na kterou může operátor reagovat.
  • Zkontrolujte čas před povolením certifikátu, který ještě nezačal platit. Certifikát je obvykle správný a stroj je často špatně nastavený, a to ovlivňuje více než jedno podepisovací volání.
  • Nechte trace zprávy mimo produkci. Přibližně deset na každé podepisování se rychle nasčítá; zapněte je při diagnostice a vypněte po ní.
  • Ověřujte po podpisu v jakémkoli pipeline, nyní když je kontrola kryptografická, takže poškozený výstup je zachycen dříve, než jej příjemce najde.

Závěr

Tři ovládání, jedno podepisovací volání a stejný návrhový koncept za všemi: riskantní výsledek nyní vyžaduje rozhodnutí, bezpečný nevyžaduje nic. Zachovejte kontrolu platnosti, považujte allow_expired za výjimku na úrovni volání, kterou logujete, nechte otisk být, pokud politika neřekne jinak, a nastavte úroveň logu tak, aby varování byla čitelná.

Spuštění ukázky na jednom z vašich vlastních PDF zabere minutu a vytiskne přesně to, co každé ovládání změnilo – šest podepsaných souborů, jedno úmyslné odmítnutí a tři řádky počtů zpráv, které už nejsou stejné.

Další zdroje