Connection String Güvenliği — appsettings.json'da Ne Saklanmamalı?
Connection String Güvenliği — appsettings.json'da Ne Saklanmamalı?
En Yaygın Güvenlik Hatası
GitHub'da binlerce public repository'de şu satır bulunabilir:
{
"ConnectionStrings": {
"DefaultConnection": "Server=prod-db.company.com;Database=FinanceDB;User Id=sa;Password=Admin123!;"
}
}
Production sunucu adresi. Veritabanı adı. sa kullanıcısı. Açık metin şifre. Hepsi bir arada. Hepsi Git geçmişinde sonsuza kadar.
Bu bir hipotez değil. Her yıl yüzlerce şirket bu hatanın bedelini öder — veri ihlali, düzenleyici ceza, itibar kaybı. BDDK, SPK gibi kurumların denetimlerinde bu madde neredeyse her zaman işaretlenir.
Bu yazı, connection string'leri ve diğer hassas verileri üretim ortamında nasıl güvenli yönetmeniz gerektiğini adım adım gösteriyor.
Neyi Asla appsettings.json'a Yazmamalısınız?
// ❌ Bunların hiçbiri appsettings.json'da olmamalı
{
"ConnectionStrings": {
"DefaultConnection": "Server=...;Password=GizliSifre123;"
},
"ExternalApis": {
"PaymentGatewayApiKey": "pk_live_abcdef123456",
"SmsProviderSecret": "sms_secret_xyz"
},
"Jwt": {
"SecretKey": "SuperGizliJwtAnahtarim"
},
"Smtp": {
"Password": "EmailSifresi"
},
"RabbitMq": {
"Password": "MqSifresi"
}
}
Kural basittir: Herhangi bir değer ele geçirildiğinde zarar verebiliyorsa — şifre, API key, secret, token, sertifika — o değer appsettings.json'a ait değildir.
appsettings.json'a yazılabilecekler:
// ✅ Bunlar güvenli — hassas veri içermiyor
{
"ConnectionStrings": {
"DefaultConnection": "Server=prod-db.company.com;Database=FinanceDB;"
},
"Logging": {
"LogLevel": { "Default": "Information" }
},
"AppSettings": {
"MaxPageSize": 100,
"DefaultCurrency": "TRY",
"FeatureFlags": {
"NewDashboard": true
}
}
}
Yöntem 1 — Environment Variables (Her Ortamda Çalışır)
Environment variable'lar, .NET'in konfigürasyon sistemi tarafından otomatik olarak okunur. Platform bağımsızdır, kurulum gerektirmez, her CI/CD pipeline'ında desteklenir.
.NET'in konfigürasyon hiyerarşisi:
appsettings.json
↓ (override)
appsettings.{Environment}.json
↓ (override)
Environment Variables ← Hassas veriler buraya
↓ (override)
Command-line arguments
Connection string'i environment variable olarak tanımlama:
.NET, iç içe konfigürasyon key'lerini __ (çift alt çizgi) ile ayırır:
# Linux / macOS
export ConnectionStrings__DefaultConnection="Server=prod-db;Database=FinanceDB;User Id=appuser;Password=GizliSifre;"
export Jwt__SecretKey="base64-encoded-256-bit-secret"
export ExternalApis__PaymentGatewayApiKey="pk_live_abcdef"
# Windows (PowerShell)
$env:ConnectionStrings__DefaultConnection = "Server=prod-db;Database=FinanceDB;User Id=appuser;Password=GizliSifre;"
$env:Jwt__SecretKey = "base64-encoded-256-bit-secret"
# Windows (cmd)
setx ConnectionStrings__DefaultConnection "Server=prod-db;Database=FinanceDB;User Id=appuser;Password=GizliSifre;"
IIS Application Pool'da environment variable:
IIS üzerinde çalışan .NET uygulamaları için en temiz yöntem, environment variable'ı doğrudan Application Pool seviyesinde tanımlamaktır:
<!-- applicationHost.config veya web.config -->
<system.webServer>
<aspNetCore processPath="dotnet" arguments=".\MyApp.dll">
<environmentVariables>
<environmentVariable name="ConnectionStrings__DefaultConnection"
value="Server=prod-db;Database=FinanceDB;User Id=appuser;Password=GizliSifre;" />
<environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Production" />
</environmentVariables>
</aspNetCore>
</system.webServer>
Ya da IIS Manager üzerinden:
Application Pools → Advanced Settings → Environment Variables
Program.cs'de özel environment variable dosyası yüklemek:
// .env dosyası okuma (development kolaylığı için)
builder.Configuration
.AddJsonFile("appsettings.json", optional: false)
.AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables() // Environment variable'ları yükle
.AddCommandLine(args); // CLI argümanlarını yükle
Yöntem 2 — .NET Secret Manager (Sadece Development)
Secret Manager, development ortamında hassas verileri proje klasörü dışında saklar. Git'e asla girmez.
Kurulum:
# Projeyi secret yönetimine hazırla
dotnet user-secrets init
# Secret ekle
dotnet user-secrets set "ConnectionStrings:DefaultConnection" "Server=dev-db;Database=DevDB;User Id=devuser;Password=DevPass123;"
dotnet user-secrets set "Jwt:SecretKey" "dev-secret-key-256-bit"
dotnet user-secrets set "ExternalApis:PaymentGatewayApiKey" "pk_test_devkey"
Veriler şu konuma kaydedilir — proje dizininin tamamen dışında:
Windows: %APPDATA%\Microsoft\UserSecrets\{guid}\secrets.json
Linux/macOS: ~/.microsoft/usersecrets/{guid}/secrets.json
Program.cs'de otomatik yükleme:
// Development ortamında Secret Manager otomatik yüklenir
if (builder.Environment.IsDevelopment())
{
builder.Configuration.AddUserSecrets<Program>();
}
Mevcut secret'ları listeleme ve silme:
# Tüm secret'ları listele
dotnet user-secrets list
# Belirli bir secret'ı sil
dotnet user-secrets remove "ConnectionStrings:DefaultConnection"
# Tüm secret'ları temizle
dotnet user-secrets clear
Önemli: Secret Manager sadece development içindir. Production'da kullanmayın.
Yöntem 3 — Azure Key Vault (Production İçin En İyi Yöntem)
Azure Key Vault, secret'ları merkezi ve güvenli bir şekilde saklar. Erişim loglanır, versiyonlanır, rotasyon desteklenir.
NuGet paketleri:
dotnet add package Azure.Extensions.AspNetCore.Configuration.Secrets
dotnet add package Azure.Identity
Program.cs entegrasyonu:
using Azure.Identity;
var builder = WebApplication.CreateBuilder(args);
// Production'da Key Vault'u yükle
if (builder.Environment.IsProduction())
{
var keyVaultUri = new Uri($"https://{builder.Configuration["KeyVaultName"]}.vault.azure.net/");
builder.Configuration.AddAzureKeyVault(
keyVaultUri,
new DefaultAzureCredential()); // Managed Identity kullanır
}
Key Vault'a secret ekleme:
# Azure CLI ile
az keyvault secret set \
--vault-name "myapp-keyvault" \
--name "ConnectionStrings--DefaultConnection" \
--value "Server=prod-db;Database=FinanceDB;User Id=appuser;Password=GizliSifre;"
az keyvault secret set \
--vault-name "myapp-keyvault" \
--name "Jwt--SecretKey" \
--value "production-256-bit-secret"
Not: Key Vault'ta iç içe key'ler için : yerine -- kullanılır.
Managed Identity ile şifresiz erişim:
Managed Identity, uygulamanızın Azure'da kimlik bilgisi saklamadan Key Vault'a erişmesini sağlar. Connection string'in şifresini başka bir yerde saklamak zorunda kalmazsınız.
# App Service için Managed Identity etkinleştir
az webapp identity assign --name "myapp" --resource-group "mygroup"
# Key Vault'a erişim izni ver
az keyvault set-policy \
--name "myapp-keyvault" \
--object-id {managed-identity-object-id} \
--secret-permissions get list
Yöntem 4 — Şifreli Konfigürasyon (Azure Olmayan Ortamlar İçin)
Azure kullanmıyor, on-premise IIS üzerinde çalışıyorsanız — ki bu Türkiye'deki finansal projelerin önemli bir kısmı — konfigürasyon şifreleme geçerli bir alternatiftir.
Protected Configuration ile web.config şifreleme:
# connectionStrings bölümünü şifrele
aspnet_regiis -pe "connectionStrings" -app "/MyApp" -prov "DataProtectionConfigurationProvider"
# Sonuç — artık şifreli
# <connectionStrings configProtectionProvider="DataProtectionConfigurationProvider">
# <EncryptedData>...</EncryptedData>
# </connectionStrings>
# Şifreyi çöz (bakım için)
aspnet_regiis -pd "connectionStrings" -app "/MyApp"
.NET 8'de Data Protection API ile özel şifreleme:
// Program.cs
builder.Services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"C:\SecureKeys\"))
.ProtectKeysWithDpapi() // Windows DPAPI ile koru
.SetApplicationName("MyFinancialApp");
// Şifreleme servisi
public class SecretProtectionService
{
private readonly IDataProtector _protector;
public SecretProtectionService(IDataProtectionProvider provider)
{
_protector = provider.CreateProtector("ConnectionStrings");
}
public string Encrypt(string plainText) => _protector.Protect(plainText);
public string Decrypt(string cipherText) => _protector.Unprotect(cipherText);
}
Yöntem 5 — appsettings.json'ı .gitignore'a Almak (Son Çare Değil, Ek Önlem)
Bu tek başına yeterli değildir — ama ek bir güvenlik katmanı olarak uygulanmalıdır.
.gitignore:
# Hassas konfigürasyon dosyalarını git'ten dışla
appsettings.Production.json
appsettings.Staging.json
secrets.json
*.pfx
*.p12
*.key
Ancak dikkat: Eğer bu dosyalar daha önce commit edilmişse, .gitignore'a eklemek geçmiş geçmişi temizlemez.
Git geçmişinden hassas veri temizleme:
# git-filter-repo ile (önerilen yöntem)
pip install git-filter-repo
git filter-repo --path appsettings.Production.json --invert-paths
# Tüm ekip force push yapmalı
git push --force --all
Üretim Ortamı İçin Kontrol Listesi
✅ appsettings.json'da şifre, API key, secret yok
✅ appsettings.*.json dosyaları .gitignore'a eklendi
✅ Git geçmişi tarandı — hassas veri kalmadı
✅ Development'ta Secret Manager kullanılıyor
✅ Production'da environment variable veya Key Vault kullanılıyor
✅ IIS Application Pool kimliği sa değil, sınırlı yetkili bir hesap
✅ Connection string'de minimum yetki prensibi uygulandı
✅ Managed Identity veya servis hesabı rotasyonu planlandı
✅ Secret erişim logları izleniyor
Veritabanı Kullanıcısı — Minimum Yetki Prensibi
Connection string güvenliği yalnızca şifreyi gizlemekle bitmez. Veritabanı kullanıcısı da minimum yetkiyle tanımlanmalıdır.
-- ❌ sa veya db_owner kullanmayın
-- "Server=prod;Database=FinanceDB;User Id=sa;Password=...;"
-- ✅ Uygulama için özel, kısıtlı kullanıcı oluşturun
CREATE LOGIN appuser WITH PASSWORD = 'GucluBirSifre123!';
CREATE USER appuser FOR LOGIN appuser;
-- Sadece ihtiyaç duyulan yetkiler
GRANT SELECT, INSERT, UPDATE, DELETE ON SCHEMA::dbo TO appuser;
-- Migration için ayrı kullanıcı (CI/CD pipeline'ında)
CREATE LOGIN migrationuser WITH PASSWORD = 'MigrationSifresi!';
CREATE USER migrationuser FOR LOGIN migrationuser;
GRANT ALTER, CREATE TABLE, CREATE INDEX ON DATABASE::FinanceDB TO migrationuser;
Özet — Hangi Yöntemi Ne Zaman Kullanmalısınız?
| Ortam | Önerilen Yöntem |
|---|---|
| Local Development | .NET Secret Manager |
| CI/CD Pipeline | Environment Variables (GitHub Secrets, Azure DevOps Variables) |
| Azure Production | Azure Key Vault + Managed Identity |
| On-Premise IIS Production | Environment Variables veya Şifreli Konfigürasyon |
| Docker | Environment Variables veya Docker Secrets |
Temel Çıkarımlar
- appsettings.json bir konfigürasyon dosyasıdır, bir secret deposu değildir
- Git geçmişine giren bir şifre değiştirilmeli, gizlenmez — geçmiş temizlenmeli
- Development için Secret Manager, production için environment variable veya Key Vault
- Veritabanı kullanıcısı sa olmamalı — minimum yetki prensibi her zaman geçerlidir
- Azure kullanıyorsanız Managed Identity ile credential saklamaktan tamamen kurtulabilirsiniz
- Secret rotasyonu bir plan değil, bir rutin olmalıdır
Şifreyi gizlemek güvenlik değildir. Şifreye erişimi kontrol etmek, loglamak ve rotasyona tabi tutmak güvenliktir.