QueryProxy
Doküman menüsü

Denetim zinciri ve SIEM dışa aktarımı

QueryProxy denetim kayıtlarını nasıl zincirleyip doğrular ve her denetim olayını SIEM'iniz için stdout, syslog ya da imzalı bir webhook'a nasıl gönderirsiniz.

Güncelleme:

Her denetim kaydı iki kez korunur: uygulama veritabanı kayıtları bir hash zincirine bağlar ve isteğe bağlı sink’ler her olayı veritabanı yöneticisinin denetlemediği bir sisteme kopyalar. İkinci kısım önemlidir; çünkü yalnızca veritabanı içinde tutulan bir zinciri, veritabanının sahibi olan biri yeniden yazabilir.

Hash zinciri

Her kayıt prev_hash ve hash saklar; burada hash = SHA-256(prev_hash || canonical_json) kaydın alanları (takım, kullanıcı, eylem, talep, bağlantı, SQL, anahtarları sıralı metadata, IP ve zaman) üzerinden hesaplanır. Kayıtlar, bir kilit satırını da alan tek bir transaction içinde bağlanır; böylece zincir çatallanamaz. İki hash üzerindeki unique index’ler, aynı öncülü olan ikinci bir kaydı reddeder.

Veritabanı trigger’ları denetim tablosunda UPDATE ve DELETE’i, PostgreSQL’de ayrıca TRUNCATE’i reddeder (MySQL ve MariaDB trigger’ları bunu engelleyemez).

Doğrulama

docker exec queryproxy php artisan audit:verify

Komut zinciri ilk kayıttan itibaren dolaşır. Zincir sağlamsa kayıt sayısını ve zincirin başını basar ve 0 ile çıkar. Değilse ilk bozuk kaydın id’sini ve nedenini basar ve 1 ile çıkar. Değiştirilmiş kayıtları, kaldırılmış ya da araya eklenmiş kayıtları, yeniden sıralanmış bir zinciri, ilk kayıttan başlamayan bir zinciri ve yazılan kayıt sayısından kısa bir zinciri (kaldırılmış bir kuyruk ya da boşaltılmış bir tablo) saptar. queryproxy:doctor en yeni kayıtların ve zincir başının daha hızlı bir kontrolünü yapar; queryproxy:doctor --full-audit tüm zinciri dolaşır.

Checkpoint’ler

Zamanlayıcı her gün audit:checkpoint çalıştırır. Son kayıt id’sini, hash’ini ve kayıt sayısını içeren bir audit.checkpoint olayı yazar; bir öncekinden beri hiçbir şey yazılmadıysa yazmaz. Checkpoint sıradan bir denetim olayıdır; bu yüzden sink’lerinize de gider.

Zincirin yapamadıkları

  • Trigger’ları kaldırıp zinciri yeniden hesaplayan bir veritabanı sahibini yakalayamaz. Bu güce sahip biri tutarlı bir geçmiş yazabilir. Farkı yalnızca veritabanının dışında, SIEM’inizde tutulan bir kopya gösterir. Checkpoint’lerin ve aşağıdaki sink’lerin amacı budur.
  • MySQL ve MariaDB: created_at UTC duvar saati olarak hash’lendiği için bağlantı saat dilimi UTC’ye sabitlenir. QueryProxy’nin arkasından sunucunun ya da oturumun saat dilimini değiştirmeyin.
  • Denetim yazıcısını çağıran uzun dış transaction’lar, bitene kadar kilit satırını tutar; bu yüzden diğer yazıcılar bekler.

SIEM’e aktarım

Her sink varsayılan olarak kapalıdır. QUERYPROXY_SIEM_SINKS onları açar: stdout, syslog ve webhook değerlerinin virgülle ayrılmış, herhangi bir kombinasyonlu listesi.

Teslim, denetim kaydı commit edildikten sonra kuyrukta çalışır; bu yüzden çökmüş bir sink bir denetim yazmasını asla engellemez ya da geri almaz. Teslim en az bir kez yapılır: alıcı olayın id’si üzerinden tekilleştirme yapmalıdır. Başarısız olmaya devam eden bir webhook ya da syslog teslimi, ölü mektup kuyruğu (dead-letter queue) görevi gören failed_jobs içine düşer (php artisan queue:failed). Kuyruk backend’inin kendisi çökmüşse olay dışa aktarılmaz ve sorun loglanır; kayıt sistemi veritabanı olarak kalır ve zinciri eksiksiz kalır. Boşluk, SIEM kopyasında dizide eksik bir id olarak görünür.

Değişken Varsayılan Anlamı
QUERYPROXY_SIEM_SINKS yok Açılacak sink’ler: stdout, syslog, webhook
QUERYPROXY_SIEM_QUEUE default Teslimlerin çalıştığı kuyruk. Hazır işçi default’a hizmet verir; farklı bir ad için ona ait bir işçi gerekir
QUERYPROXY_SIEM_STDOUT_STREAM php://stdout stdout sink’inin yazdığı stream
QUERYPROXY_SIEM_SYSLOG_HOST yok Syslog alıcısının host’u
QUERYPROXY_SIEM_SYSLOG_PORT 514 (tls için 6514) Alıcı portu
QUERYPROXY_SIEM_SYSLOG_TRANSPORT udp udp, tcp veya tls
QUERYPROXY_SIEM_SYSLOG_FRAMING octet-counting tcp ve tls için: octet-counting veya newline
QUERYPROXY_SIEM_SYSLOG_FACILITY 13 Syslog facility (13 “log audit”tir)
QUERYPROXY_SIEM_SYSLOG_APP_NAME queryproxy APP-NAME alanı
QUERYPROXY_SIEM_SYSLOG_HOSTNAME yok HOSTNAME alanı
QUERYPROXY_SIEM_SYSLOG_TLS_CA_FILE yok Bir tls alıcısını doğrulamak için CA dosyası; boşsa sistem güven deposu kullanılır
QUERYPROXY_SIEM_SYSLOG_TIMEOUT 5 Saniye
QUERYPROXY_SIEM_WEBHOOK_URL yok Her olayı alan http:// veya https:// URL’si
QUERYPROXY_SIEM_WEBHOOK_SECRET yok İmzalama secret’ı, en az 16 karakter. QUERYPROXY_SIEM_WEBHOOK_SECRET_FILE onu bir dosyadan okur
QUERYPROXY_SIEM_WEBHOOK_TIMEOUT 5 Saniye
QUERYPROXY_SIEM_WEBHOOK_TRIES 6 İş başarısız olmadan önceki teslim denemeleri

Yapılandırması hatalı bir sink kullanılmaz ve sorun süreç başına bir kez loglanır. queryproxy:doctor bunu siem_sinks olarak bildirir.

Olay

Tüm sink’ler aynı JSON belgesini gönderir; belge docs/audit-event.schema.json ile tanımlanır (JSON Schema Draft 2020-12, additionalProperties: false, schema_version: 1).

Alan Anlamı
id Denetim kaydı id’si; kurulum başına benzersiz. Buna göre tekilleştirin
timestamp UTC, saniye hassasiyetinde
instance Kurulumun APP_URL’inin host’u; ayarlı değilse null
action Olay adı, örneğin request.approved
category action’ın noktadan önceki kısmı
actor { "id", "email" }, sistem olayları için null
team_id, connection_id, query_request_id İlişkili nesneler ya da null
ip İstemci adresi; konsol ve kuyruk olayları için null
sql_redacted Literal’leri yer tutucularla değiştirilmiş SQL ya da null
sql_hidden SQL var ama güvenle redakte edilemediğinde true
metadata Olaya özgü ayrıntılar ya da null

Ham SQL asla dışa aktarılmaz. Şemanın action listesi olay kataloğundan üretilir ve user, request, connection, masking_rule, team, auth, chat_integration, chat_identity, execution, audit, masking_key, error_messages ve result kategorilerinde gruplanmış 50 olay içerir. actor.email, olay teslim edilirken okunur; bu yüzden denetim yazısı ile teslim arasında e-posta adresini değiştiren bir kullanıcı yeni adresiyle görünür.

stdout

Konteynerin standart çıktısında satır başına bir JSON nesnesi. Aynı stream nginx, php-fpm ve kuyruk işçisinin çıktısını da (RUNNING ve DONE satırları) taşır; bu yüzden toplayıcı JSON olmayan satırları atlamalıdır. Konteyner log driver’ları ve Docker logunu okuyan agent’lar bunu alır.

syslog

Gövdesi JSON olay olan bir RFC 5424 mesajı; UDP, TCP ya da TLS üzerinden. TCP ve TLS, newline seçmediğiniz sürece octet-counting framing (RFC 6587) kullanır. tls ile QueryProxy alıcının sertifikasını ve adını doğrular; alıcının CA’sı sistem güven deposunda değilse QUERYPROXY_SIEM_SYSLOG_TLS_CA_FILE ayarlayın. Standart TLS syslog portu 6514’tür.

İmzalı webhook

QueryProxy, JSON olayı şu başlıklarla POST eder ve yönlendirmeleri izlemez:

Başlık İçerik
X-QueryProxy-Timestamp Teslimin yapıldığı Unix saniyesi
X-QueryProxy-Signature sha256= ve ardından secret ile "{timestamp}.{body}" üzerinden hesaplanan HMAC-SHA256’nın hex değeri
X-QueryProxy-Event action
X-QueryProxy-Event-Id Denetim kaydı id’si
User-Agent QueryProxy-Audit/1

En az 16 karakterlik secret’ı olmayan bir webhook asla imzasız gönderilmez. 2xx dışındaki her HTTP durumu başarısızlık sayılır ve artan bir gecikmeyle yeniden denenir (10 sn, 1 dk, 5 dk, 15 dk, ardından 1 sa). Bir teslime güvenmeden önce doğrulayın:

import hashlib
import hmac
import time

def is_valid(secret: str, timestamp: str, raw_body: bytes, signature: str) -> bool:
    # Reject stale deliveries; a retry carries a fresh timestamp.
    if abs(time.time() - int(timestamp)) > 300:
        return False
    message = timestamp.encode() + b"." + raw_body
    expected = "sha256=" + hmac.new(secret.encode(), message, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature)

İmzayı, yeniden serileştirilmiş bir kopya üzerinden değil, alındığı haliyle ham gövde üzerinden hesaplayın.

Ürüne özgü connector’lar (Splunk, Elastic, Wazuh, Microsoft Sentinel) ile gelmez. Syslog kabul eden, container loglarını okuyan ya da imzalı bir HTTP POST alan herhangi bir toplayıcı bu olayları içeri alabilir.

Sonraki adımlar

Gezinmek için ok tuşları, açmak için Enter.