💡 Tam çalışan örnek GitHub’da mevcuttur:
load-untrusted-documents-safely-python
Eski Yöntem Acı Veriyordu
Yüklenen bir belgenin küçük resmini oluşturmak için üç satır yazdınız. Şöyle görünüyordu ve gayet iyiydi:
with signature.Signature(upload_path) as sign:
save_page_preview(sign, thumbnail_path)
Bu satırların, GroupDocs.Signature 26.9’dan önce yaptığı şey, belgenin işaret ettiği her adresi almaktı. Bir Word dosyası içinde bulunmayan bir resim tutabilir – dosya bir URL saklar ve onu açan her şey bu URL’yi indirir. Masaüstünde bu bir özelliktir. Yüklemeleri kabul eden bir sunucuda ise, dosyayı gönderen kişinin, altyapınızın hangi adreslere istek yapacağını belirlediği anlamına gelir.
Saldırının adı sunucu tarafı istek sahteciliği (SSRF) ve üç şekli adlandırmaya değerdir. İnternetten erişilemeyen bir iç adres, sunucunuzdan erişilebilir olduğundan, hazırlanmış bir belge hizmetinizin http://169.254.169.254/ ya da localhost üzerindeki bir yönetici uç noktasını almasını sağlayabilir. Bir UNC yolu, bir Windows hostunun dışa doğru kimlik doğrulaması yapmasını tetikleyebilir ve kimlik bilgilerini saldırganın kontrolündeki bir sunucuya teslim edebilir. Ve yanıt vermeyen bir hosta bağlantı, zaman aşımına uğrayana kadar yükleme iş parçacığını tutar; bu, zararsız görünen belgelerle çalışan havuzunu tüketmenin ucuz bir yoludur.
Burada belge kütüphanesinde bir hata yoktur. Bir bağlantıyı takip etmek formatın istediği şeydir. Rahatsız edici olan, bu davranışın varsayılan olmasıydı; kodda kimse incelemede bunu işaret etmezdi.
Daha İyi Bir Yol Var
Güvenli belge yükleme, Python için GroupDocs.Signature davranışıdır ve bu istekleri reddeder. 26.9 sürümünden itibaren LoadOptions.skip_external_resources varsayılan olarak True olur, böylece aynı üç satır artık hiçbir şey almaz ve bağlantılı resmin bulunacağı yerde bir yer tutucu oluşturur.
Değişiklik yeni bir özellikten ziyade bir varsayılandır – özellik zaten mevcuttu. 26.9’un değiştirdiği şey, kodunuz hiçbir şey belirtmediğinde hangi yöne işaret ettiğidir; bu, çoğu hizmetin tek kullandığı ayardır.
Yeni Yöntem: Üç Yükleme Modu
Adım 1 - Güvenilmeyen her şey için varsayılanı tutun
Hiç LoadOptions yok:
with signature.Signature(source_path) as sign:
return save_page_preview(sign, preview_path)
Hiçbir istek yapılmaz. Önizleme, aksi takdirde olacağından daha küçüktür ve bu boyut farkı, makineden hiçbir isteğin çıkmadığını gösteren en kullanışlı kanıttır.
Adım 2 - Gerçekten sahip olduğunuz bir hostu beyaz listeye ekleyin
Birçok belge, meşru bir yere bağlanır: bir şirket CDN’i, dahili bir resim sunucusu, bir şablon deposu. Sadece bunu ve başka hiçbir şeyi izin verin:
load_options = LoadOptions()
load_options.whitelisted_resources = [trusted_address]
with signature.Signature(source_path, load_options) as sign:
return save_page_preview(sign, preview_path)
Eşleşme kuralı dikkat çekmelidir. Kaynak adresine karşı büyük/küçük harfe duyarsız bir alt dize testidir; bu da kısa bir parçayı tehlikeli kılar: github, github.attacker.example/payload.png adresini, istediğiniz host kadar eşleştirir. Bir şema, bir host ve bir yol kullanın – bu örnek raw.githubusercontent.com/groupdocs-signature/ adresini beyaz listeye ekler.
Adım 3 - Her şeyi kasıtlı olarak izin verin
26.9 öncesi davranış, hâlâ kullanılabilir:
load_options = LoadOptions()
load_options.skip_external_resources = False
Kendi uygulamanızın ürettiği belgeler için makul bir yaklaşımdır. Bir tuzak: eski load_external_resources özelliği ters kutuplu olduğundan, skip_external_resources = False ifadesi load_external_resources = True yerine geçer. Eski özelliğin değerini kopyalarsanız, güvenlik duruşunuzu hatasız bir şekilde tersine çevirirsiniz.
Yan Yana: Önce vs. Sonra
Aynı belge, aynı kod yolu, üç yükleme politikası. Bunlar, örnek Result/ klasöründeki dosyaların boyutlarıdır; böylece güvenmek yerine kontrol edilebilir:
| Yükleme modu | Önizleme boyutu | Giden istekler |
|---|---|---|
| varsayılan (26.9 ve sonrası) | 16,435 bytes | none |
| beyaz listedeki host | 51,738 bytes | one, to the allowed address |
| tüm kaynaklar (26.9 öncesi varsayılan) | 51,738 bytes | one per linked resource |
Bağlantılı resim, bu farkın 35,303 baytını oluşturur. Ayarı o iki sayı yan yana gelene kadar güvenmedim ve aynı şeyi öneririm: özelliği geri okuduğunuzda, neyi yapılandırdığınızı, sürecin ne yaptığını değil, gösterir.
Dış Kaynak Olarak Ne Sayılır?
İnsanların beklediğinden daha dar bir kapsamı vardır, bu yüzden yükseltme genellikle sorunsuz geçer. Gömülü olmayan, bağlantılı resimler, INCLUDEPICTURE alanları, sunum ve elektronik tablolardaki bağlantılı resimler ve bir SVG’nin referans verdiği görüntüler ve stil sayfaları. Gömülü içerik dokunulmaz, çünkü zaten dosyanın içinde bulunur ve render için istek gerekmez.
Bu ayrım, tüm güvenlik sınırını oluşturur. Bir belge, baytlar yerine bir adres sakladığında sunucunuzun dışa çıkmasını sağlar; bu yüzden herhangi bir koleksiyon için soru, dosyalarının kaç tanesinin gömülü yerine bağlantı içerdiğidir. Hiçbiri bağlantı içermiyorsa, yeni varsayılan size hiçbir şey maliyet çıkarmaz ve daha fazla okumadan yükseltebilirsiniz.
Gerçek Dünya Örneği: İmzalanan Bir Yükleme
Varsayılan değişikliğin var olduğu durum. Dışarıdan bir belge gelir ve üzerine bir imza eklemeniz gerekir:
with signature.Signature(source_path) as sign:
options = QrCodeSignOptions("Approved by GroupDocs.Signature")
options.encode_type = QrCodeTypes.QR
options.left = 400
options.top = 50
options.width = 120
options.height = 120
result = sign.sign(output_path, options)
Belge yüklenirken, imzalanırken veya kaydedilirken hiçbir dış kaynak istenmez. İmzalı çıktı bağlantısını korur, böylece daha sonra Word’de açan bir kullanıcı resmi kendi makinesinde çözülmüş olarak görür. Atlamak, belgeye bir düzenleme değil, sunucu tarafı bir politikadır – bu da başkasının adına işlediğiniz dosyalara güvenle uygulanmasını sağlar.
Yükselttiğinizde Başka Ne Değişir?
Çoğu hizmet için görünür bir şey yoktur; bu, davranışı her yerde değiştiren bir güvenlik varsayılanının yükseltme incelemesinden geçmeyeceği için açıkça belirtilmeye değerdir. İmzalama, doğrulama ve arama etkilenmez. Tek istisna, bir zamanlar bağlantılı resmi gösteren ve şimdi bir yer tutucu gösteren önizlemedir – değişiklik görevini yapıyor. Host sizinse beyaz listeye ekleyin, değilse kabul edin.
Özel olarak belirtmeye değer: SVG. Bir SVG, URL ile görüntü ve stil sayfalarına referans verebilir; bu referanslar aynı kural altında dış kaynaklardır ve SVG hem yaygın bir yükleme formatı hem de yaygın bir SSRF vektörüdür. SVG avatarları kabul edip sunucu tarafında render eden bir hizmet, tam olarak bu değişikliğin koruduğu sistem tipidir.
Bir Python Detayı: Önizleme Nasıl Yazılır
PreviewOptions, bir yol yerine iki akış fabrikası alır ve sadece saf Python çağrılabilir nesneler yeterlidir:
def create_page_stream(page_data):
return open(preview_path, "wb")
def release_page_stream(page_data, page_stream):
page_stream.close()
preview_options = PreviewOptions(create_page_stream, release_page_stream)
preview_options.preview_format = PreviewOptions.PreviewFormats.PNG
sign.generate_preview(preview_options)
Biri sayfa başına bir akış oluşturur, diğeri ise serbest bırakır. Örnek belge tek sayfalıdır, bu yüzden bir dosya yazılır; çok sayfalı giriş için, ad içinde sayfa numarasını ekleyin ya da her sayfa sonrakini üzerine yazar.
Sonuç
Varsayılan tersine çevrildi; riskli davranış açık bir karar gerektirirken, güvenli davranış hiçbir şey gerektirmez. Güvenilmeyen giriş için varsayılanı koruyun, kendi hostlarınızın dahil olduğu durumlarda dar bir beyaz liste uygulayın ve imzalamanın hiç ağ gerektirmediğini unutmayın.
Dosya boyutundan daha güçlü bir kontrol istiyorsanız, bir test belgesini kontrol ettiğiniz bir hosta yönlendirin ve önizleme çalışırken erişim günlüğünü izleyin. Boyut, baytların gelip gelmediğini söyler; erişim günlüğü ise bir isteğin yapılıp yapılmadığını gösterir ve bu, önemli olan durumda tam olarak farklıdır – erişilemeyen bir beyaz listedeki host, çıktıda tek başına engellenen bir hostla aynı görünür.
Örneği kendi belgelerinizden biriyle çalıştırmak bir dakika sürer ve üç dosya boyutunda, hizmetinizin dosyayı gönderen kişi adına tam olarak neyi getirdiğini gösterir.