Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Tento článek se zabývá bezpečnostními postupy pro aplikace Go, které se připojují k SQL Server pomocí ovladačego-mssqldb. Zabývá se prevencí injekcí SQL, správou přihlašovacích údajů, konfigurací šifrování a principem nejmenších oprávnění.
Prevence injektáže SQL
SQL injection je nejčastější zranitelnost v oblasti bezpečnosti databází. Ovladač go-mssqldb poskytuje parametrizované dotazy, které oddělují SQL kód od datových hodnot. Vždy používejte parametry pro vstupy zadané uživatelem.
Použití parametrizovaných dotazů
Parametry jsou odesílány odděleně od SQL textu, takže uživatelský vstup nelze nikdy interpretovat jako SQL kód:
// 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))
Nikdy nespojujte uživatelský vstup do SQL
Konkatenace řetězců umožňuje útočníkům vkládat libovolné SQL:
// 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;--" ...
Názvy dynamických tabulek nebo sloupců
Parametrizované dotazy nelze použít pro názvy tabulek, sloupců nebo jiné identifikátory. Pokud vaše aplikace vyžaduje dynamické identifikátory, ověřte je podle seznamu povolených:
// 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))
}
Caution
Nikdy neukládejte uživatelem zadaný vstup přímo do SQL identifikátorů, ani při úniku závorek. Vždy ověřujte podle seznamu povolených hodnot.
Uložené procedury a SQL injekce
Uložené procedury automaticky nezabrání SQL injekci. Pokud postup interně používá EXECUTE nebo sp_executesql se spojenými řetězci, může být stále zranitelný. Používejte parametrizované hovory:
// Parameters are passed safely to the procedure.
_, err := db.ExecContext(ctx, "dbo.SearchEmployees",
sql.Named("searchTerm", userInput))
Spravovat tajné údaje připojovacího řetězce
Spojovací řetězce mohou obsahovat hesla, klientská tajemství a cesty k certifikátům. Nikdy je neukládejte do zdrojového kódu.
Používání proměnných prostředí
Přečtěte celý připojovací řetězec z proměnné prostředí:
connString := os.Getenv("MSSQL_CONNECTION_STRING")
if connString == "" {
log.Fatal("MSSQL_CONNECTION_STRING environment variable is required")
}
db, err := sql.Open("sqlserver", connString)
Sestavte spojovací řetězce z jednotlivých tajemství
Sestavte připojovací řetězec ze samostatných proměnných prostředí pro každou součást:
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())
Úplně odstraňte hesla
Nejbezpečnější připojovací řetězec nemá vůbec žádné heslo. Použijte autentizaci Microsoft Entra ID s řízenou identitou:
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")
Možnosti tajného úložiště
| Životní prostředí | Doporučené úložiště | Poznámky |
|---|---|---|
| Místní rozvoj | Proměnné prostředí nebo soubor uživatelských tajemství | Neodhlašujte .env soubory do správy zdrojového kódu. |
| Azure App Service / Container Apps | Nastavení aplikace nebo odkazy na Key Vault | Odkazy na Key Vault vkládají tajné klíče do proměnných prostředí za běhu. |
| Kubernetes | Tajné klíče Kubernetes nebo Azure Key Vault s ovladačem CSI | Tajemství jsou uložena jako soubory nebo proměnné prostředí. |
| Kanály CI/CD | Tajné klíče pipeline / tajné klíče GitHub Actions | Use ActiveDirectoryServicePrincipal or ActiveDirectoryAzurePipelines for Azure SQL. |
Důležité
Přidejte .env, *.pfx a *.pem do souboru .gitignore. Náhodné uložení tajemství do úložiště je jedním z nejčastějších zdrojů úniku přihlašovacích údajů.
Konfigurace šifrování
Používejte šifrování pro všechna vzdálená připojení
Nastavte encrypt=true pro všechna vzdálená připojení. Šifrování, které je potřeba pouze serveru, je zranitelné vůči útokům typu útočník uprostřed (adversary-in-the-middle). Klient musí vynucovat šifrování. Azure SQL umožňuje šifrování ve výchozím nastavení:
sqlserver://<user>:<password>@<server>:1433?database=AdventureWorks2025&encrypt=true
Pro nejsilnější šifrování použijte TDS 8.0
TDS 8.0 (přísný režim) provádí TLS handshake před výměnou jakýchkoli dat protokolu TDS, čímž zabraňuje útokům na snížení protokolu:
sqlserver://<user>:<password>@<server>:1433?database=AdventureWorks2025&encrypt=strict
TDS 8.0 vyžaduje SQL Server 2022 nebo Azure SQL.
Nepoužívej TrustServerCertificate v produkci
Nastavení TrustServerCertificate=true deaktivuje validaci certifikátů, což umožňuje útoky útočníka uprostřed (adversary-in-the-middle):
// DEVELOPMENT ONLY. Never deploy to production.
connString := "sqlserver://<user>:<password>@<server>?database=AdventureWorks2025&TrustServerCertificate=true"
Pro produkci nastavte správnou validaci certifikátů. Viz Šifrování a certifikáty.
Nastavte minimální verzi TLS
Vynuťte TLS 1.2 nebo novější, abyste zabránili útokům na degradaci protokolu.
sqlserver://<user>:<password>@<server>:1433?database=AdventureWorks2025&encrypt=true&tlsmin=1.2
Použití principu nejnižšího oprávnění
Používejte uživatele s databázovým zaměřením
Vytvářejte uzavřené databázové uživatele zaměřené na jednu databázi místo serverových přihlašovacích údajů, které přistupují k více databázím.
-- 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];
Samostatná čtecí a zápisná spojení
Pokud má vaše aplikace odlišné cesty pro čtení a zápis, vytvořte samostatné databázové uživatele s odpovídajícími oprávněními.
// 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")
Vyhněte se použití SA nebo DBO v aplikacích
sa přihlášení a dbo uživatel mají neomezený přístup. Pokud má aplikace připojená k AS sa zranitelnost proti SQL injekci, útočník získává plnou kontrolu nad databázovým serverem.
Chraňte klíče funkce Always Encrypted
Když používáte Always Encrypted, hlavní klíč sloupců (CMK) chrání šifrovací klíče sloupců (CEK). Zabezpečte CMK odpovídajícím způsobem:
| Poskytovatel klíčů | Nejlepší praxe |
|---|---|
| Místní certifikát (PFX) | Uložit soubor PFX mimo adresář aplikací. Nastavte omezující oprávnění souboru. Použijte proměnnou prostředí pro heslo. |
| úložiště certifikátů Windows | Použití CurrentUser\My pro servisní účty. Nastavte oprávnění certifikátu pomocí certutil. |
| Azure Key Vault | Používejte spravovanou identitu pro přístup. Nastavte zásady přístupu k trezoru klíčů s nejmenšími oprávněními. Povolte obnovitelné odstranění a ochranu před trvalým odstraněním. |
Pro konfiguraci poskytovatele klíčů viz Always Encrypted.
Přihlaste se bezpečně
Nelogujte spojovací řetězce ani přihlašovací údaje
Spojovací řetězce mohou obsahovat hesla, která se nakonec objeví v logovacích souborech:
// 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)
Pokud musíte zaznamenat detaily připojení pro diagnostiku, nejprve redigujte připojovací řetězec:
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()
}
Zaznamenávejte cenzurovanou hodnotu jen tehdy, když ji potřebujete pro krátkodobou diagnostiku. Preferujte samostatné zaznamenávání jména serveru, názvu databáze a autentizačního režimu.
Nezaznamenávejte citlivé parametry dotazu
Vyhněte se zaznamenávání hodnot parametrů, které obsahují osobní nebo citlivá data:
// 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")
Používejte logové vlajky při výrobě opatrně
Parametr ovladače může vypisovat log SQL příkazy a hodnoty parametrů:
| Flag | Riziko | Produkční bezpečí? |
|---|---|---|
1 (chyby) |
Nízká úroveň | Ano |
2 (zprávy) |
Nízká úroveň | Ano |
4 (řady) |
Střední, zpřístupňuje data | Ne |
8 (SQL) |
Medium, zpřístupňuje dotazy | Podmíněný |
16 (params) |
Vysoká, zobrazuje hodnoty parametrů | Ne |
32 (transakce) |
Nízká úroveň | Ano |
64 (ladění) |
Vysoko, odhaluje detaily protokolu | Ne |
Pro produkci použijte log=1 (pouze chyby) nebo log=3 (chyby + zprávy).
Kontrolní seznam zabezpečení
| Area | Recommendation |
|---|---|
| Injektáž SQL | Pro veškerý uživatelský vstup používejte parametrizované dotazy. Ověřte dynamické identifikátory vůči seznamu povolených. |
| Credentials | Pokud je to možné, používejte spravovanou identitu Microsoft Entra. Nikdy nevkládejte hesla napevno do zdrojového kódu. |
| Encryption | Nastavte encrypt=true nebo encrypt=strict pro všechny produkční spojení. Nastavte tlsmin=1.2. |
| Certifikáty | Nepoužívejte TrustServerCertificate=true v produkčním prostředí. Ověřte serverové certifikáty. |
| Nejnižší oprávnění | Vytvořte uživatele databáze specifické pro aplikaci pouze s požadovanými oprávněními. |
| Secrets | Ukládejte spojovací řetězce do proměnných prostředí, do Key Vaultu nebo do úložišť tajných údajů platformy. |
| Logging | Nezaznamenávejte spojovací řetězce, hesla ani hodnoty citlivých parametrů. |
| Správa zdrojového kódu | Přidejte .env, *.pfx, a *.pem k .gitignore. |