Skip to main content
Payven API’lerine erişim OAuth 2.0 Client Credentials akışı ile sağlanır: client_id + client_secret → access token. client_secret, organizasyonunuz adına işlem yapma yetkisidir; sızdığında saldırganın elinde sizin adınıza ödeme oluşturma kapısı olur. Aşağıdaki kurallara uymak sızıntı riskini ve sızıntı sonrası etkiyi minimuma indirir. Auth akışının tamamı için: Kimlik Doğrulama.

Kuralname

Asla kaynak kodda tutmayınclient_secret’ı .env, secret manager veya environment variable olarak yönetin.
Asla istemcide tutmayın — tarayıcı, mobil uygulama veya desktop client’a göndermeyin. Token alma sunucu tarafında yapılmalı; istemciye yalnızca kısa ömürlü access token gider.
Asla loglara yazmayın — log framework’ünüzde request/response loglama açıksa Authorization header’ı ile client_secret body alanını maskeleyin.
Asla destek ekibine paylaşmayın — Payven destek ekibi sizden client_secret istemez.
Sandbox ve production’ı ayırın — farklı client’lar, farklı secret store’lar.
IP whitelist tanımlayın — production client’ları için zorunlu kabul edin (Identity tarafında enforce edilir).
Düzenli rotasyon — minimum 6 ayda bir, sızıntı şüphesinde anında.
Audit logları izleyin — konsoldaki API kayıtları ekranından beklenmeyen istek varsa hemen tepki verin.
Token cache uygulayın — her istek öncesi yeni token almayın; access token süresi dolmadan (60sn margin) refresh edin.

Saklama önerileri

OrtamÖnerilen secret store
AWSAWS Secrets Manager veya Parameter Store (SecureString)
AzureAzure Key Vault
GCPSecret Manager
KubernetesExternal Secrets Operator + cloud KMS
On-premiseHashiCorp Vault
Geliştirme.env (commit edilmez) + direnv veya dotenv

Çoklu client stratejisi

Tek bir client’la çalışmak yerine işlevlere göre ayrılmış client’lar oluşturmanız önerilir:
ClientKullanım
payments-prodSadece ödeme alma servisinde kullanılan production client’ı
reporting-prodSadece raporlama job’larında kullanılan, daha kısıtlı IP whitelist’li client
dev-team-sandboxGeliştirici ekibinin paylaştığı sandbox client’ı
Avantajlar: Bir client_secret sızdığında etki alanı sınırlı kalır, audit’lerde hangi servisin ne yaptığını ayırt etmek kolaylaşır.

Rotasyon prosedürü

Sıfır kesinti ile rotasyon:
1

Yeni client veya secret üretin

Konsol → API Anahtarları → Yeni Client Oluştur (veya mevcut client için Secret Rotate). Mevcut secret’ı silmeyin — Identity, geçiş süresince eski ve yeni secret’ı geçici olarak birlikte kabul eder.
2

Yeni secret'ı secret store'a yazın

Production secret manager’ında yeni değeri kaydedin.
3

Servisinizi yeniden deploy edin

Yeni secret ile başlayan servis pod/instance’ları çalışmaya başlasın. Eski olanlar hâlâ eski secret’la çalışıyor — geçiş penceresinde ikisi de geçerli.
4

Audit log'u izleyin

Konsol → API Kayıtları ekranında eski secret’a gelen istek olup olmadığını izleyin. Trafik sıfıra inene dek bekleyin.
5

Eski secret'ı pasife alın

Trafik tamamen kesildiğinde eski secret’ı revoke edin.

Sızıntı şüphesinde acil müdahale

client_secret’ınızın sızdığını düşündüğünüz an aşağıdaki adımları paralel uygulayın:
1

Secret'ı hemen revoke edin

Konsoldan client’ı pasife çekin veya secret’ı rotate edin. Süreç anlıktır.
2

Yeni secret üretip servisinizi rotasyona alın

Yukarıdaki adımları hızlandırılmış şekilde uygulayın.
3

Audit log incelemesi

Sızıntı penceresinde gerçekleşen tüm işlemleri konsol → API Kayıtları’ndan ekstrakt edin.
4

Destek ekibine bildirin

Destek talebi açın — etki analizi konusunda yardım alın.

Loglama kuralı

Request/response loglaması yapan kütüphaneler için header maskeleme örneği:
public class SensitiveHeaderRedactor : DelegatingHandler
{
    private static readonly string[] SensitiveHeaders =
    {
        "Authorization"
    };

    protected override async Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken ct)
    {
        var clone = new HttpRequestMessage(request.Method, request.RequestUri);
        foreach (var header in request.Headers)
        {
            var value = SensitiveHeaders.Contains(header.Key, StringComparer.OrdinalIgnoreCase)
                ? new[] { "***REDACTED***" }
                : header.Value.ToArray();
            clone.Headers.Add(header.Key, value);
        }
        // logger logs `clone`, sends `request`
        return await base.SendAsync(request, ct);
    }
}