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.
Chraňte své mssql-python aplikace dodržováním těchto osvědčených postupů pro autentizaci, parametrizované dotazy a ochranu dat.
Začněte s autentizací bez hesla, kdykoli můžete. Lokální .env soubory a SQL hesla považujte za dočasné pomůcky pro vývoj a přesouvejte tajemství do spravovaných identit nebo tajného úložiště dříve, než kód dorazí do sdíleného prostředí.
Zabezpečení ověřování
Použijte autentizaci Microsoft Entra místo SQL autentizace
Autentizace Microsoft Entra eliminuje uložená hesla a podporuje spravované identity. Preferuji to před SQL autentizací ve všech prostředích.
Pro pracovní zátěže hostované v Azure použijte managed identity s ActiveDirectoryMSI. Nepotřebuje žádná uložená tajemství a propojuje se bez nutnosti procházet řetězcem oprávnění:
import mssql_python
def connect_with_managed_identity():
return mssql_python.connect(
"Server=<server>.database.windows.net;"
"Database=<database>;"
"Authentication=ActiveDirectoryMSI;"
"Encrypt=yes;"
)
Pro lokální vývoj použijte ActiveDirectoryDefault, který automaticky zachytí vaše Azure CLI nebo jiné vývojářské přihlašovací údaje. Vyhněte se tomu v produkci, protože DefaultAzureCredential při prvním připojení zkouší každého poskytovatele přihlašovacích údajů v pořadí, což přidává latenci, kterou produkční zátěže nepotřebují:
import mssql_python
def connect_with_default_credential():
return mssql_python.connect(
"Server=<server>.database.windows.net;"
"Database=<database>;"
"Authentication=ActiveDirectoryDefault;"
"Encrypt=yes;"
)
Vyhněte se: SQL autentizace ukládá přihlašovací údaje v kódu/konfiguraci a je zranitelná vůči únikům informací.
conn = mssql_python.connect("Server=...;UID=user;PWD=password")
Nikdy nenatvrdo kódujte přihlašovací údaje
Proměnné prostředí používejte pouze pro lokální vývoj. Ve sdílených prostředích preferuji autentizaci bez hesla. Pokud se nelze vyhnout staršímu způsobu ověřování SQL, načítejte tajný klíč za běhu z úložiště tajných klíčů, místo abyste celý připojovací řetězec ukládali do správy zdrojového kódu.
Následující přístup má napevno zakódované přihlašovací údaje a nikdy by se neměl používat:
conn_str = "Server=<server>;UID=<login>;PWD=<password>"
Pro lokální vývoj načítejte pověřovací údaje z proměnných prostředí:
import os
conn_str = (
f"Server={os.environ['DB_SERVER']};"
f"Database={os.environ['DB_NAME']};"
)
Pro sdílená prostředí, která stále tajemství potřebují, jej získejte za běhu z Azure Key Vault:
from azure.keyvault.secrets import SecretClient
from azure.identity import DefaultAzureCredential
def get_connection_string():
credential = DefaultAzureCredential()
secret_client = SecretClient(
vault_url="https://myvault.vault.azure.net/",
credential=credential
)
return secret_client.get_secret("db-connection-string").value
Prevence injekcí SQL
Vždy používejte parametrizované dotazy
Parametrizované dotazy zabraňují SQL injekci tím, že oddělují uživatelský vstup od struktury dotazu. Vždy parametrizujte uživatelský vstup.
Následující dotaz ve formátu řetězce je zranitelný vůči SQL injection. Nikdy nevytvářejte dotazy tímto způsobem:
user_input = "'; DROP TABLE Person.Person; --"
cursor.execute(f"SELECT * FROM Person.Person WHERE FirstName = '{user_input}'")
Následující parametrizovaný dotaz je bezpečný, protože ovladač odesílá hodnotu odděleně od textu dotazu:
user_input = "'; DROP TABLE Person.Person; --"
cursor.execute(
"SELECT * FROM Person.Person WHERE FirstName = %(name)s",
{"name": user_input}
)
Parametrizujte všechny komponenty dotazu
Nemůžete přímo parametrizovat názvy tabulek a sloupců. Interpolace z uživatelského vstupu činí vaši aplikaci zranitelnou vůči SQL injection:
table = user_input
cursor.execute(f"SELECT * FROM {table}")
Místo toho ověřte dynamické identifikátory vůči seznamu povolených hodnot a parametrizujte zbývající hodnoty.
ALLOWED_TABLES = {"Person.Person", "Production.Product", "Sales.SalesOrderHeader"}
def query_table(cursor, table_name: str, conditions: dict):
"""Query with validated table name."""
if table_name not in ALLOWED_TABLES:
raise ValueError(f"Invalid table: {table_name}")
# Table name is safe, parameters are parameterized
where_clauses = [f"{k} = %({k})s" for k in conditions.keys()]
query = f"SELECT * FROM {table_name} WHERE {' AND '.join(where_clauses)}"
cursor.execute(query, conditions)
return cursor.fetchall()
Validace a sanitace vstupu
Když vytváříte dynamické SQL s identifikátory, ověřte každou hodnotu podle přísného vzoru před použitím:
import re
def validate_identifier(value: str) -> bool:
"""Validate SQL identifier (table/column name)."""
# Only allow alphanumeric and underscore
return bool(re.match(r'^[a-zA-Z_][a-zA-Z0-9_]*$', value))
def safe_order_by(cursor, table: str, order_column: str, direction: str):
"""Order by with validation."""
if not validate_identifier(order_column):
raise ValueError(f"Invalid column name: {order_column}")
if direction.upper() not in ("ASC", "DESC"):
raise ValueError(f"Invalid direction: {direction}")
cursor.execute(f"""
SELECT * FROM {table}
ORDER BY {order_column} {direction.upper()}
""")
Používejte uložené procedury pro složité operace
Uložené procedury snižují plochu SQL vystavenou aplikačnímu kódu:
employee_id = 5
cursor.execute("""
EXECUTE dbo.uspGetEmployeeManagers @BusinessEntityID = %(id)s
""", {"id": employee_id})
Zabezpečení připojení
Vyžaduje šifrování
Vždy šifrujte spojení. Azure SQL vynucuje šifrování ve výchozím nastavení. Pro on-premises SQL Server nastavte Encrypt=yes explicitně:
conn = mssql_python.connect(
"Server=<server>.database.windows.net;"
"Database=<database>;"
"Encrypt=yes;"
"TrustServerCertificate=no"
)
Pro nejvyšší bezpečnost použijte přísný režim TDS 8.0
TDS 8.0 poskytuje:
- TLS 1.3 od začátku připojení
- Vyžadováno ověření certifikátu
- Žádná záložní možnost ke starším protokolům
conn = mssql_python.connect(
"Server=tcp:<server>.database.windows.net,1433;"
"Database=<database>;"
"Encrypt=strict"
)
Validovat serverové certifikáty
Vždy v produkčním prostředí ověřujte certifikát serveru, abyste zabránili útokům typu man-in-the-middle. Nenastavujte TrustServerCertificate=yes, protože to obchází validaci. Místo toho nastavte TrustServerCertificate=no na validaci proti CA certifikátům a nastavte HostNameInCertificate na ověření názvu hostitele:
conn = mssql_python.connect(
"Server=<server>;"
"Database=<database>;"
"Encrypt=yes;"
"TrustServerCertificate=no;"
"HostNameInCertificate=<server>.domain.com"
)
Ochrana dat
Chraňte citlivá data na úrovni serveru
Always Encrypted momentálně není konfigurovatelný pomocí klíčových slov mssql-python připojovací řetězec. Pokud potřebujete Always Encrypted, použijte pyodbc s ODBC ovladačem pro SQL Server, který to podporuje. I když neposkytují stejnou úroveň ochrany, můžete použít funkce SQL Server, jako je dynamické maskování dat a bezpečnost na úrovni řádků, k ochraně citlivých sloupců.
employee_id = 1
cursor.execute("""
SELECT NationalIDNumber, LoginID
FROM HumanResources.Employee
WHERE BusinessEntityID = %(id)s
""", {"id": employee_id})
row = cursor.fetchone()
Ochrana dat během přenosů
- Použití
Encrypt=yesv spojovacích řetězcích. - Pro připojení na místě používejte VPN nebo privátní endpointy.
- Use Azure Private Link for Azure SQL.
Princip nejmenšího oprávnění
Používejte minimální databázová oprávnění
Aplikační účty by měly mít minimální oprávnění. Nepoužívejte sadb_owner ani pro připojení k aplikacím.
-
Pouze pro čtení:
GRANT SELECT ON SCHEMA::dbo TO ReportingApp; -
Přístup ke konkrétním stolům:
GRANT SELECT, INSERT, UPDATE ON Orders TO OrderProcessor; -
Pouze uložené procedury:
GRANT EXECUTE ON ProcessOrder TO OrderProcessor;
Používejte různé účty pro různé operace
Každou úroveň oprávnění podpořte vlastní identitou, aby cesta pro čtení nemohla provádět zápisy. Tento příklad používá dvě uživatelem přiřazené spravované identity, jednu s povoleným přístupem pouze pro čtení a jednu s povoleným zápisem, vybrané podle ID klienta:
readonly_client_id = os.environ["READONLY_IDENTITY_CLIENT_ID"]
readwrite_client_id = os.environ["READWRITE_IDENTITY_CLIENT_ID"]
def get_readonly_connection():
"""Connection for read-only operations."""
return mssql_python.connect(
f"Server={server};Database={db};"
f"Authentication=ActiveDirectoryMSI;UID={readonly_client_id};"
f"Encrypt=yes;ApplicationIntent=ReadOnly;"
)
def get_readwrite_connection():
"""Connection for write operations."""
return mssql_python.connect(
f"Server={server};Database={db};"
f"Authentication=ActiveDirectoryMSI;UID={readwrite_client_id};"
f"Encrypt=yes;"
)
Uchovávejte tajné klíče role aplikace mimo systém správy zdrojového kódu
Hesla pro role aplikací jsou stále tajemstvím. Ukládejte je do trezoru nebo do prostředí s injekcí tajemství a otáčejte je se stejnou opatrností jako s jakýmkoli jiným přihlašovacím údajem.
def execute_with_role(cursor, role: str, query: str, params: dict):
"""Execute query with specific application role."""
# Activate application role
cursor.execute(
"EXECUTE sp_setapprole @rolename = %(role)s, @password = %(pwd)s",
{"role": role, "pwd": os.environ[f"ROLE_{role.upper()}_PWD"]}
)
try:
cursor.execute(query, params)
return cursor.fetchall()
finally:
# Reset to original context
cursor.execute("EXECUTE sp_unsetapprole")
Audit a protokolování
Záznamy bezpečnostních událostí
Nezaznamenávejte citlivá data, ale zaznamenávejte bezpečnostní události, jako jsou neúspěšná připojení, chyby oprávnění a podezřelé dotazy.
import logging
logger = logging.getLogger("db_security")
def secure_connect(connection_string: str):
"""Connect with security logging."""
logger.info("Attempting database connection")
try:
conn = mssql_python.connect(connection_string)
logger.info("Database connection established")
return conn
except mssql_python.OperationalError as e:
logger.warning(f"Database connection failed: {type(e).__name__}")
raise
Auditně citlivé operace
Konfigurujte audit databáze pro citlivé tabulky a operace. Můžete také implementovat audity na úrovni aplikací pro kritické akce.
def audit_data_access(cursor, user_id: str, action: str, resource: str):
"""Log data access for audit trail."""
cursor.execute("""
INSERT INTO AuditLog (UserID, Action, Resource, Timestamp, IPAddress)
VALUES (%(user)s, %(action)s, %(resource)s, GETUTCDATE(), %(ip)s)
""", {
"user": user_id,
"action": action,
"resource": resource,
"ip": get_client_ip()
})
Nikdy nezaznamenávejte citlivá data
Nezahrňujte hodnoty parametrů do log zpráv. Zaznamenávejte operaci, ne data.
Vyhněte se tomu - zapíše hodnotu do protokolu:
nid = "295847284"
logger.debug(f"Query: SELECT * FROM HumanResources.Employee WHERE NationalIDNumber = '{nid}'")
Doporučeno – zaznamenávat záměr bez zveřejňování hodnot:
logger.debug("Executing employee lookup query")
nid = "295847284"
cursor.execute("SELECT * FROM HumanResources.Employee WHERE NationalIDNumber = %(nid)s", {"nid": nid})
Zpracování chyb
Neodhalujte vnitřní detaily
Interně zaznamenávejte podrobné chyby, ale vraťte uživatelům obecné zprávy, abyste předešli úniku databázové struktury:
def safe_query(cursor, query: str, params: dict):
"""Execute query with safe error handling."""
try:
cursor.execute(query, params)
return cursor.fetchall()
except mssql_python.ProgrammingError as e:
# Log full error internally
logging.error(f"Query error: {e}")
# Return generic error to user
raise UserFacingError("An error occurred processing your request")
except mssql_python.IntegrityError:
raise UserFacingError("Invalid data provided")
Sanitizace chybových zpráv
Přiřaďte databázové výjimky k uživatelsky přívětivým zprávám, které neodhalují podrobnosti implementace:
class UserFacingError(Exception):
"""Exception safe to show to users."""
pass
def handle_database_error(error: Exception) -> str:
"""Convert database errors to safe user messages."""
if isinstance(error, mssql_python.IntegrityError):
if "UNIQUE" in str(error):
return "A record with this value already exists"
if "FOREIGN KEY" in str(error):
return "Referenced item not found"
return "An error occurred. Please try again later."
Kontrolní seznam zabezpečení
Kontrolní seznam bezpečnosti spojení
- [ ] Používejte autentizaci Microsoft Entra, pokud je to možné.
- [ ] Povolit šifrování (
Encrypt=yes). - [ ] Ověřte serverové certifikáty.
- [ ] Ukládejte přihlašovací údaje do zabezpečeného trezoru.
- [ ] Soubory
.envponechávejte pouze lokálně a tajné údaje vkládejte ve sdílených prostředích prostřednictvím cílové platformy. - [ ] Použijte TDS 8.0 striktní režim pro Azure SQL.
Bezpečnost dotazů
- [ ] Vždy používejte parametrizované dotazy.
- [ ] Ověřte dynamické identifikátory.
- [ ] Používejte uložené procedury pro složitou logiku.
- [ ] Omezte velikost výsledků dotazu.
Zabezpečení dat
- [ ] Používejte ochranu dat na úrovni serveru (maskování, bezpečnost na úrovni řádků).
- [ ] Používejte bezpečnost na úrovni řádků, kde je to vhodné.
- [ ] Maskujte citlivá data v logech.
Řízení přístupu
- [ ] Použijte princip nejmenšího privilegia.
- [ ] Oddělené účty pro čtení/zápis.
- [ ] Pravidelně auditujte oprávnění.
- [ ] Zaveďte časové limity spojení.
Monitoring
- [ ] Zaznamenávej bezpečnostní události.
- [ ] Monitorujte anomálie.
- [ ] Nastavte upozornění na selhání.
- [ ] Provádějte pravidelné bezpečnostní kontroly.