Yapay zekâ botunu üretim veritabanına bağlamak: üç katmanlı salt-okunurluk
Bir destek botunun canlı MySQL'e bakması gerekiyordu ama tek bir satır bile yazmaması gerekiyordu. Tek bir önleme güvenmek yerine neden üç katman kurduğumu ve hassas veriyi loglara hiç düşürmeden nasıl maskelediğimi anlatıyorum.
Sorun
Destek ekibine gelen soruların çoğu birbirine benziyor: fatura durumu, hat bilgisi, arıza kaydı. Bu soruları cevaplamak için botun canlı veritabanına bakması gerekiyor; aksi hâlde verdiği cevap ya eski ya da uydurma olur.
Ama canlı veritabanına bağlanan bir bot, yanlış giden bir şeyin doğrudan müşteri verisine dokunması demek. Benim için iki şart vardı:
- Bot hiçbir koşulda veritabanına yazamamalı.
- Müşterinin hassas verisi hiçbir noktada ham hâlde loglara ya da veritabanına düşmemeli.
Neden tek önlem yetmez
İlk akla gelen çözüm genelde tek bir kontroldür: "Sorguda UPDATE ya da DELETE geçiyorsa reddet." Bu tek başına kırılgan. Sorgular büyük/küçük harf, yorum satırı veya iç içe ifadelerle şekil değiştirebilir; uygulama kodunda yapılacak küçük bir değişiklik kontrolü sessizce devre dışı bırakabilir.
Bu yüzden güvenliği tek bir katmanın doğru çalışmasına bırakmadım. Her katman, bir öncekinin atlanabileceğini varsayıyor.
Üç katman
- Tablo whitelist'i. Bot yalnızca açıkça izin verilen tabloları görebiliyor. Listede olmayan bir tabloya yönelen sorgu daha çalıştırılmadan reddediliyor. Böylece en kötü senaryoda bile erişilebilecek veri sınırlı kalıyor.
- SQL Guard. Çalıştırılacak her sorgu önce yazma ifadelerine karşı denetleniyor. Bu katman yanlış giden şeyi erken ve anlaşılır bir hatayla durduruyor.
READ ONLYtransaction. Sorgu, veritabanı seviyesinde yazmaya kapalı bir işlem içinde çalışıyor. İlk iki katman bir şekilde atlansa bile yazma girişimini veritabanı motorunun kendisi reddediyor.
Son katman en önemlisi: güvenliği uygulama kodunun iyi niyetine değil, veritabanının kendi kuralına bağlıyor. İlk iki katman ise sorunları üçüncüye kalmadan, daha anlaşılır bir yerde yakalıyor.
Hassas veriyi maskelemek
Salt-okunurluk veritabanını koruyor ama konuşmanın kendisi de hassas veri taşıyor. Müşteri sohbet sırasında TC kimlik numarasını, telefonunu, e-postasını ya da kart numarasını yazabiliyor.
Bu alanları düzenli ifadelerle yakalayıp maskeledim. Kart numaraları için ayrıca Luhn doğrulaması kullandım: rastgele 16 haneli her sayıyı kart numarası sanıp maskelemek yerine, gerçekten geçerli bir kart numarası olup olmadığına bakıyor. Bu, hem gereksiz maskelemeyi hem de gözden kaçan kart numaralarını azaltıyor.
Asıl önemli karar maskelemenin nerede yapıldığı: log ya da veritabanı yazımından önce. Hassas veri hiçbir noktada ham hâlde diske düşmüyor; sonradan temizlemeye çalışılacak bir şey kalmıyor.
Kural motoru ve testler
Botu serbest metin üreten bir model yerine YAML ile tanımlanmış bir state machine üzerine kurdum: 16 akış, her birinin kendi adımları, doğrulamaları ve çıkışları var. Bu da güvenliğin bir parçası: bot ne yapacağını önceden tanımlanmış akışlardan biliyor, beklenmedik bir şey üretmiyor.
Akışlar YAML'da durduğu için bir akışı değiştirmek başka bir akışı sessizce bozabiliyor. Bunu yakalamak için 107 test yazdım. Testler olmadan sistemi güvenle güncellemek mümkün değildi.
Bot çözemediği durumda konuşmayı bırakmıyor: Zammad/Zendesk üzerinde ticket açıp konuşma geçmişiyle birlikte canlı operatöre devrediyor.
Öğrendiklerim
- Güvenliği katmanlara böl ve her katmanın atlanabileceğini varsay. En sağlam katmanı uygulamanın değil altyapının kendisine (burada veritabanı motoruna) koy.
- Hassas veriyi kaynağında maskele. Sonradan loglardan temizlemek hem zor hem de güvenilmez.
- Kural tabanlı akış + test, kurumsal destekte serbest üretimden daha güvenli. Kontrol edilebilirlik, "daha akıllı" görünen cevaptan daha değerli.
Botun canlı hâlini deneyebilirsin: TaksimChatFun Canlı Destek.