Ödeme sistemleri ve güvenliği [3] — Yazılımlarımızda HSM ‘i kullanma

Ömer SAVAŞ
6 min readApr 8, 2024

--

Önsöz: Bu yazıda genel amaçlı tip hsm ile iletişimde kullandığıimız protokol olan pkcs11 den biraz bahsedip bir kaç dil için HSM nasıl kullanılır; en yüksek verim için nasıl bir yol izlenmelidir? Bunu açıklamaya çalışacağım. Spoiler: Bu -nazaran- daha detay teknik bir yazı olacak. Genel kültür okuyucusu bu yazıda sıkılabilir.

Serinin diğer yazıları:
Ödeme sistemleri ve güvenliği [1] — HSM nedir
Ödeme sistemleri ve güvenliği [2] — Kriptoloji
Ödeme sistemleri ve güvenliği [3] — Yazılımlarımızda HSM ‘i kullanma
Ödeme sistemleri ve güvenliği [4] — Key tipleri ve yapıları

Merhaba değerli okuyucu. İlk konumuz PKCS11. Bu bizim genel amaçlı HSM ler ile iletişime geçerken kullandığımız -genel geçer- protokol. Açılımı: Public Key Cryptography Standard. Sektöre ilk girdiğimde dikkatimi protokol isminin sonundaki 11 çekmişti. Dedim ki neden 11? Bunu 11 de ne durdurdu. (Feyyaz ‘a selam olsun) Sonradan öğrendim ki aslında çok sayıda pkcs standartı var. Açılımından da anlaşılacağı üzere bunlar kriptolojideki standartlar. 11 numaralı standart da donanım tabanlı kriptoloji cihazları (yani HSM) için yazılmış olan bölüm. PKCS7 de sertifikalar için mesela.

Hemen aklıma gelmişden bir dallanam yapıp pkcs11 ‘e geri döneceğim; ödeme sistemleri tipi HSM ‘ler için direkt bir standart yok. 1. yazıda sanırım bir miktar konuşmuştuk; ödeme sistemeri tipi HSM ile direkt TCP iletişim kurabiliyoruz. (Yazar burada “konuşmuştuk” diyerek subliminal bir interaktif ilişki mesajı vermektedir) Bu TCP mesajları çok temel olarak komutları ve parametreleri içeriyor. Başka bir yazıda buna daha detaylı değineceğim.

Herneyse. PKCS11 temel olarak ihtiyacımız olan tüm fonksiyonların hangi parametreler ile çağırılması gerektiğini, dönüş türlerini, hatta sabitleri vs tanımlıyor. Her HSM üreticisi kendi ürünü için bir dll ve so tipinde kütüphane paylaşıyor. Bu kütüphane PKCS11 standartındaki fonksiyonları içeriyor. Mesela bir encrypt işlemi yapmak istiyorsak dll i load ediyoruz ve uygulamamız dll üzerinden ilgili parametreleri göndererek bu işlemi gerçekleştiriyor ve sonucu dll üzerinden alıyor. Bu dll ‘i bir ORM gibi yada soyutlama katmanı olarak düşünebiliriz. Yani teorik olarak bir marka HSM için yazığımız uygulamamızın dll değiştirerek başka marka HSM lerle de çalışmasını bekleriz.

Ama iş pratiğe gelince malesef tam olarak öyle olmuyor.
[Rakip marka HSM ‘e p*slik atma mode ON]
Mesela bazı marka HSM ‘ler var. İsim vermek gibi olsun Safenet ProtectServer Server; dll lerini standarta uygun olmayan şekilde geliştirmişler. Valla billa. Örnek vermek gerekirse standart bariz bir şekilde RSA Private bir key ile şifreleme yapamazsın diyor. Normal şartlarda bir kullanıcı bu tipte bir key ile şifreleme yapmak istese yine standartın uygun gördüğü bir hata kodu dönülüp işlem yapılmamalı. Ama bu cihaz işlemi gerçekleştiriyor. İşin kötü tarafı bazı eski uygulamalar bu davranışa göre geliştirilmiş. Eskiyen HSM ‘i yerli ve milli, gözümüzün nuru, performans makinesi bizim marka HSM ile replace edelim dediğimizde uygulama çalışamıyor. Ne güzel.
- Napcanız olum gavur malı HSM ‘leri bizimkini alın. Hem dışarda içine ne koyuyolar bilemiyoz.
[Rakip marka HSM ‘e p*slik atma mode OFF]

Tamam sakinim evet. Standartımız sadece HSM ile iletişimin nasıl kurulacağını ve birbirimizi anlayabilmemiz için gerekli sabitleri tanımlıyor. İşi nasıl yapacağımıza karışmıyor. İşlemleri tam olarak nasıl yapacağımıza karar veren şeyler -genellikle- PCI, FIPS vs. Allah ömür versin inşallah bunlar hakkında da bir yazı yazacağım. Bunlar çeşitli sektörlerde HSM i kullanabilmek için sağlamanız gerekli standartlar.

Bu konuyu şunun için açtım; bu dll ler HSM ile iletişimde bir köprü olmak ile birlikte güvenlik ve performans konusunda da bazı insiyatifler barındırabiliyorlar. Mesela bir sign işlemi yapacak olalım mekanizma olarak da rsa-pkcs-sha256 seçilmiş olsun. Normal mantıkta tüm datanız HSM ‘in içine kadar gider orada sha256 özeti alınır ve bu özet imza edilir. Datanızın afaki büyük olduğu senaryoları düşünürsek HSM ‘in imza performansı astronomik seviyede düşebilir. Bunun yerine mesela sha256 özetini dll kendisi alsa ve HSM ‘e direk özet datasını rsa-pkcs ile imza ettirse… Hem datamız dll -yani sunucu- dışarısına hiç çıkmamış olur hem network yükünden kurtulmuş oluruz hem de HSM performansı çok daha yüksek olur. Sanırım gereksiz bir detay oldu ama madem o kadar uğraştım yazdım siz de okuyun :p

Son olarak, üreticiden üreticiye değişmek ile birlikte HSM ‘i maksimum performansta kullanabilmek için genel yöntemlerden bahsedip kod kısmına geçeceğim. (Pkcs11 hakkında daha fazla blog okumak isterseniz Ömer YILDIZ bey ‘in bloğunu tavsiye ederim)

İlk kriterimiz multi-threat. HSM ‘ler genellikle donanımsal olarak birden fazla işlem çekirdeğine sahiptirler. Bu sebeple de tek bir process ile HSM ‘i maksimum kapasitede süremeyiz. Datasheet de optimum threat sayısı vardır ama bence daha doğru olan sizin datanıza ve yapacağınız işleme göre farklı threat sayıları ile testler yaparak kendi doğrunuzu bulmak. Bizim marka HSM için 32–64 thereat aralığını denemenizi öneririm.

Gerçek hayatta karşılaştığım en büyük yanlışlardan biri multi-threat olarak geliştirtirilmiş bir uygulamada pkcs11.dll ‘i tek threat ile load edip istekleri tek kanaldan akıtmak. Uygulamanın multithreat olmasının iletişim kanalına bir faydası yok.

  • Alttaki metni daha önce yazmıştım ama Fatih abi laf arasında bunun tam olarak böyle olmadığını söyledi. Detayları soracağım ama benim değidiğim gibi olduğuna dair delillerim var *swh.
    Metin: Tabiri caizse dll de threat sayısı kadar load edilmeli ve bağımsız bağlantılar açılmalı.

Mesela test toolları için log çıktılarına bakarsanız threat sayısı kadar load işlemi yapıldığını görebilirsiniz. Aşağıda p11speed kütüphanesi ile test işlemi gerçekleştirmek için gerekli komutu bırakıyorum.

p11speed --sign --slot 0 9999 --mechanism RSA_PKCS --keysize 2048 --threads 32 --iterations 10000

İkinci konumuz session pooling. Önce session meselesini açmak istiyorum. PKCS11 ‘in session dediği şey temelde TCP seviyesindeki sessionlar gibi şeyler değil. HSM ile bağlantıyı başlattıktan sonra session açma talebi atarsınız ve HSM size adanmış bir ID numarası verir. Yani bunu iki tarafın da bildiği sayısal bir değer olarak düşünebiliriz. Ama tabiki sıfır maliyetli de değil. Bu sebeple doğru yaklaşım başlangıçta bir havuz oluşturup bir miktar sessionu açık olarak havuzda tutmak ve işlem yapacağımız zaman bu sessionlar üzerinden işlemleri göndermek. Runtime da bir session hataya düşerse de hemen onu yenilemek. Bu bizi HSM ‘in maksimum kapasitesini kullanmaya götürecek yöntem.

He bir de üreticilere özel bazı dll ‘ler var. Mesela Safenet üreticisi pkcs11 dışında kendinize özel kriptolojik operasyonlar yaratıp bu buisness ‘ı HSM ‘in içine gömebilmenize izin veren “functionality module” isminde bir yaklaşıma sahip. Ama bizim gibi bir çok firma bu özel buisness ‘ı kendi uygulamanız içinde daha üst katmanlarda çözmenizi ve HSM ‘e sadece PKCS11 methodları ile gelmenizi bekliyor.

Evet uzun bir yazı oldu ama nihayet kodlama kısmına geldik. Bu yazının kapsamındaki tüm kodlara buradaki github reposundan erişebilirsiniz. Ben Ayrıca kodları kendi makinenizde koşturabilmeniz için açık kaynak bir proje olan softhsm2 ‘ yi kullanabilirsiniz. Burada bir kurulum videosu var. “Okuyom ben yea ne videosu” diyosanız burada bir makalesi mevcut.

Kurulum esnasında size verilen slot numarası ve belirlediğiniz pin bilgisini kaydetmeyi unutmayınız.

Aslında farklı kütüphaneleri kullanmak yerine pure olarak dll dosyasındaki methodlarımızı çağırıp HSM ile iletişim kurmak mümkün fakat bunu yapmak için hem dll fonksiyonlarını/imzalarını çok iyi bilmelisiniz ve operasyonları hangi sıra ile ilerleteceğinize hakim olmalısınız. Örneğin bir encrypt işlemi yapmak için;

- Önce C_Initialize ile iletişim başlatılmalı,
- C_Login ilse slota login olunmalı,
- C_OpenSession ile bir session açılmalı,
- C_EncryptInit ve C_Encrypt ard arda çağırılarak encrpyt başlatılmalı,
- Eğer datamız tek isteğe sığmayacak kadar büyük ise C_EncryptUpdate ile datanın geri kalan kısımları gönderilmeli
- Son olarak da C_EncryptFinal ile işlem sonlandırılmalı.

Low level dünyasına hoşgeldiniz. Genellikle bu sebepden dolayı daha hi-level kütüphaneleri kullanarak encrypt fonksiyonunu çağırıp işimizi tek adımda hallediriz.

İlk dilimiz python. PyKCS11 kütüphanesi ile HSM ‘i sürebiliyorsunuz. python-example.py ile önce HSM ‘e bağlantımızı test ediyor. Ardından ihtiyacımız olan AES keyi (aes128 isminde) oluşturuyor ve 1 ‘er adet encrypt/decrypt işlemi atıyor.

İkinci yazılım dilimiz ise Java. Java dili kriptoloji işlemleri için SunPKCS11 isminde dahili bir kütüphane barındırıyor. Bu script içinde yine HSM ‘e bağlanıp aes128 keyi ile bir encrypt/decrypt işlemi yaptırıyor.

[Java hakkında ss buraya gelecek]

Son olarak da C# dili ile örneklendirip bitirmek istiyorum. Pkcs11-Interop isminde up level bir kütüphane var. Açık kaynak haline buradan erişebilirsiniz. Gayet performanslı bir kütüphane ama bazı kriptolojik işlemler için response datanın length değerini ilk istekte alamadığı için aynı isteği mükerrer olarak gönderdiğini gördüm. Bu hatanın çözümünü isteyen özelden yeşillendirsin :) Evet yukarıdaki işlemlerin aynısını yapan ve içerisinde session pooling mekanizmasını barındıran örnek kod aşağıda.

Bir sonraki yazıda görüşmek dileğiyle…

Serinin diğer yazıları:
Ödeme sistemleri ve güvenliği [1] — HSM nedir
Ödeme sistemleri ve güvenliği [2] — Kriptoloji
Ödeme sistemleri ve güvenliği [3] — Yazılımlarımızda HSM ‘i kullanma
Ödeme sistemleri ve güvenliği [4] — Key tipleri ve yapıları

--

--