Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Bu makale, sürücü kullanılarak SQL Server'a go-mssqldb bağlanan Go uygulamaları için güvenlik uygulamalarını ele almaktadır. SQL enjeksiyon önleme, kimlik bilgileri yönetimi, şifreleme yapılandırması ve en az ayrıcalık ilkesini ele alır.
SQL enjeksiyonunu önleme
SQL enjeksiyonu, en yaygın veritabanı güvenlik açığıdır. Sürücü, go-mssqldb SQL kodunu veri değerlerinden ayıran parametreli sorgular sağlar. Kullanıcı tarafından sağlanan giriş için her zaman parametreler kullanın.
Parametreli sorguları kullanma
Parametreler SQL metninden ayrı gönderilir, bu nedenle kullanıcı girdisi asla SQL kodu olarak yorumlanamaz:
// CORRECT: Parameters are sent separately from the SQL text.
rows, err := db.QueryContext(ctx,
"SELECT * FROM Sales.vSalesPerson WHERE FirstName = @name AND CountryRegionName = @loc",
sql.Named("name", userName),
sql.Named("loc", userLocation))
Kullanıcı girişini SQL ile asla birleştirme
Dizi birleştirme, saldırganların keyfi SQL enjekte etmesine olanak tanır:
// WRONG: SQL injection vulnerability.
query := fmt.Sprintf("SELECT * FROM Sales.vSalesPerson WHERE FirstName = '%s'", userName)
rows, err := db.QueryContext(ctx, query) // If userName is "'; DROP TABLE HumanResources.Department;--" ...
Dinamik tablo veya sütun adları
Tablo isimleri, sütun adları veya diğer tanımlayıcılar için parametreli sorgular kullanamazsınız. Uygulamanız dinamik tanımlayıcılar gerektiriyorsa, bunları izin listesine göre doğrulayın:
// Validate against known-safe values.
var validColumns = map[string]bool{
"FirstName": true, "CountryRegionName": true, "TerritoryName": true,
}
func queryByColumn(ctx context.Context, db *sql.DB, column, value string) (*sql.Rows, error) {
if !validColumns[column] {
return nil, fmt.Errorf("invalid column name: %q", column)
}
// Safe to use column directly because it was validated against the allowlist.
query := fmt.Sprintf("SELECT * FROM Sales.vSalesPerson WHERE [%s] = @p1", column)
return db.QueryContext(ctx, query, sql.Named("p1", value))
}
Dikkat
Kullanıcıdan alınan girdiyi, köşeli ayraçlarla kaçış uygulansa bile, asla doğrudan SQL tanımlayıcılarında kullanmayın. Her zaman izin verilen değerler listesine göre doğrulama yapın.
Depolanmış prosedürler ve SQL enjeksiyonu
Kayıtlı prosedürler otomatik olarak SQL enjeksiyonunu engellemez. Prosedür, kendi içinde birleştirilmiş dizelerle EXECUTE veya sp_executesql kullanıyorsa yine de güvenlik açığına sahip olabilir. Parametrizlenmiş çağrılar kullanın:
// Parameters are passed safely to the procedure.
_, err := db.ExecContext(ctx, "dbo.SearchEmployees",
sql.Named("searchTerm", userInput))
Bağlantı dizesi gizli dizilerini yönetin
Bağlantı dizeleri şifreler, istemci sırları ve sertifika yolları içerebilir. Bunları asla kaynak kodunda depolamayın.
Ortam değişkenlerini kullanma
Bir ortam değişkeninden tam bağlantı dizesi'i okuyun:
connString := os.Getenv("MSSQL_CONNECTION_STRING")
if connString == "" {
log.Fatal("MSSQL_CONNECTION_STRING environment variable is required")
}
db, err := sql.Open("sqlserver", connString)
Bireysel sırlardan bağlantı dizileri oluşturun
Her bileşen için ayrı ortam değişkenlerinden bağlantı dizesi'i derleyin:
import (
"net/url"
"os"
)
query := url.Values{}
query.Add("database", os.Getenv("DB_NAME"))
query.Add("encrypt", "true")
password := os.Getenv("DB_PASSWORD")
u := &url.URL{
Scheme: "sqlserver",
User: url.UserPassword(os.Getenv("DB_USER"), password),
Host: os.Getenv("DB_HOST"),
RawQuery: query.Encode(),
}
db, err := sql.Open("sqlserver", u.String())
Şifreleri tamamen kaldırın
En güvenli bağlantı dizesi'in hiç şifresi yoktur. Microsoft Entra ID doğrulamasını yönetilen kimlik ile kullanın:
import _ "github.com/microsoft/go-mssqldb/azuread"
// No password, no secret. The managed identity handles authentication.
db, err := sql.Open("azuresql",
"sqlserver://<server>.database.windows.net?database=AdventureWorks2025&fedauth=ActiveDirectoryDefault&encrypt=true&TrustServerCertificate=false")
Gizli depolama seçenekleri
| Çevre | Önerilen depolama alanı | Notlar |
|---|---|---|
| Yerel kalkınma | Ortam değişkenleri veya kullanıcı sırları dosyası |
.env dosyalarını kaynak denetimine eklemeyin. |
| Azure App Service / Container Apps | Uygulama ayarları veya Key Vault referansları | Key Vault referansları, çalışma zamanında sırları ortam değişkenleri olarak enjekte eder. |
| Kubernetes | Kubernetes Secrets veya CSI sürücüsü ile Azure Key Vault | Sırlar dosya veya ortam değişkeni olarak monte edilir. |
| CI/CD boru hatları | Boru hattı sırları / GitHub Actions sırları | Azure SQL için ActiveDirectoryServicePrincipal veya ActiveDirectoryAzurePipelines kullanın. |
Important
.env, *.pfx ve *.pem öğelerini .gitignore dosyanıza ekleyin. Sırları yanlışlıkla bir depoya yerleştirmek, kimlik bilgisi sızıntılarının en yaygın kaynaklarından biridir.
Şifrelemeyi yapılandırma
Tüm uzak bağlantılar için şifreleme kullanın
Tüm uzak bağlantılar için encrypt=true ayarlayın. Sadece sunucu tarafından gerekli olan şifreleme, ortadaki düşman saldırılarına karşı savunmasızdır. İstemci şifrelemeyi zorunlu kılmalıdır. Azure SQL varsayılan olarak şifrelemeyi etkinleştirir:
sqlserver://<user>:<password>@<server>:1433?database=AdventureWorks2025&encrypt=true
En güçlü şifreleme için TDS 8.0 kullanın
TDS 8.0 (katı mod), herhangi bir TDS protokol verisi alışverişinden önce TLS el sıkışmasını gerçekleştirir ve protokol düşürme saldırılarını önler:
sqlserver://<user>:<password>@<server>:1433?database=AdventureWorks2025&encrypt=strict
TDS 8.0 için SQL Server 2022 veya Azure SQL gereklidir.
Üretimde TrustServerCertificate kullanmayın
Ayar, TrustServerCertificate=true sertifika doğrulamasını devre dışı bırakır ve bu da ortada düşman saldırılarına izin verir:
// DEVELOPMENT ONLY. Never deploy to production.
connString := "sqlserver://<user>:<password>@<server>?database=AdventureWorks2025&TrustServerCertificate=true"
Üretim için, uygun sertifika doğrulamasını yapılandırın. Şifreleme ve sertifikalar bölümünü incele.
Minimum TLS sürümü ayarlayın
Protokol düşürme saldırılarını önlemek için TLS 1.2 veya daha sonrasını uygulayın.
sqlserver://<user>:<password>@<server>:1433?database=AdventureWorks2025&encrypt=true&tlsmin=1.2
En az ayrıcalık ilkesini uygulama
Veritabanı kapsamındaki kullanıcıları kullanın
Birden çok veritabanına erişen sunucu düzeyindeki oturum açma hesapları yerine, tek bir veritabanıyla sınırlı içerilen veritabanı kullanıcıları oluşturun.
-- Create a contained database user (no server-level login needed).
CREATE USER [app_user] WITH PASSWORD = '<password>';
-- Grant only the permissions the application needs.
ALTER ROLE db_datareader ADD MEMBER [app_user];
ALTER ROLE db_datawriter ADD MEMBER [app_user];
GRANT EXECUTE ON SCHEMA::dbo TO [app_user];
Ayrı okuma ve yazma bağlantıları
Uygulamanızın farklı okuma ve yazma yolları varsa, uygun izinlere sahip ayrı veritabanı kullanıcıları oluşturun.
// Read-only queries use a restricted user.
readDB, _ := sql.Open("sqlserver",
"sqlserver://app_reader:password@<server>?database=AdventureWorks2025&ApplicationIntent=ReadOnly&encrypt=true")
// Write operations use a user with write permissions.
writeDB, _ := sql.Open("sqlserver",
"sqlserver://app_writer:password@<server>?database=AdventureWorks2025&encrypt=true")
Uygulamalarda sa veya dbo kullanmaktan kaçının
sa oturum açma hesabı ve dbo kullanıcı sınırsız erişime sahiptirler. Bağlanmış bir uygulamada sa SQL enjeksiyonu açığı varsa, saldırgan veritabanı sunucusu üzerinde tam kontrol sahibi olur.
Her Zaman Şifrelenmiş Anahtarları Koruyun
Always Encrypted kullandığınızda, sütun ana anahtarı (CMK) sütun şifreleme anahtarlarını (CEK) korur. CMK'yı uygun şekilde güvence altına alın:
| Anahtar sağlayıcı | En iyi uygulama |
|---|---|
| Yerel sertifika (PFX) | PFX dosyasını uygulama dizininin dışında sakla. Kısıtlayıcı dosya izinleri belirleyin. Şifre için bir ortam değişkeni kullanın. |
| Windows Sertifika Deposu | Hizmet hesapları için kullanın CurrentUser\My . Sertifika izinlerini kullanarak certutilayarlayın. |
| Azure Key Vault | Erişim için yönetilen kimlik kullanın. Anahtar kasası erişim politikalarını en az ayrıcalıklı olarak ayarlayın. Geçici silmeyi ve temizleme korumasını etkinleştirin. |
Anahtar sağlayıcı yapılandırması için Always Encrypted sayfasına bakınız.
Güvenli oturum açın
Bağlantı dizileri veya kimlik bilgilerini kaydetme
Bağlantı dizeleri, günlük dosyalarında yer alabilen parolalar içerebilir:
// WRONG: Logs the password.
log.Printf("Connecting to %s", connString)
// CORRECT: Log only the server and database.
log.Printf("Connecting to server=%s database=%s", serverName, dbName)
Tanı için bağlantı detaylarını kaydetmek zorundaysanız, önce bağlantı dizesi'i sansürleyin:
func redactSQLServerURL(raw string) string {
u, err := url.Parse(raw)
if err != nil {
return "<invalid connection string>"
}
if u.User != nil {
username := u.User.Username()
if username != "" {
u.User = url.UserPassword(username, "REDACTED")
}
}
q := u.Query()
for _, key := range []string{"password", "clientassertion", "systemtoken"} {
if q.Has(key) {
q.Set(key, "REDACTED")
}
}
u.RawQuery = q.Encode()
return u.String()
}
Sansürlenmiş değeri sadece kısa süreli tanı için ihtiyacınız olduğunda kaydedin. Sunucu adı, veritabanı adı ve kimlik doğrulama modunu ayrı ayrı kaydetmeyi tercih edin.
Hassas sorgu parametrelerini günlüğe kaydetmeyin
Kişisel veya hassas veri içeren parametre değerlerini kaydetmekten kaçının:
// WRONG: Logs sensitive parameter values.
log.Printf("Query: SELECT * FROM HumanResources.Employee WHERE NationalIDNumber = %s", nationalIDNumber)
// CORRECT: Log the query structure without parameter values.
log.Printf("Querying HumanResources.Employee by NationalIDNumber")
Üretim sırasında log bayraklarını dikkatlice kullanın
Sürücünün parametresi log SQL ifadeleri ve parametre değerleri verebilir:
| Flag | Risk | Üretim güvenli mi? |
|---|---|---|
1 (hatalar) |
Low | Evet |
2 (mesajlar) |
Low | Evet |
4 (satırlar) |
Medya, verileri açığa çıkarır | Hayır |
8 (SQL) |
Medium, sorguları açığa çıkarır | Conditional |
16 (parametreler) |
Yüksek değerde, parametre değerlerini açığa çıkarır | Hayır |
32 (işlemler) |
Low | Evet |
64 (hata ayıklama) |
Yüksek, protokol ayrıntılarını açığa çıkarır | Hayır |
Üretim için, log=1 (yalnızca hatalar) veya log=3 (hatalar + mesajlar) kullanın.
Güvenlik denetim listesi
| Area | Recommendation |
|---|---|
| SQL enjeksiyonu | Tüm kullanıcı girdileri için parametreli sorgular kullanın. Dinamik tanımlayıcıları izin listesine göre doğrulayın. |
| Credentials | Mümkün olduğunda Microsoft Entra yönetilen kimliğini kullanın. Kaynak kodunda asla şifre kodlamayın. |
| Encryption | Tüm üretim bağlantıları için encrypt=true veya encrypt=strict olarak ayarlayın.
tlsmin=1.2ayarlayın. |
| Sertifikalar | Üretimde kullanmayın TrustServerCertificate=true . Sunucu sertifikalarını doğrulayın. |
| En az ayrıcalık | Sadece gerekli izinlere sahip uygulama özel veritabanı kullanıcıları oluşturun. |
| Secrets | Bağlantı dizelerini ortam değişkenlerinde, Key Vault'ta veya platform gizli depolarında sakla. |
| Logging | Bağlantı dizilerini, şifreleri veya hassas parametre değerlerini kaydetmeyin. |
| Kaynak denetimi |
.gitignore öğesine .env, *.pfx ve *.pem ekleyin. |