CodeAuditAgent
Tüm yazılar
  • Güvenlik
  • Git
  • Gizli Anahtarlar

Git Geçmişinde Sızan Gizli Anahtarlar: Bulun, Değiştirin, Önleyin

Commit edilmiş bir API anahtarını silmek onu git geçmişinden kaldırmaz. Sızan anahtarları bulun, önce değiştirin, geçmişi güvenle yeniden yazın ve sızıntıyı önleyin.

· 7 dk okuma · Lina Source LLC

Biri bir .env dosyasını commit eder ya da bir şeyi hızlıca denemek için canlı bir API anahtarını bir yapılandırma modülüne yapıştırır. Bir inceleyen fark eder, anahtar bir sonraki commit'te silinir ve herkes yoluna devam eder. Oysa anahtar hâlâ oradadır. Git her dosyanın her sürümünü saklar ve depoyu klonlayabilen herkes anahtarı ekleyen commit'i okuyabilir.

Koda gömülü kimlik bilgileri CWE-798 olarak sınıflandırılır. Bu rehber, böyle bir bilgi geçmişe çoktan girmişse ne yapmanız gerektiğini anlatıyor: her gizli anahtarı bulun, her şeyden önce değiştirin, geçmişi yeniden yazmaya değip değmeyeceğine karar verin ve bir sonrakini durduracak korumaları kurun.

Satırı silmek neden yetmez

Bir gizli anahtarı kaldıran commit, anahtarı içermeyen yeni bir anlık görüntü ekler. Anahtarı içeren önceki anlık görüntü ise dalın geçmişinde hâlâ referans alınmaktadır. git log -p onu gösterir, eski commit'e git checkout yapmak onu geri getirir ve mevcut her klon ile fork'ta zaten bir kopyası vardır. Orijinal commit'ler bir kez push edildiyse, merge öncesinde dalı squash etmek de işe yaramaz: uzak depo onları hâlâ tutuyor olabilir ve bunları fetch eden herkesin yerel kopyasında bulunur.

Herkese açık bir depoda, anahtarın görüldüğünü varsayın. Otomatik tarayıcılar herkese açık push'ları kimlik bilgisi kalıpları için izler ve bir push ile ilk kötüye kullanım arasındaki süre çok kısa olabilir. Özel bir depoda risk daha küçüktür ama sıfır değildir: okuma erişimi olan her çalışan, yüklenici, CI sistemi ve entegrasyon anahtara sahiptir.

Adım 1: önce değiştirin

Riski gerçekten ortadan kaldıran tek adım anahtarı değiştirmektir (rotation). Geçmişi yeniden yazmak, anahtarı gelecekteki klonlardan gizler; zaten var olan kopyalar için hiçbir şey yapmaz. Bu yüzden depoya dokunmadan önce kimlik bilgisini iptal edin ve yenisiyle değiştirin.

Değişikliği kesintiye yol açmayacak şekilde planlayın. Birçok sağlayıcı aynı anda iki anahtarın geçerli olmasına izin verir: yeni anahtarı oluşturun, eskisinin kullanıldığı her yere dağıtın, trafiğin yeni anahtara geçtiğini doğrulayın, ardından eskisini iptal edin. Sağlayıcı yalnızca tek bir anahtara izin veriyorsa kısa bir kesintiyi kabul edin; birkaç dakikalık kesinti, kusursuz bir geçişi koordine ederken sızdığı bilinen bir kimlik bilgisini aktif bırakmaktan daha iyi bir takastır.

  • Sağlayıcının konsolunda yeni bir anahtar oluşturun ve normal yapılandırma yolunuz üzerinden dağıtın.
  • Eski anahtarı iptal edin. Yalnızca kullanmayı bırakmayın; kullanılmayan geçerli bir anahtar hâlâ geçerli bir anahtardır.
  • Commit tarihinden bu yana eski anahtarla yapılan etkinlikler için sağlayıcının denetim loglarını kontrol edin: API çağrıları, yeni kullanıcılar, değiştirilmiş izinler, beklenmedik faturalar.
  • Gizli bilgi bir veritabanı parolası veya imzalama anahtarıysa neleri açabileceğini düşünün. Sızan bir JWT imzalama anahtarı, herhangi bir token'ın sahtesinin üretilmiş olabileceği anlamına gelir; bu yüzden mevcut oturumları geçersiz kılın.
  • Neyin, ne kadar süreyle açığa çıktığını ve neleri değiştirdiğinizi yazın. Bir müşteri veya denetçi sorarsa bu kayda ihtiyacınız olacak.

Adım 2: sızan her şeyi bulun

Commit edilmiş bir gizli anahtarın olduğu yerde çoğu zaman başkaları da vardır. Yalnızca mevcut ağacı değil, her dal ve etiket dahil tüm geçmişi tarayın.

# Commits that added or removed a string anywhere in history
git log -p -S "sk_live_" --all

# Regex search across the diffs of all commits
git log -p -G "AKIA[0-9A-Z]{16}" --all

# Files that ever existed at a suspicious path
git log --all --oneline -- .env config/production.json

# Dedicated scanners check hundreds of known credential formats
gitleaks git -v .
trufflehog git file://. --only-verified

gitleaks ve trufflehog, tam da bu iş için geliştirilmiş açık kaynak tarayıcılardır. Yaygın sağlayıcı anahtarlarının biçimlerini bilirler ve trufflehog bulunan bir kimlik bilgisinin hâlâ geçerli olup olmadığını kontrol edebilir. Eski gitleaks sürümleri git alt komutu yerine gitleaks detect --source . kullanır. Tarayıcıyı bir kez tüm geçmiş üzerinde çalıştırın, ardından yeni commit'lerde çalışmaya devam etmesini sağlayın. Test fixture'ları ve dokümantasyondaki örnek anahtarlar gibi bazı yanlış pozitifler bekleyin. Her birini inceleyin, ardından doğrulanmış yanlış pozitifleri tarayıcının izin listesine veya baseline dosyasına kaydedin; böylece sonraki çalıştırma yalnızca yeni bulguları gösterir.

Deponun çevresindeki yerleri de unutmayın: ortam değişkenlerini ekrana basan CI logları, issue ve pull request yorumları, wiki sayfaları, depodan oluşturulan Docker imaj katmanları ve hata ayıklarken paylaşılan gist'ler veya paste'ler.

Adım 3: geçmişi yeniden yazıp yazmamaya karar verin

Gizli anahtar değiştirildikten sonra işe yaramaz hâle gelir; bu yüzden geçmişi yeniden yazmak bir sınırlama değil, temizlik adımıdır. Yine de depo herkese açıksa, anahtar kendisinin ötesinde bir şey açığa çıkarıyorsa (dahili bir sunucu adı, bir müşteri adı) ya da uyumluluk gerektiriyorsa yapmaya değer. Gerçek maliyetleri vardır: her iş birlikçinin yeniden klonlaması gerekir, açık pull request'ler aksar ve commit hash'leri değişir. Sürüm notları, dağıtım kayıtları, issue bağlantıları veya diğer depolarda sabitlenmiş bağımlılıklar gibi bir commit'e hash ile başvuran her şey, artık dalda bulunmayan commit'leri gösterecektir. Yeniden yazmayı önceden duyurun, sakin bir zaman seçin ve açık pull request'leri önce merge edin veya kapatın.

Git projesinin bu iş için önerdiği araç, eski git filter-branch yerine git filter-repo'dur. Temiz bir klon üzerinde çalışır ve güvenlik önlemi olarak origin remote'unu kaldırır; bu yüzden push etmeden önce onu geri eklersiniz.

# Start from a fresh clone
git clone [email protected]:acme/api.git api-clean
cd api-clean

# Option A: remove a file from every commit
git filter-repo --invert-paths --path config/production.env

# Option B: replace secret strings everywhere they appear
# replacements.txt contains one rule per line, for example:
#   PASTE_THE_OLD_KEY_HERE==>REDACTED
git filter-repo --replace-text ../replacements.txt

# filter-repo removes origin; add it back and force-push
git remote add origin [email protected]:acme/api.git
git push --force --all
git push --force --tags

Yeniden yazmanın yapamadıkları

  • Mevcut klonlara, fork'lara, CI önbelleklerine veya yedeklere ulaşamaz. Yeniden yazmadan önce fetch eden herkes eski commit'leri saklamaya devam eder.
  • GitHub'da pull request'ler için oluşturulan referanslar salt okunurdur ve eski commit'leri erişilebilir tutabilir. Önbelleğe alınmış görünümleri ve bu referansları kaldırmak için GitHub Support ile iletişime geçmek gerekir.
  • Eski bir klondan pull veya merge yapan iş birlikçiler eski geçmişi doğrudan geri push edebilir. Herkesten yeniden klonlamasını isteyin ve bu süreçte dalı koruma altına alın.
  • Gizli anahtarı kopyalandığı diğer yerlerden kaldırmaz: loglar, destek kayıtları, sohbet mesajları veya derlenmiş artifact'ler.

Sıranın önemli olmasının nedeni budur. Önce değiştirin, sonra temizleyin. Canlı bir anahtar içeren yeniden yazılmış bir geçmiş, sahte bir güvenlik hissi verir. Push'tan sonra tarayıcınızı temiz bir klon üzerinde çalıştırarak anahtarın her dal ve etiketten gerçekten silindiğini doğrulayın.

Adım 4: bir sonrakini önleyin

Amaç, gizli bir anahtarı commit etmeyi zorlaştırmak ve commit edileni hızla fark etmektir. Hiçbir kontrol ikisini birden yapamaz; bu yüzden katmanlar oluşturun.

Gizli anahtarları kod yolunun dışında tutun

Kimlik bilgilerini çalışma zamanında ortam değişkenlerinden veya bir secret manager'dan okuyun ve ihtiyaç duyduklarınızın mevcut olduğunu uygulama başlarken doğrulayın. Yer tutucu değerlerle bir .env.example commit edin ve .env'i ilk commit'ten itibaren .gitignore'a ekleyin. Üretim ortamında AWS Secrets Manager, Google Secret Manager, HashiCorp Vault gibi bir secret manager veya platformunuzun şifreli ortam ayarları size erişim kontrolü, denetim logları ve daha kolay anahtar değişimi sağlar.

Gizli anahtarları commit edilmeden önce engelleyin

Bir pre-commit hook, hatayı uzak depoya ulaşmadan, geliştiricinin makinesinde yakalar. pre-commit framework'ü bunu, her katkıcının kurabileceği birkaç satırlık bir yapılandırmaya indirger.

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/gitleaks/gitleaks
    rev: vX.Y.Z  # pin to the latest release tag
    hooks:
      - id: gitleaks

# Install once per clone
#   pip install pre-commit
#   pre-commit install

Hook'lar yereldir ve atlanabilir; bu yüzden aynı tarayıcıyı son savunma hattı olarak her push'ta CI'da da çalıştırın. GitHub'da, planınızın desteklediği yerlerde secret scanning ve push protection özelliklerini etkinleştirin; push protection, tanınan sağlayıcı token'larını içeren push'ları sunucu tarafında reddeder.

Gözden kaçan sızıntıların hasarını azaltın

  • Her anahtarı minimum izinlerle ve sağlayıcının izin verdiği yerlerde belirli IP'ler veya referrer'larla sınırlandırın.
  • Uzun ömürlü statik anahtarlar yerine CI'dan bulut sağlayıcınıza OIDC federasyonu gibi kısa ömürlü kimlik bilgilerini tercih edin.
  • Her ortam için ayrı anahtarlar kullanın; böylece sızan bir test anahtarı üretim ortamına dokunamaz.
  • Her kritik gizli anahtar için bir değişim runbook'u tutun; böylece baskı altında anahtar değiştirmek doğaçlama değil, rutin bir iş olur.

Kod incelemesinin yeri

Tarayıcılar bilinen biçimleri iyi eşleştirir; ancak iki sabitten birleştirilen bir parola veya bir yapılandırma fallback'inde gelen varsayılan bir kimlik bilgisi gibi bağlam gerektiren durumlarda zayıftır. Kod üzerinden yapılan bir inceleme bunları yakalar. CodeAuditAgent, herkese açık bir deponun varsayılan dalını veya yapıştırılmış bir kod parçasını denetlerken koda gömülü kimlik bilgilerini alıntılanmış kanıtla birlikte CWE-798 olarak işaretler. Commit geçmişini değil mevcut kodu okur; bu yüzden geçmiş commit'ler için bir geçmiş tarayıcısını devrede tutun.

Kısacası: commit edilmiş bir gizli anahtar, sızmış bir gizli anahtardır. Bugün değiştirin, yarattığı aksamaya değiyorsa geçmişi temizleyin ve bir sonraki sızıntının herkese açık bir sayfada değil, pre-commit hook'unda başarısız olmasını sağlayın.