💡 Tam çalışan örnek GitHub’da mevcuttur:
pdf-signing-certificate-checks-python
Giriş
Bir hizmet, yüklenen PDF’leri her gece imzalar. Bir sabah, kullandığı sertifikanın son kullanma tarihi geçmiş olur ve hiçbir şey değişmiş gibi görünmez: iş çalışır, dosyalar yazılır, günlük (log) normal görünür. Haftalar sonra birisi bu belgelerden birini Acrobat’ta açar ve bir uyarı şeridi görür, çünkü süresi dolmuş bir sertifika ile yapılan imza daha zayıf bir imza değildir – doğrulayıcıların geçersiz olarak rapor ettiği bir imzadır. Onaylı görünen belgeler, imzasız olanlardan daha az değer taşır, çünkü insanlar onlara güvenmiştir.
Bu reddetmenin bir adı vardır. Sertifika geçerlilik kontrolü, Python için bir GroupDocs.Signature davranışıdır ve sertifikanın geçerlilik süresi dolduğunda ya da henüz başlamadığında imzalamayı reddeder. Bu özellik, aynı biçimde iki değişiklikle birlikte 26.9 sürümünde gelmiştir: PDF imzaları için varsayılan özet (digest) SHA-256 olmuştur ve SignatureSettings.log_level sessizce yok sayılmak yerine filtreleme yapmaya başlamıştır. Her biri, daha önce sessizce gerçekleşen bir sonucu önünüze getirir.
Bu makale, bu üç kontrolü Python üzerinden .NET ile nasıl davrandığını karşılaştırır – her birinin çıktıyı ne şekilde değiştirdiği, ne zaman kullanılacağı ve bağlayıcı (binding) iki ayrıntısının insanları bir öğleden sonra nasıl zorladığı. Alıntılanan tüm sonuçlar, bir sayfalık PDF üzerinde örnek çalıştırılarak elde edilmiştir.
Neden Bu, Bir Sürüm Notundan Daha Önemli
Üç değişiklik, adlandırmaya değer bir özelliği paylaşır: hepsi, daha sonra keşfedeceğiniz bir hatayı şimdi keşfetmenizi sağlar.
- Süresi dolmuş sertifikalar: imzalama çağrısı, birisi sertifikayı yenileyebileceği bir noktada başarısız olur; dağıtımdan sonra doğrulama hatası veren belgeler üretilmez.
- Özet varsayılanları: yeni imzalar, kimsenin hatırlamasına gerek kalmadan SHA-256 kullanır, böylece zayıf seçenek bir karar gerektirir, dikkatsizlik değil.
- Günlük (log) seviyeleri: yalnızca uyarı veren bir hizmet artık yalnızca uyarıları alır, bu da uyarıların okunabilir olmasını sağlar; bu da bir kişinin uyarıyı görmesi anlamına gelir.
Sonuncusu, kulağa göründüğünden daha az süslüdür. Süresi dolmuş sertifika uyarısının tüm değeri, birinin bunu görmesidir; imzalama çalışması başına on izleme mesajı içinde gömülü bir uyarı ise kimsenin görmediği bir uyarıdır.
Önkoşullar
Başlamadan önce şunların kurulu olduğundan emin olun:
- 64‑bit bir yorumlayıcıda Python 3.9 veya üzeri – paket, bir .NET çalışma zamanı içerir ve 32‑bit tekerlek (wheel) sunmaz.
- GroupDocs.Signature for Python via .NET 26.10.0, değerlendirme sınırlamalarını kaldırmak isterseniz bir ücretsiz geçici lisans alın.
- İmzalanacak bir PDF ve örnek gibi geçici test sertifikaları oluşturmak isterseniz
cryptographypaketi.
Kurulum
pip install groupdocs-signature-net cryptography
Kontrol 1 – İmzaya yazılan özet (digest)
DigitalSignOptions üzerindeki hash_algorithm özeti seçer. 26.9’dan beri varsayılan SHA‑256’dır; geçerli doğrulayıcıların beklediği adbe.pkcs7.detached formatındadır; bundan önce yeni imzalar SHA‑1 kullanıyordu.
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)
İki ayrıntı vurgulanmaya değerdir. Sertifika, bir dosya yolu yerine certificate_stream aracılığıyla io.BytesIO olarak gelir; bu, bellekte oluşturulan bir PKCS#12’nin kütüphaneye hiç diske yazılmadan ulaşmasını sağlar – örnek, özel anahtar içermediği için buna dayanır. HashAlgorithm ise AUTO, SHA1, SHA256, SHA384 ve SHA512 seçeneklerini sunar; bir zaman damgası eklenirse, imzanın kullandığı özet (digest) otomatik olarak kullanılır.
Pratikte bu, en az dokunduğunuz kontroldür. Varsayılan zaten doğru cevaptır, SHA384 ve SHA512 bir imzalama politikası onları gerektirdiğinde mevcuttur ve SHA1 ise değiştirilemeyen doğrulayıcılar için bir uyumluluk ayarıdır.
Kontrol 2 – Süresi dolmuş bir sertifika sizi durdurur mu?
Hiçbir geçersizleştirme (override) olmadan, geçerlilik süresi bitmiş ya da henüz başlamamış bir sertifika ile imzalamaya çalışmak GroupDocsSignatureException fırlatır ve hiçbir şey yazmaz.
try:
sign.sign(output_path, options)
return True
except signature.GroupDocsSignatureException as error:
print(f"Rejected: {str(error).splitlines()[0]}")
return False
Mesaj, sertifikanın adını, süresinin dolduğu tarihi, parmak izini ve onu izin verecek özelliği (property) belirtir; bu, bir uygulamanın operatöre neyi yenilemesi gerektiğini söylemesi için yeterlidir. Python’da sadece ilk satırı almak önemlidir: istisna metni, bağlayıcıdan (binding) gelen .NET yığın izini (stack trace) içerir ve bu kullanıcıya gösterilmemelidir.
Gerçekten yine de imzalamanız gerektiğinde – arşivlenmiş bir sertifika ile test yapmak ya da yenileme sürecindeyken bu gece çalışması gereken bir toplu işlem – geçersizleştirme (override) çağrı bazlıdır:
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 aynı biçimde, daha sonraki bir tarihte geçerli olacak bir sertifika için kullanılır ve iki bayrak bağımsızdır: süresi dolmuş bir sertifikaya izin vermek, erken bir sertifikaya izin vermez. Erken bir sertifika genellikle makinenin saatinin yanlış olduğu anlamına gelir; yanlış saat, o makinenin ürettiği her imzayı şüpheli kılar, bu yüzden herhangi bir geçersizleştirmeden önce saati kontrol edin.
Her iki geçersizleştirme de sessiz geçmek yerine bir uyarı üretir; bu, üçüncü kontrolle bağlantılı kısımdır.
Kontrol 3 – Birisi bunu fark eder mi?
SignatureSettings.log_level bir bayrak (flags) değeridir. Örnek, aynı belgeyi üç kez imzalar: LogLevel.NONE, LogLevel.WARNING | LogLevel.ERROR ve LogLevel.ALL altında, gelen mesajları sayar:
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)
Sayımlar sırasıyla hiç şey, bir uyarı ve o uyarı artı on izleme mesajı olarak çıkar. 26.9’dan önce üç satır da aynı olurdu, çünkü seviye kabul edilir ve yok sayılırdı – bu, bir seviye ayarladığınızda hiçbir değişiklik görmediyseniz ve kendi kodunuzu yanlış okuduğunuzu düşündüyseniz bilmeniz gereken bir durumdur.
Bağlayıcı (binding) iki ayrıntısı bir öğleden sonra zamanımı aldı, bu yüzden açıkça belirtilmelidir. SignatureSettings.logger yalnızca okunabilir; bu yüzden logger bir kurucu (constructor) argümanıdır ve ona atama yapmaya çalışmak AttributeError fırlatır; log_level normal şekilde sonradan ayarlanır. Ayrıca özel bir logger, groupdocs.signature.logging.ILogger sınıfını alt sınıf (subclass) yapmamalıdır – bu temel sınıf, kütüphanenin sahip olduğu bir tutamağı (handle) gerektiren yerel bir nesneyi sarar, bu yüzden alt sınıf oluşturmak TypeError verir. Bağlayıcı, aşağıdaki üç yöntemi sağlayan herhangi bir düz nesneyi kabul eder:
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)
error ve warning metodlarına isteğe bağlı bir exception parametresi verin. Kütüphane her zaman bir istisna göndermez ve bu parametreyi zorunlu kılan bir logger, parametresiz mesajlarda kırılır.
Üç Kontrolün Karşılaştırması: Ne Zaman Hangi Kontrol Kullanılır
| Kontrol | En Uygun Kullanım | Temel Avantajlar | Sınırlamalar |
|---|---|---|---|
hash_algorithm |
bir politikada belirtilen özete uymak | tek atama; aynı çıktı boyutu | sertifika kendisi güvensizse anlamsız |
| geçerlilik kontrolü ve geçersizleştirmeler | başkaları için imza yapan her şey | hata, düzeltilebilecek bir noktada durur | geçersizleştirme bir dosya üretir, ancak güvenilir bir dosya değildir |
log_level |
günlükleri zaten yoğun olan hizmetler | on mesaj bir mesaj olur | yalnızca günlükleri filtreler, istisnaları asla filtrelemez |
Bunlar alternatif değildir – tek bir imzalama çağrısı üç kontrolü de kullanır. Düşünme sırası, sonuç sırasıdır: geçerlilik kontrolü dosyanın var olup olmadığını belirler, özet (digest) içeriğini belirler, günlük seviyesi ise kimin bildiğini belirler.
Günlük seviyesi, aldığım istisnaları değiştirir mi?
Hayır. Hangi mesajların logger’ınıza ulaşacağını belirler, başka bir şey yapmaz. Süresi dolmuş bir sertifika, LogLevel.NONE altında hâlâ GroupDocsSignatureException fırlatır ve allow_expired LogLevel.ALL altında hâlâ imzalar; dönüş değerleri ve istisnalar her seviyede aynıdır. Değişen tek şey, şüpheli bir imzayı açıklayan uyarının bir kişi tarafından okunup okunmadığıdır.
Doğrulama Aynı Yönde İlerledi
Bahsetmeye değer, çünkü aynı sürümün diğer yarısıdır. Boş bir DigitalVerifyOptions ile verify artık her PDF dijital imzasını kriptografik olarak kontrol eder, böylece imzalandıktan sonra değiştirilmiş bir belge geçersiz döner, sadece açıklanmamış olmaz:
with signature.Signature(signed_path) as sign:
result = sign.verify(DigitalVerifyOptions())
return result.is_valid
İki satır ve imzalayıp ardından depolayan her işlem hattına eklenmesi önerilir. True değerinin vaat etmediği şey şudur: imzanın belgeyle eşleştiğini söyler, ancak yayıncının (issuer) güvenilir olduğunu söylemez. Örnekteki kendi kendine imzalanmış sertifikalar burada doğrulanır, ancak bir PDF okuyucu tarafından hâlâ reddedilir; bu, güven sorusunu ayrı olarak yanıtlar.
En İyi Uygulamalar ve İpuçları
- Reddetmeyi varsayılan tutun; kullanıcılar adına imza yapan her şeyde bunu varsayılan yapın ve geçersizleştirmeyi (override) yalnızca çağrı bazında, global olarak değil uygulayın. İstisna ucuzdur; geçersiz imzaların toplu hâli pahalıdır.
- Uyarı metnini sayacın sadece sayısı yerine kaydedin. Sertifika ve tarihi adlandırır; bu, operatörün harekete geçebileceği tek bölümdür.
- Bir sertifikanın henüz geçerli olmadan önce saati kontrol edin. Sertifika genellikle doğrudur, makine yanlıştır ve bu birden fazla imzalama çağrısını etkiler.
- Üretimde izleme (trace) mesajlarını kapalı tutun. İmzalama çalışması başına yaklaşık on izleme mesajı çabuk birikebilir; tanı koyma sırasında açın, sonrasında kapatın.
- İmzalamadan sonra doğrulama yapın; kontrol artık kriptografik, böylece bozuk bir çıktı alıcıya ulaşmadan yakalanır.
Sonuç
Üç kontrol, tek bir imzalama çağrısı ve hepsinin arkasındaki aynı tasarım fikri: riskli sonuç artık bir karar gerektirir, güvenli sonuç ise hiçbir şey gerektirmez. Geçerlilik kontrolünü tutun, allow_expired’ı çağrı bazlı bir istisna olarak loglayın, politika gerektirmedikçe özeti (digest) dokunmayın ve uyarıların okunabilir olmasını sağlayacak bir günlük seviyesi ayarlayın.
Kendi PDF’nizle örneği çalıştırmak bir dakika sürer ve her kontrolün neyi değiştirdiğini tam olarak gösterir – altı imzalı dosya, bir kasıtlı reddetme ve artık aynı olmayan üç mesaj sayısı satırı.