Siber saldırılar her geçen gün daha sofistike hale gelirken, sistem dosyalarınızda veya kritik verilerinizde meydana gelen yetkisiz değişiklikleri saniyeler içinde tespit etmek hayati önem taşır. Bu makale, Python kullanarak dosya bütünlüğünü gerçek zamanlıya yakın bir hızda nasıl izleyebileceğinizi, güvenlik açıklarını nasıl kapatabileceğinizi ve olası veri ihlallerini nasıl önleyebileceğinizi adım adım açıklayacaktır.
Günümüzün dijital dünyasında siber güvenlik tehditleri sürekli evrim geçirmekte ve bu durum, kurumların savunma stratejilerini gözden geçirmesini zorunlu kılmaktadır. Bir sunucuya sızan kötü amaçlı bir yazılım, kritik sistem dosyalarını değiştirebilir, veri tabanı yapılarını bozabilir veya hassas verilerin bulunduğu dizinlerde yeni dosyalar oluşturabilir. Bu tür yetkisiz değişiklikler, genellikle fark edilmeden uzun süre sistemde kalabilir ve ciddi güvenlik ihlallerine yol açabilir. İşte tam da bu noktada Dosya Bütünlüğü İzleme (File Integrity Monitoring – FIM) devreye girer. FIM, belirli dosyaların veya dizinlerin üzerinde yapılan her türlü değişikliği (oluşturma, silme, değiştirme) tespit eden ve bu değişiklikler hakkında uyarı veren bir güvenlik kontrol mekanizmasıdır. Temel olarak, bir dosyanın veya dizinin “sağlıklı” durumdaki parmak izini (hash değerini) kaydeder ve periyodik olarak veya gerçek zamanlı olarak bu parmak izini kontrol ederek herhangi bir sapmayı bildirir.
Peki, FIM’in bu kadar kritik olmasının nedenleri nelerdir? İlk olarak, güvenlik ihlallerinin erken tespiti için vazgeçilmezdir. Bir saldırgan sisteme sızdığında, izlerini örtmek veya kalıcı erişim sağlamak için genellikle sistem dosyalarını değiştirir veya yeni kötü amaçlı dosyalar yerleştirir. FIM, bu değişiklikleri anında tespit ederek güvenlik ekiplerine potansiyel bir saldırı hakkında erken uyarı sağlar. Bu erken uyarı, saldırının yayılmasını engellemek veya geri dönülemez zararlar vermesini önlemek için kritik öneme sahiptir. İkinci olarak, düzenleyici uyumluluk gereksinimlerini karşılamak için FIM şarttır. Özellikle HIPAA, PCI DSS, GDPR gibi düzenlemeler, hassas verilerin korunması ve sistem bütünlüğünün sürdürülmesi konusunda katı kurallar getirir. FIM çözümleri, bu düzenlemelerin denetim izi (audit trail) ve bütünlük kontrolü gereksinimlerini karşılayarak kuruluşların yasal yükümlülüklerini yerine getirmesine yardımcı olur. Örneğin, PCI DSS, ödeme kartı verileri ortamındaki tüm sistem dosyalarında FIM uygulanmasını açıkça talep eder.
Üçüncü bir neden ise, iç tehditlere karşı korunmadır. Güvenlik ihlalleri her zaman dışarıdan gelmez; bazen kötü niyetli çalışanlar veya yetkisini aşan personel tarafından da tetiklenebilir. FIM, içeriden kaynaklanan yetkisiz değişiklikleri de tespit ederek, bir çalışanın hassas bir yapılandırma dosyasını değiştirmeye çalışması gibi durumlarda uyarı verebilir. Bu, hem veri bütünlüğünü korur hem de operasyonel riskleri azaltır. Son olarak, sistemin orijinal durumuna dönmesini kolaylaştırır. Bir güvenlik ihlali yaşandığında veya bir sistem hatası meydana geldiğinde, FIM tarafından tutulan bütünlük kayıtları, hangi dosyaların değiştiğini ve ne zaman değiştiğini gösterir. Bu bilgiler, sistemin hızlı bir şekilde önceki sağlıklı durumuna geri döndürülmesine yardımcı olur ve felaket kurtarma (disaster recovery) süreçlerini hızlandırır. Özetle, FIM sadece bir güvenlik aracı olmaktan öte, modern IT altyapılarının temel bir bileşenidir ve proaktif bir savunma stratejisi için olmazsa olmazdır. Bu sayede, “2 saniyede dosya değişikliği tespiti” gibi iddialı hedeflere ulaşarak, olası zararları en aza indirebilir ve işletmelerin sürekli operasyonunu güvence altına alabilirsiniz.
Vaka Analizi: Büyük Bir Perakende Zincirinin PCI DSS Uyum Süreci
Büyük bir perakende zinciri, ödeme kartı verilerini işlediği için PCI DSS (Ödeme Kartı Sektörü Veri Güvenliği Standardı) uyumluluğunu sağlamak zorundaydı. Zincir, POS sistemlerinden sunucularına kadar yüzlerce cihazda dosya bütünlüğü izleme çözümü olmadan düzenli denetimlerde sorunlar yaşıyordu. Bir denetimde, bir POS cihazındaki kritik sistem dosyasının yetkisizce değiştirildiği fark edildi. Değişiklik, kötü amaçlı bir yazılımın sızma girişimi sonucuydu, ancak standart loglama mekanizmaları bu kadar hızlı tespit edememişti. Zincir, Python tabanlı bir FIM çözümü entegre ederek bu sorunu çözdü. Yeni sistem, kritik dizinlerdeki her türlü dosya değişikliğini anında tespit ediyor ve merkezi bir SIEM (Security Information and Event Management) sistemine iletiyordu. Bu sayede, potansiyel tehditler saniyeler içinde belirlenip müdahale edilebilir hale geldi. Bu entegrasyon, sadece uyumluluğu sağlamakla kalmadı, aynı zamanda genel güvenlik duruşunu önemli ölçüde güçlendirdi.
Dosya Bütünlüğü İzlemenin Temel Taşları Nelerdir?
Dosya Bütünlüğü İzleme (FIM) sistemi kurarken anlamamız gereken birkaç temel kavram bulunmaktadır. Bu kavramlar, sistemin nasıl çalıştığını, neden etkili olduğunu ve Python ile nasıl uygulanacağını anlamak için kritik öneme sahiptir. İlk ve belki de en önemli kavram, “hash fonksiyonları”dır. Hash fonksiyonları, herhangi bir boyuttaki veriyi (örneğin, bir dosyanın içeriğini) alıp sabit boyutlu, benzersiz bir karakter dizisine dönüştüren matematiksel algoritmalardır. Bu çıktıya “hash değeri” veya “özet” denir. Örneğin, SHA-256 (Secure Hash Algorithm 256-bit) gibi popüler bir hash algoritması, bir dosyanın içeriği ne olursa olsun, 256 bit uzunluğunda tek bir hash değeri üretir. Bu hash değerlerinin en önemli özelliği, girdideki en ufak bir değişikliğin bile (tek bir karakterin değişmesi gibi) tamamen farklı bir hash değeri üretmesidir. Ayrıca, aynı hash değerini veren iki farklı girdi bulmak (çakışma) teorik olarak çok zordur; bu da hash’leri dosya bütünlüğünü kontrol etmek için ideal kılar.
İkinci temel taş “izleme mekanizmaları”dır. FIM sistemleri genellikle iki ana yöntemden birini kullanarak dosya değişikliklerini algılar: “polling” (sorgulama) ve “event-driven” (olay tabanlı). Polling, belirli bir dizindeki dosyaların hash değerlerini periyodik olarak (örneğin, her 5 saniyede bir veya her 1 dakikada bir) yeniden hesaplayıp daha önce kaydedilen hash değerleriyle karşılaştırma yöntemidir. Eğer mevcut hash değeri kayıtlı olandan farklıysa, bu bir değişiklik olduğunu gösterir. Bu yöntem kolay uygulanabilir olsa da, yüksek frekansta polling yapmak sistem kaynaklarını tüketebilirken, düşük frekansta polling yapmak değişikliklerin tespitinde gecikmelere yol açabilir. Hedefimiz olan “2 saniyede dosya değişikliği tespiti” için polling tek başına yeterli olmayabilir veya çok yoğun kaynak gerektirebilir. Diğer yandan, event-driven izleme, işletim sisteminin dosya sistemi olaylarını (dosya oluşturma, silme, değiştirme, izin değişikliği vb.) dinlemesi anlamına gelir. Linux’ta inotify, macOS’ta FSEvents ve Windows’ta ReadDirectoryChangesW gibi sistem API’leri bu tür olayları anında bildirir. Bu yöntem, değişiklikleri gerçek zamanlıya yakın bir hızda tespit etme yeteneği sunar ve sistem kaynaklarını daha verimli kullanır, çünkü yalnızca bir olay meydana geldiğinde tetiklenir.
Üçüncü önemli bileşen “veritabanı veya depolama”dır. FIM sisteminin düzgün çalışabilmesi için, başlangıçtaki “sağlıklı” dosya durumlarının (hash değerleri, boyutu, son değiştirilme tarihi gibi meta veriler) güvenli bir şekilde saklanması gerekir. Bu veriler genellikle bir veritabanında (SQLite, PostgreSQL, MySQL gibi) veya yapılandırılmış dosyalarda (JSON, YAML) depolanır. Depolama alanı, hem ilk taramadan elde edilen referans verileri hem de her kontrol sonrasında tespit edilen değişiklikleri (audit trail) tutar. Bu sayede, hangi dosyanın ne zaman, kim tarafından ve nasıl değiştiğine dair kapsamlı bir kayıt tutulabilir. Son olarak, “uyarı ve raporlama” mekanizmaları FIM sisteminin etkinliğini artırır. Bir değişiklik tespit edildiğinde, sistemin yöneticilere e-posta, SMS, anlık mesajlaşma veya merkezi bir güvenlik olay yönetimi (SIEM) sistemine log gönderme gibi yollarla anında uyarı vermesi gerekir. Bu sayede güvenlik ekipleri duruma hızlıca müdahale edebilir. Tüm bu temel taşlar bir araya geldiğinde, Python ile güçlü ve hızlı bir dosya bütünlüğü izleme sistemi inşa edilebilir. Bu sistem, hem siber güvenlik duruşunuzu güçlendirir hem de düzenleyici gereksinimlere uyum sağlamanıza yardımcı olur.
Python ile Temel Dosya Bütünlüğü Kontrolü Nasıl Yapılır?
Python, dosya işlemleri ve kriptografik hash fonksiyonları için zengin bir standart kütüphane desteği sunar. Bu bölümde, Python kullanarak belirli bir dizindeki dosyaların hash değerlerini nasıl hesaplayacağınızı ve bu değerleri bir veritabanında (örneğin, SQLite) saklayarak periyodik bütünlük kontrolleri yapacağınızı adım adım göstereceğiz. Amacımız, basit ama işlevsel bir FIM çekirdeği oluşturmak.
İlk adım, bir dosyanın hash değerini hesaplamaktır. hashlib modülü, SHA-256 gibi çeşitli hash algoritmalarını destekler. Büyük dosyalarla çalışırken, dosyanın tamamını belleğe yüklemek yerine, parçalar halinde okuyup hash fonksiyonuna beslemek daha verimlidir. Bu yaklaşım, sistem kaynaklarını korurken performansı da optimize eder.
import hashlib
import os
def calculate_file_hash(filepath, hash_algo='sha256', block_size=65536):
"""
Belirtilen dosyanın hash değerini hesaplar.
:param filepath: Hash değeri hesaplanacak dosyanın yolu.
:param hash_algo: Kullanılacak hash algoritması (örn. 'sha256', 'md5').
:param block_size: Dosyanın okunacağı blok boyutu.
:return: Dosyanın hex formatındaki hash değeri.
"""
if not os.path.exists(filepath) or not os.path.isfile(filepath):
return None
hasher = hashlib.new(hash_algo)
with open(filepath, 'rb') as f:
for block in iter(lambda: f.read(block_size), b''):
hasher.update(block)
return hasher.hexdigest()
# Örnek kullanım:
# test_file_path = "test_document.txt"
# with open(test_file_path, "w") as f:
# f.write("Bu bir test dosyasıdır.")
#
# print(f"'{test_file_path}' dosyasının SHA256 hash değeri: {calculate_file_hash(test_file_path)}")
Şimdi, bu hash değerlerini saklayacak bir mekanizmaya ihtiyacımız var. SQLite, Python'un standart kütüphanesinde yer alan hafif, sunucusuz bir veritabanı olduğu için başlangıç için harika bir seçenektir. Her dosya için yolu, adını, hash değerini ve son kontrol tarihini saklayabiliriz. Bu bilgiler, bir sonraki kontrolde değişiklik olup olmadığını anlamamızı sağlayacaktır. Ayrıca, veritabanı yönetimini basitleştiren sqlite3 modülü ile kolayca etkileşime geçebiliriz.
import sqlite3
import time
DATABASE_NAME = "file_integrity.db"
def initialize_database():
"""Veritabanını ve 'files' tablosunu oluşturur."""
conn = sqlite3.connect(DATABASE_NAME)
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS files (
id INTEGER PRIMARY KEY AUTOINCREMENT,
filepath TEXT UNIQUE NOT NULL,
filename TEXT NOT NULL,
initial_hash TEXT NOT NULL,
last_checked TIMESTAMP,
last_modified TIMESTAMP
)
''')
cursor.execute('''
CREATE TABLE IF NOT EXISTS changes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
filepath TEXT NOT NULL,
change_type TEXT NOT NULL, -- 'modified', 'added', 'deleted'
old_hash TEXT,
new_hash TEXT,
change_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
''')
conn.commit()
conn.close()
def record_file_state(filepath, hash_value):
"""Bir dosyanın hash değerini ve meta verilerini veritabanına kaydeder."""
conn = sqlite3.connect(DATABASE_NAME)
cursor = conn.cursor()
filename = os.path.basename(filepath)
last_modified = os.path.getmtime(filepath)
cursor.execute('''
INSERT OR REPLACE INTO files
(filepath, filename, initial_hash, last_checked, last_modified)
VALUES (?, ?, ?, ?, ?)
''', (filepath, filename, hash_value, time.time(), last_modified))
conn.commit()
conn.close()
def get_file_state(filepath):
"""Bir dosyanın kaydedilmiş hash değerini ve diğer meta verilerini getirir."""
conn = sqlite3.connect(DATABASE_NAME)
cursor = conn.cursor()
cursor.execute('SELECT initial_hash, last_modified FROM files WHERE filepath = ?', (filepath,))
result = cursor.fetchone()
conn.close()
return result
def log_change(filepath, change_type, old_hash=None, new_hash=None):
"""Dosya değişikliklerini 'changes' tablosuna kaydeder."""
conn = sqlite3.connect(DATABASE_NAME)
cursor = conn.cursor()
cursor.execute('''
INSERT INTO changes (filepath, change_type, old_hash, new_hash)
VALUES (?, ?, ?, ?)
''', (filepath, change_type, old_hash, new_hash))
conn.commit()
conn.close()
print(f"UYARI: Dosya '{filepath}' {change_type}!")
if old_hash and new_hash:
print(f"Eski Hash: {old_hash[:10]}... Yeni Hash: {new_hash[:10]}...")
# Veritabanını başlat
initialize_database()
Dizinleri Tarama ve Değişiklikleri Algılama
Şimdi, belirli bir dizindeki tüm dosyaları tarayacak ve bunları veritabanımızdaki kayıtlarla karşılaştıracak ana fonksiyonu yazalım. Bu fonksiyon, hem yeni eklenen dosyaları, hem değiştirilen dosyaları hem de silinen dosyaları tespit edecektir. Bu döngü, polling tabanlı FIM sisteminin temelini oluşturur. os.walk fonksiyonu, bir dizindeki tüm alt dizinleri ve dosyaları gezmek için oldukça kullanışlıdır.
def monitor_directory_polling(directory_to_monitor):
"""
Belirtilen dizindeki dosya değişikliklerini (polling yöntemiyle) izler.
:param directory_to_monitor: İzlenecek dizinin yolu.
"""
print(f"Dizin izleniyor: {directory_to_monitor}")
# Mevcut veritabanındaki dosyaları al
conn = sqlite3.connect(DATABASE_NAME)
cursor = conn.cursor()
cursor.execute('SELECT filepath, initial_hash FROM files')
db_files = {row[0]: row[1] for row in cursor.fetchall()}
conn.close()
current_files = {} # Mevcut dosyaların hash'lerini tutacak
# Dizini tara ve mevcut dosyaların hash'lerini hesapla
for root, _, files in os.walk(directory_to_monitor):
for filename in files:
filepath = os.path.join(root, filename)
current_hash = calculate_file_hash(filepath)
if current_hash:
current_files[filepath] = current_hash
# Yeni eklenen veya değiştirilen dosyaları bul
for filepath, current_hash in current_files.items():
if filepath not in db_files:
log_change(filepath, 'added', new_hash=current_hash)
record_file_state(filepath, current_hash) # Yeni dosyayı kaydet
elif db_files[filepath] != current_hash:
log_change(filepath, 'modified', old_hash=db_files[filepath], new_hash=current_hash)
record_file_state(filepath, current_hash) # Değişen dosyanın hash'ini güncelle
# Silinen dosyaları bul
for filepath in db_files:
if filepath not in current_files:
log_change(filepath, 'deleted', old_hash=db_files[filepath])
# Veritabanından silinen dosyayı kaldır
conn = sqlite3.connect(DATABASE_NAME)
cursor = conn.cursor()
cursor.execute('DELETE FROM files WHERE filepath = ?', (filepath,))
conn.commit()
conn.close()
print("Kontrol tamamlandı.")
# Örnek kullanım:
# if __name__ == "__main__":
# # İzlenecek bir dizin oluşturun
# monitoring_dir = "monitor_test_dir"
# os.makedirs(monitoring_dir, exist_ok=True)
#
# # Başlangıç durumu için bir dosya oluşturun
# with open(os.path.join(monitoring_dir, "config.ini"), "w") as f:
# f.write("[Settings]\nparam=value")
#
# # Başlangıçta tüm dosyaları kaydet
# monitor_directory_polling(monitoring_dir)
# print("\nİlk tarama tamamlandı. Şimdi değişiklik yapalım...\n")
#
# # Değişiklikler yapın
# time.sleep(2)
# with open(os.path.join(monitoring_dir, "config.ini"), "a") as f:
# f.write("\nnew_param=new_value")
# with open(os.path.join(monitoring_dir, "new_file.txt"), "w") as f:
# f.write("Bu yeni bir dosya.")
# os.remove(os.path.join(monitoring_dir, "config.ini")) # Dosyayı sil
#
# # Yeniden kontrol et ve değişiklikleri gör
# monitor_directory_polling(monitoring_dir)
#
# # Temizlik (isteğe bağlı)
# # os.remove(os.path.join(monitoring_dir, "new_file.txt"))
# # os.rmdir(monitoring_dir)
# # os.remove(DATABASE_NAME)
Bu temel polling tabanlı sistem, belirli aralıklarla çalıştırıldığında dosya değişikliklerini tespit edebilir. Ancak, "2 saniyede" gibi hızlı tespitler için event-driven (olay tabanlı) izleme yöntemlerine geçmemiz gerekecektir.
Gerçek Zamanlıya Yakın İzleme: Olay Tabanlı Yaklaşımlar (inotify/watchdog)
Polling yöntemi basit olsa da, "2 saniyede dosya değişikliği tespiti" gibi hedefler için yetersiz kalabilir. Daha hızlı ve verimli bir yaklaşım için işletim sistemi düzeyindeki olay tabanlı izleme mekanizmalarını kullanmak şarttır. Linux sistemlerinde inotify API'si, dosya sistemi olaylarını (oluşturma, silme, değiştirme, taşıma vb.) anında bildirerek bu ihtiyacı karşılar. Python için inotify'nin kullanımı biraz karmaşık olabilir, ancak watchdog gibi kütüphaneler bu işlemi büyük ölçüde basitleştirir ve platformlar arası uyumluluk sağlar.
watchdog kütüphanesi, dosya sistemi olaylarını izlemek için mükemmel bir araçtır. Arka planda işletim sisteminin native event API'lerini (Linux'ta inotify, macOS'ta FSEvents, Windows'ta ReadDirectoryChangesW) kullanarak çalışır. Bu sayede, biz polling yapmak zorunda kalmadan, bir dosya veya dizinde bir değişiklik olduğunda anında bildirim alırız.
İlk olarak, watchdog kütüphanesini kurmanız gerekir:
pip install watchdog
Şimdi, watchdog kullanarak dosya değişikliklerini nasıl izleyeceğimize bakalım. Bir FileSystemEventHandler sınıfı oluşturarak, hangi dosya sistemi olaylarına tepki vereceğimizi tanımlarız. Bu olaylar arasında on_created, on_deleted, on_modified ve on_moved gibi metotlar bulunur. Bu metotların içine, değişikliği algıladığımızda yapılması gereken işlemleri (örneğin, hash değerini yeniden hesaplamak, veritabanına kaydetmek, uyarı göndermek) yerleştireceğiz.
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
import time
import os
import hashlib
import sqlite3 # Önceki bölümden import ediyoruz
# Global değişkenler veya konfigürasyonlar
DATABASE_NAME = "file_integrity.db"
MONITORED_DIR = "monitor_realtime_dir" # İzlenecek dizin
def calculate_file_hash(filepath, hash_algo='sha256', block_size=65536):
"""Daha önceki bölümdeki hash hesaplama fonksiyonu."""
if not os.path.exists(filepath) or not os.path.isfile(filepath):
return None
hasher = hashlib.new(hash_algo)
try:
with open(filepath, 'rb') as f:
for block in iter(lambda: f.read(block_size), b''):
hasher.update(block)
except IOError:
return None # Dosya kilitli veya erişilemezse hata vermemesi için
return hasher.hexdigest()
def initialize_database():
"""Veritabanı başlatma fonksiyonu."""
conn = sqlite3.connect(DATABASE_NAME)
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS files (
id INTEGER PRIMARY KEY AUTOINCREMENT,
filepath TEXT UNIQUE NOT NULL,
filename TEXT NOT NULL,
initial_hash TEXT NOT NULL,
last_checked TIMESTAMP,
last_modified TIMESTAMP
)
''')
cursor.execute('''
CREATE TABLE IF NOT EXISTS changes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
filepath TEXT NOT NULL,
change_type TEXT NOT NULL, -- 'modified', 'added', 'deleted'
old_hash TEXT,
new_hash TEXT,
change_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
''')
conn.commit()
conn.close()
def record_file_state(filepath, hash_value):
"""Bir dosyanın hash değerini ve meta verilerini veritabanına kaydeder."""
conn = sqlite3.connect(DATABASE_NAME)
cursor = conn.cursor()
filename = os.path.basename(filepath)
try:
last_modified = os.path.getmtime(filepath)
except FileNotFoundError:
last_modified = time.time() # Dosya silinmişse veya anlık erişilemezse
cursor.execute('''
INSERT OR REPLACE INTO files
(filepath, filename, initial_hash, last_checked, last_modified)
VALUES (?, ?, ?, ?, ?)
''', (filepath, filename, hash_value, time.time(), last_modified))
conn.commit()
conn.close()
def get_file_state(filepath):
"""Bir dosyanın kaydedilmiş hash değerini ve diğer meta verilerini getirir."""
conn = sqlite3.connect(DATABASE_NAME)
cursor = conn.cursor()
cursor.execute('SELECT initial_hash FROM files WHERE filepath = ?', (filepath,))
result = cursor.fetchone()
conn.close()
return result[0] if result else None
def delete_file_state(filepath):
"""Veritabanından dosya durumunu siler."""
conn = sqlite3.connect(DATABASE_NAME)
cursor = conn.cursor()
cursor.execute('DELETE FROM files WHERE filepath = ?', (filepath,))
conn.commit()
conn.close()
def log_change(filepath, change_type, old_hash=None, new_hash=None):
"""Dosya değişikliklerini 'changes' tablosuna kaydeder."""
conn = sqlite3.connect(DATABASE_NAME)
cursor = conn.cursor()
cursor.execute('''
INSERT INTO changes (filepath, change_type, old_hash, new_hash)
VALUES (?, ?, ?, ?)
''', (filepath, change_type, old_hash, new_hash))
conn.commit()
conn.close()
print(f"UYARI: Dosya '{filepath}' {change_type}!")
if old_hash and new_hash:
print(f"Eski Hash: {old_hash[:10]}... Yeni Hash: {new_hash[:10]}...")
elif new_hash:
print(f"Yeni Hash: {new_hash[:10]}...")
class FileChangeHandler(FileSystemEventHandler):
"""watchdog olaylarını işleyen sınıf."""
def on_created(self, event):
if event.is_directory:
print(f"Dizin oluşturuldu: {event.src_path}")
# Yeni dizindeki mevcut dosyaları da ilk taramaya dahil et
for root, _, files in os.walk(event.src_path):
for filename in files:
filepath = os.path.join(root, filename)
current_hash = calculate_file_hash(filepath)
if current_hash:
log_change(filepath, 'added', new_hash=current_hash)
record_file_state(filepath, current_hash)
return
# Dosya oluşturulduğunda
filepath = event.src_path
current_hash = calculate_file_hash(filepath)
if current_hash:
log_change(filepath, 'added', new_hash=current_hash)
record_file_state(filepath, current_hash)
def on_deleted(self, event):
if event.is_directory:
print(f"Dizin silindi: {event.src_path}")
# Dizin içindeki tüm dosyaları da veritabanından sil
conn = sqlite3.connect(DATABASE_NAME)
cursor = conn.cursor()
cursor.execute('SELECT filepath FROM files WHERE filepath LIKE ?', (event.src_path + '%',))
deleted_files = [row[0] for row in cursor.fetchall()]
conn.close()
for filepath in deleted_files:
log_change(filepath, 'deleted', old_hash=get_file_state(filepath))
delete_file_state(filepath)
return
# Dosya silindiğinde
filepath = event.src_path
old_hash = get_file_state(filepath)
if old_hash:
log_change(filepath, 'deleted', old_hash=old_hash)
delete_file_state(filepath)
def on_modified(self, event):
if event.is_directory:
return # Dizin modifikasyonları genellikle bizi ilgilendirmez
# Dosya değiştirildiğinde
filepath = event.src_path
old_hash = get_file_state(filepath)
current_hash = calculate_file_hash(filepath)
if old_hash and current_hash and old_hash != current_hash:
log_change(filepath, 'modified', old_hash=old_hash, new_hash=current_hash)
record_file_state(filepath, current_hash) # Yeni hash'i kaydet
elif not old_hash and current_hash:
# Dosya başlangıçta izlenmiyorsa ama modifiye edildiyse
log_change(filepath, 'modified (initial add)', new_hash=current_hash)
record_file_state(filepath, current_hash)
def on_moved(self, event):
# Dosya taşındığında veya yeniden adlandırıldığında
old_filepath = event.src_path
new_filepath = event.dest_path
old_hash = get_file_state(old_filepath)
# Eski dosya kaydını sil
if old_hash:
delete_file_state(old_filepath)
log_change(old_filepath, 'moved_from', old_hash=old_hash)
# Yeni dosya kaydını oluştur
current_hash = calculate_file_hash(new_filepath)
if current_hash:
record_file_state(new_filepath, current_hash)
log_change(new_filepath, 'moved_to', new_hash=current_hash)
def initial_scan_and_populate(directory):
"""İzlemeye başlamadan önce dizindeki tüm dosyaları tarar ve veritabanına kaydeder."""
print(f"Başlangıç taraması yapılıyor: {directory}")
for root, _, files in os.walk(directory):
for filename in files:
filepath = os.path.join(root, filename)
current_hash = calculate_file_hash(filepath)
if current_hash:
record_file_state(filepath, current_hash)
print("Başlangıç taraması tamamlandı.")
if __name__ == "__main__":
initialize_database()
os.makedirs(MONITORED_DIR, exist_ok=True)
# İzlenecek dizini başlangıçta doldur
with open(os.path.join(MONITORED_DIR, "system_config.conf"), "w") as f:
f.write("setting=true\nversion=1.0")
with open(os.path.join(MONITORED_DIR, "important_data.csv"), "w") as f:
f.write("id,name\n1,test")
initial_scan_and_populate(MONITORED_DIR)
event_handler = FileChangeHandler()
observer = Observer()
observer.schedule(event_handler, MONITORED_DIR, recursive=True)
observer.start()
print(f"'{MONITORED_DIR}' dizini gerçek zamanlı olarak izleniyor. Çıkmak için Ctrl+C.")
try:
while True:
time.sleep(1) # Observer'ın çalışmaya devam etmesini sağlar
except KeyboardInterrupt:
observer.stop()
observer.join()
print("İzleme durduruldu.")
# Temizlik (isteğe bağlı)
# import shutil
# shutil.rmtree(MONITORED_DIR)
# os.remove(DATABASE_NAME)
Vaka Analizi: Web Sunucusu Bütünlük Kontrolü
Küçük bir e-ticaret sitesi, daha önce bir SQL enjeksiyon saldırısı sonucu web sayfalarının kötü amaçlı kodlarla değiştirilmesiyle büyük kayıp yaşamıştı. Bu durumun tekrarlanmasını engellemek için watchdog tabanlı bir FIM çözümü entegre etmeye karar verdiler. Web sunucusunun public_html dizini ve wp-config.php gibi kritik PHP dosyalarının bulunduğu dizinler watchdog ile izlemeye alındı. Herhangi bir PHP dosyasında yapılan bir değişiklik anında tespit edilip yöneticilere e-posta ile bildiriliyordu. Bir gün, gece yarısı bir index.php dosyasında beklenmedik bir değişiklik algılandı. FIM sistemi anında bir uyarı gönderdi ve güvenlik ekibi müdahale ederek değişikliğin yetkisiz olduğunu ve bir zayıf eklentiden kaynaklandığını tespit etti. Saldırı daha fazla yayılmadan engellendi ve site hızlıca eski haline getirildi. Bu, watchdog ile elde edilen gerçek zamanlıya yakın tespitin somut bir örneğidir.
Performans Optimizasyonu ve Gelişmiş Özellikler
"2 saniyede dosya değişikliği tespiti" hedefine ulaşmak için sadece event-driven izleme yeterli olmayabilir; aynı zamanda performans optimizasyonlarına ve sisteminizi daha dayanıklı hale getirecek gelişmiş özelliklere de ihtiyacımız var. Özellikle çok sayıda dosyanın bulunduğu sistemlerde veya yüksek I/O yükü olan ortamlarda bu optimizasyonlar kritik hale gelir.
Veritabanı Performansı ve Ölçeklenebilirlik
Küçük sistemler için SQLite yeterli olsa da, binlerce, hatta milyonlarca dosyanın izlendiği büyük ortamlar için daha güçlü veritabanı çözümlerine yönelmek gerekebilir. PostgreSQL veya MySQL gibi ilişkisel veritabanları, concurrent (eşzamanlı) işlemlerde daha iyi performans sunar ve daha gelişmiş indeksleme, replikasyon ve yedekleme özellikleri sağlar. Örneğin, PostgreSQL'de dosya yollarını indekslemek, sorguların çok daha hızlı çalışmasını sağlayacaktır:
CREATE INDEX idx_files_filepath ON files (filepath);
CREATE INDEX idx_changes_filepath ON changes (filepath);
Ayrıca, veritabanı bağlantı havuzları (connection pools) kullanmak, her dosya değişikliği olayında yeni bir bağlantı açma ve kapatma yükünü ortadan kaldırarak performansı artırabilir. Python'da SQLAlchemy gibi ORM kütüphaneleri bu tür optimizasyonları kolaylaştırır. SQLite kullanmaya devam ediyorsanız, WAL (Write-Ahead Logging) modunu etkinleştirmek, eşzamanlı okuma ve yazma işlemlerini iyileştirerek performansı artırabilir.
Filtreleme ve İstenmeyen Olayları Engelleme
Gerçek zamanlı izleme, çoğu zaman sistem tarafından oluşturulan geçici dosyalar, log dosyaları veya sürekli değişen önbellek dosyaları gibi bizi ilgilendirmeyen birçok olayı da yakalar. Bu "gürültüyü" filtrelemek, hem performans açısından önemlidir hem de gereksiz uyarılarla yorulmayı engeller. watchdog kütüphanesi, PatternMatchingEventHandler gibi sınıflar sunarak belirli dosya desenlerini veya dizinleri dahil etme/hariç tutma yeteneği sağlar. Örneğin, .log veya .tmp uzantılı dosyaları veya belirli dizinleri izleme dışı bırakabilirsiniz.
# Sadece .conf ve .txt dosyalarını izle, .log dosyalarını görmezden gel
from watchdog.events import PatternMatchingEventHandler
class CustomEventHandler(PatternMatchingEventHandler):
def __init__(self, patterns=None, ignore_patterns=None, ignore_directories=False, case_sensitive=False):
super().__init__(patterns, ignore_patterns, ignore_directories, case_sensitive)
self.file_integrity_monitor = FileChangeHandler() # Kendi event handler'ımızı çağırıyoruz
def on_modified(self, event):
if not event.is_directory:
print(f"Filtrelenmiş değişiklik: {event.src_path}")
self.file_integrity_monitor.on_modified(event)
# Örnek kullanımda:
# event_handler = CustomEventHandler(
# patterns=["*.conf", "*.txt"],
# ignore_patterns=["*.log", "*.tmp"],
# ignore_directories=True
# )
Bu şekilde, yalnızca gerçekten önemli olan dosya değişikliklerine odaklanabilir, sistemin gereksiz yükünü azaltabilir ve "2 saniye" hedefine daha yakın kalabilirsiniz.
Dağıtık Ortamlar ve Merkezi Yönetim
Tek bir sunucuyu izlemek nispeten kolaydır, ancak yüzlerce sunucu veya konteynerden oluşan dağıtık bir ortamda FIM uygulamak daha karmaşıktır. Bu senaryolarda, her sunucuda çalışan Python FIM ajanlarının, tespit ettikleri değişiklikleri merkezi bir sisteme (örneğin, bir mesaj kuyruğu (Kafka, RabbitMQ) veya doğrudan bir SIEM/log yönetimi çözümüne) göndermesi gerekir. Bu merkezi sistem, tüm uyarıları toplar, korelasyon analizleri yapar ve yöneticilere konsolide bir görünüm sunar. Python'daki requests kütüphanesi ile basit API çağrıları yaparak veya pika gibi kütüphanelerle mesaj kuyruklarına entegre olarak bu dağıtık yapıyı kurabilirsiniz.
Güvenlik ve Kimlik Doğrulama
FIM sisteminin kendisi de güvenli olmalıdır. Veritabanı bağlantı bilgileri, API anahtarları gibi hassas bilgiler açık metin olarak depolanmamalı, bunun yerine ortam değişkenleri veya güvenli bir sır yönetimi çözümü (Vault, AWS Secrets Manager) kullanılmalıdır. Ayrıca, FIM ajanının çalıştırıldığı kullanıcı hesabı, sadece izlemesi gereken dosyalara okuma erişimi olan ve sistemde minimum ayrıcalıklara sahip bir kullanıcı olmalıdır. Bu, FIM ajanı ele geçirilse bile potansiyel zararın minimize edilmesini sağlar.
Hata Yönetimi ve Dayanıklılık
FIM uygulamaları, dosya kilitleri, disk hataları, ağ sorunları gibi birçok beklenmedik durumla karşılaşabilir. Uygulamanızın bu durumları gracefully (zarafetle) ele alması ve çökmek yerine loglama yapıp çalışmaya devam etmesi önemlidir. try-except blokları ile olası hataları yakalamak, yeniden deneme mekanizmaları (retries) eklemek ve ayrıntılı hata loglaması yapmak, sistemin dayanıklılığını artırır. Örneğin, bir dosyayı hash'lemeye çalışırken PermissionError alırsanız, bunu loglayıp sonraki dosyaya geçmelisiniz. Tüm bu gelişmiş yaklaşımlar, FIM sisteminizin sadece hızlı değil, aynı zamanda sağlam ve güvenilir olmasını sağlar, böylece "2 saniyede dosya değişikliği tespiti" vaadini gerçek bir güvenlik avantajına dönüştürür.
Sonuç ve Sıkça Sorulan Sorular
Bu makalede, dosya bütünlüğü izlemenin (FIM) neden modern siber güvenlik stratejilerinin temel bir bileşeni olduğunu derinlemesine inceledik. Python'un güçlü yeteneklerini kullanarak, hem polling tabanlı basit bir FIM sistemi nasıl kuracağınızı hem de watchdog kütüphanesi aracılığıyla gerçek zamanlıya yakın, olay tabanlı izlemenin nasıl uygulanacağını adım adım öğrendiniz. Ayrıca, sisteminizin ölçeklenebilirliğini ve güvenilirliğini artırmak için veritabanı optimizasyonları, filtreleme teknikleri ve dağıtık ortamlar için stratejiler gibi gelişmiş konulara da değindik.
Gördüğümüz gibi, "2 saniyede dosya değişikliği tespiti" sadece bir hedef değil, doğru araçlar ve yaklaşımlarla ulaşılabilir bir güvenlik seviyesidir. Python'un esnekliği ve zengin kütüphane ekosistemi sayesinde, kuruluşlar kendi özel ihtiyaçlarına göre uyarlanmış, maliyet-etkin FIM çözümleri geliştirebilirler. Bu, siber saldırılara karşı erken uyarı mekanizmaları oluşturarak potansiyel zararları en aza indirmek, düzenleyici uyumluluğu sağlamak ve genel sistem bütünlüğünü korumak için kritik bir adımdır.
Unutmayın ki bir FIM çözümünün başarısı sadece teknik uygulamasına değil, aynı zamanda doğru izleme kapsamının belirlenmesine, elde edilen uyarıların düzgün bir şekilde analiz edilmesine ve hızlı müdahale planlarının olmasına da bağlıdır. Proaktif bir güvenlik duruşu, sürekli iyileştirme ve teknolojik yenilikleri takip etmeyi gerektirir. Python ile geliştireceğiniz FIM sistemi, bu yolculukta size önemli bir avantaj sağlayacaktır.
Sıkça Sorulan Sorular (SSS)
-
Python ile FIM kurmak, ticari bir FIM çözümüne göre daha mı iyi?
Python ile kendi FIM çözümünüzü kurmak, size maksimum esneklik ve özelleştirme imkanı sunar. Ticari çözümler genellikle daha kapsamlı özellikler ve hazır entegrasyonlar sağlarken, özel ihtiyaçlara göre uyarlama zor olabilir ve maliyetli olabilir. Python çözümü, belirli dosya tiplerine, dizinlere veya iş akışlarına odaklanarak daha hafif ve hızlı bir yapı oluşturmanıza olanak tanır. Ancak, bakım, destek ve gelişmiş raporlama gibi konularda daha fazla efor gerektirebilir.
-
Hangi dosyaları izlemeliyim? Her şeyi izlemek gerekli mi?
Hayır, her şeyi izlemek genellikle ne gerekli ne de verimlidir. Genellikle, işletim sistemi dosyaları, uygulama yapılandırma dosyaları, kritik veri dizinleri (örneğin, web sunucusu
public_htmlveya veritabanı dosyaları), güvenlik ayarları ve log dosyalarını izlemelisiniz. Sürekli değişen ve kritik olmayan dosyaları (geçici dosyalar, önbellekler, kullanıcının kişisel belgeleri) izlemek, gereksiz gürültüye ve performans düşüşüne neden olabilir. İzlenecek dosyaların kapsamı, sistemin kritikliği ve düzenleyici uyumluluk gereksinimlerine göre belirlenmelidir. -
FIM, bir saldırıyı tamamen engelleyebilir mi?
FIM, bir saldırıyı doğrudan engellemez; ancak bir saldırının gerçekleştiğini veya sistemde yetkisiz bir değişikliğin yapıldığını çok hızlı bir şekilde tespit ederek güvenlik ekiplerine erken uyarı sağlar. Bu erken tespit, saldırının daha fazla yayılmasını veya daha büyük zararlar vermesini engellemek için kritik öneme sahiptir. FIM, bir savunma katmanı olarak diğer güvenlik kontrolleri (güvenlik duvarları, IDS/IPS, antivirüs vb.) ile birlikte çalışmalıdır.
-
Çok sayıda dosya olan bir sistemde performans sorunları yaşamamak için ne yapmalıyım?
Büyük sistemlerde performansı optimize etmek için birkaç strateji izleyebilirsiniz: yalnızca kritik dizinleri ve dosya tiplerini izleyin,
watchdoggibi olay tabanlı izleme kütüphaneleri kullanın (polling yerine), hash değerlerini bir veritabanında saklayın ve veritabanı indekslerini doğru bir şekilde kullanın. Ayrıca, izleme görevini daha küçük parçalara bölerek birden fazla Python süreci veya thread ile paralel çalıştırmayı düşünebilirsiniz. -
Tespit edilen değişiklikler hakkında nasıl uyarı almalıyım?
Uyarı mekanizması, tespit süresi kadar önemlidir. Python ile e-posta (
smtplib), SMS (üçüncü parti API'ler), anlık mesajlaşma (Slack, Telegram gibi platformların API'leri) veya merkezi bir SIEM/log yönetimi sistemine (Splunk, ELK Stack) log gönderme gibi çeşitli yollarla uyarılar gönderebilirsiniz. En iyi yaklaşım, güvenlik operasyonları ekibinizin kullandığı mevcut araçlara entegrasyon sağlamaktır. Bu entegrasyon, uyarıların daha hızlı görülmesini ve müdahale edilmesini sağlar.
