Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Biztonságossá tegye mssql-python alkalmazásait ezeknek a legjobb gyakorlatoknak a hitelesítés, paraméterezett lekérdezések és adatvédelmi gyakorlatok követésével.
Kezdje jelszó nélküli hitelesítéssel, amikor csak lehet. Kezeld a helyi .env fájlokat és SQL jelszavakat ideiglenes fejlesztési segédeszközként, és a titkokat kezelt identitásokba vagy titkos tárolóba helyezzék, mielőtt a kód elérné a közös környezetet.
A hitelesítés biztonsága
Használd a Microsoft Entra hitelesítést SQL hitelesítésen keresztül
A Microsoft Entra hitelesítés megszünteti a tárolt jelszavakat, és támogatja a menedzselt identitásokat. Minden környezetben jobban választom az SQL hitelesítést helyett.
Az Azure-ban futtatott munkaterhelésekhez használjon egy menedzselt identitást a következővel: ActiveDirectoryMSI. Nincs szüksége tárolt titkos adatokra, és anélkül csatlakozik, hogy végigmenne egy hitelesítőadat-láncon:
import mssql_python
def connect_with_managed_identity():
return mssql_python.connect(
"Server=<server>.database.windows.net;"
"Database=<database>;"
"Authentication=ActiveDirectoryMSI;"
"Encrypt=yes;"
)
Helyi fejlesztéshez használd ActiveDirectoryDefault, amely automatikusan felveszi az Azure CLI-t vagy más fejlesztői hitelesítményeidet. Ne használja éles környezetben, mert DefaultAzureCredential az első kapcsolat során sorrendben végigpróbálja az összes hitelesítőadat-szolgáltatót, ami olyan késleltetést okoz, amelyre az éles környezetben futó számítási feladatoknak nincs szükségük:
import mssql_python
def connect_with_default_credential():
return mssql_python.connect(
"Server=<server>.database.windows.net;"
"Database=<database>;"
"Authentication=ActiveDirectoryDefault;"
"Encrypt=yes;"
)
Kerüld el: SQL hitelesítés kódban/konfigurációban tárolja a hitelesítő adatokat, és sebezhető a szivárgásokkal.
conn = mssql_python.connect("Server=...;UID=user;PWD=password")
Soha ne égesd bele a hitelesítő adatokat a kódba
Használj környezeti változókat csak helyi fejlesztéshez. Megosztott környezetben a jelszó nélküli hitelesítést részesítjük előnyben. Ha egy örökölt SQL-hitelesítési folyamat elkerülhetetlen, futásidőben kérje le a titkot egy titoktárból, ahelyett, hogy a teljes kapcsolati karakterláncot bejelentené a verziókezelőbe.
Az alábbi megközelítés rögzíti a hitelesítést, és soha nem szabad használni:
conn_str = "Server=<server>;UID=<login>;PWD=<password>"
Helyi fejlesztéshez olvasd el a környezeti változókból származó hitelesítéseket:
import os
conn_str = (
f"Server={os.environ['DB_SERVER']};"
f"Database={os.environ['DB_NAME']};"
)
Azoknál a megosztott környezeteknél, amelyekben továbbra is szükség van titokra, futásidőben kérd le azt az Azure Key Vaultból:
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
SQL injekció megelőzése
Mindig használj paraméterezett lekérdezéseket
A paraméterezett lekérdezések megakadályozzák az SQL beinjekcióját azáltal, hogy elválasztják a felhasználói bemenetet a lekérdezési struktúrától. Mindig paraméterezd a felhasználói bemenetet.
A következő string formátumú lekérdezés sebezhető az SQL injekció szempontjából. Soha ne építs lekérdezéseket így:
user_input = "'; DROP TABLE Person.Person; --"
cursor.execute(f"SELECT * FROM Person.Person WHERE FirstName = '{user_input}'")
Az alábbi paraméterezett lekérdezés biztonságos, mert az illesztőprogram külön küldi az értéket a lekérdezési szövegtől:
user_input = "'; DROP TABLE Person.Person; --"
cursor.execute(
"SELECT * FROM Person.Person WHERE FirstName = %(name)s",
{"name": user_input}
)
Paraméterezzünk minden lekérdezési komponenseket
Nem lehet közvetlenül paraméterezni a táblázat- és oszlopneveket. Ha ezeket a felhasználói bemenetből helyettesíti be, az alkalmazás sebezhetővé válik az SQL-injekcióval szemben:
table = user_input
cursor.execute(f"SELECT * FROM {table}")
Ehelyett validáljuk a dinamikus azonosítókat egy engedélyezett értékek listájával szemben, és paraméterezzük a maradék értékeket.
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()
Validáld és sterilizáld a bemenetet
Amikor dinamikus SQL-t építesz azonosítókkal, minden értéket egy szigorú mintázat alapján validálj, mielőtt használnád:
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()}
""")
Használjon tárolt eljárásokat összetett műveletekhez
A tárolt eljárások csökkentik az alkalmazás kódjának kitett SQL felületét:
employee_id = 5
cursor.execute("""
EXECUTE dbo.uspGetEmployeeManagers @BusinessEntityID = %(id)s
""", {"id": employee_id})
Kapcsolatbiztonság
Titkosítás szükségessé tétele
Mindig titkosítsd a kapcsolatokat. Az Azure SQL alapértelmezett titkosítást érvényesít. On-premises SQL Server esetén Encrypt=yes állítsuk explicit:
conn = mssql_python.connect(
"Server=<server>.database.windows.net;"
"Database=<database>;"
"Encrypt=yes;"
"TrustServerCertificate=no"
)
Használj TDS 8.0 szigorú módot a legmagasabb biztonság érdekében
A TDS 8.0 a következőket biztosít:
- TLS 1.3 a csatlakozás kezdetétől
- Tanúsítvány érvényesítés szükséges
- Nincs visszalépés a régebbi protokollokhoz
conn = mssql_python.connect(
"Server=tcp:<server>.database.windows.net,1433;"
"Database=<database>;"
"Encrypt=strict"
)
Szerver tanúsítványok validálása
Éles környezetben mindig ellenőrizd a kiszolgáló tanúsítványát, hogy megelőzd a közbeékelődéses támadásokat. Ne állítsd be a(z) TrustServerCertificate=yes értéket, mert az megkerüli az érvényesítést. Ehelyett a TrustServerCertificate=no értéket állítsd be a CA-tanúsítványok ellenőrzésére, a HostNameInCertificate értéket pedig a gazdagépnév ellenőrzésére:
conn = mssql_python.connect(
"Server=<server>;"
"Database=<database>;"
"Encrypt=yes;"
"TrustServerCertificate=no;"
"HostNameInCertificate=<server>.domain.com"
)
Adatvédelem
Érzékeny adatok védelme szerver szinten
A Always Encrypted jelenleg nem konfigurálható mssql-python kapcsolati karakterlánc kulcsszavakkal. Ha Always Encryptedre van szükséged, használd a pyodbc-t az ODBC Driver for SQL Server-lel, ami támogatja azt. Bár nem nyújtanak ugyanilyen szintű védelmet, az SQL Server funkciói, mint a dinamikus adatmaszkolás és a sorszintű biztonság használható az érzékeny oszlopok védelmére.
employee_id = 1
cursor.execute("""
SELECT NationalIDNumber, LoginID
FROM HumanResources.Employee
WHERE BusinessEntityID = %(id)s
""", {"id": employee_id})
row = cursor.fetchone()
Az átvitel alatt álló adatok védelme
- Használja a(z)
Encrypt=yeskifejezést a kapcsolati sztringekben. - Használj VPN-t vagy privát végpontokat az on-premises kapcsolatokhoz.
- Use Azure Private Link for Azure SQL.
A legkisebb jogosultság elve
Minimális adatbázis-jogosultságok használata
Az alkalmazásfiókoknak minimális jogosultságokkal kell rendelkeznie. Ne használd a sa vagy db_owner elemet alkalmazáskapcsolatokhoz.
-
Csak olvasható tudósítás:
GRANT SELECT ON SCHEMA::dbo TO ReportingApp; -
Konkrét táblázat-hozzáférés:
GRANT SELECT, INSERT, UPDATE ON Orders TO OrderProcessor; -
Csak tárolt eljárás:
GRANT EXECUTE ON ProcessOrder TO OrderProcessor;
Különböző fiókokat használj különböző műveletekhez
Minden jogosultsági szintet saját identitással erősítsd meg, hogy egy olvasási út ne tudjon írást végrehajtani. Ez a példa két felhasználó által kijelölt menedzselt identitást használ: az egyik csak olvasási hozzáférést, a másik írási jogot, amelyeket kliensazonosító választ ki:
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;"
)
Tartsd távol az alkalmazás szereptitkokat a forrásvezérlésből
Az alkalmazás szerepének jelszavak továbbra is titkosak. Tárold őket egy trezorban vagy titkos környezeti változóban, és forgatd őket ugyanolyan gondossággal, mint bármely más hitelminősítéssel.
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")
Ellenőrzés és naplózás
Biztonsági események naplózása
Ne logold az érzékeny adatokat, de jegyzed fel a biztonsági szempontból releváns eseményeket, mint a meghibásodott kapcsolatok, engedélyhibák és gyanús lekérdezések.
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
Auditérzékeny műveletek
Konfiguráld az adatbázis-auditálást érzékeny táblákhoz és műveletekhez. Alkalmazásszintű auditálást is bevezethetsz kritikus műveletekhez.
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()
})
Sose naplózz érzékeny adatokat
Ne vegyél fel paraméterértékeket a naplóüzenetekben. Naplózza a műveletet, ne az adatokat.
Kerüld el – kiszivárogtatja az értéket a naplóba:
nid = "295847284"
logger.debug(f"Query: SELECT * FROM HumanResources.Employee WHERE NationalIDNumber = '{nid}'")
Ajánlott – a szándékot logolja értékek felfedése nélkül:
logger.debug("Executing employee lookup query")
nid = "295847284"
cursor.execute("SELECT * FROM HumanResources.Employee WHERE NationalIDNumber = %(nid)s", {"nid": nid})
Hibakezelés
Ne fedd fel a belső részleteket
A részletes hibákat belsőleg naplózzuk, de a felhasználóknak csak általános hibaüzeneteket adjunk vissza, hogy elkerüljük az adatbázis szerkezetére vonatkozó információk kiszivárgását:
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")
Tisztítsd meg hibaüzeneteket
Térképezze fel az adatbázis kivételeket felhasználóbarát üzenetekhez, amelyek nem fedik meg a megvalósítás részleteit:
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."
Biztonsági ellenőrzőlista
Kapcsolatbiztonsági ellenőrzőlista
- [ ] Használd a Microsoft Entra hitelesítést, amikor lehetséges.
- [ ] Titkosítás engedélyezése (
Encrypt=yes). - [ ] Szerver tanúsítványok validálása.
- [ ] Tárold a hitelesítési adatokat egy biztonságos trezorban.
- [ ] A
.envfájlokat csak helyben tartsa, és megosztott környezetekben a titkos adatokat a célplatformon keresztül adja meg. - [ ] Használd TDS 8.0 strict módot Azure SQL-hez.
Lekérdezésbiztonság
- [ ] Mindig használj paraméterezett lekérdezéseket.
- [ ] Validáld a dinamikus azonosítókat.
- [ ] Használj tárolt eljárásokat összetett logikához.
- [ ] Korlátozzuk a lekérdezési eredmény méretét.
Adatbiztonság
- [ ] Használj szerverszintű adatvédelmet (maszkolás, sorszintű biztonság).
- [ ] Használj sorszintű biztonságot, ahol megfelelő.
- [ ] Maszkolj érzékeny adatokat a naplókban.
Hozzáférés-kezelés
- [ ] Használd a legkisebb kiváltság elvét.
- [ ] Külön olvasási és írási fiókok.
- [ ] Rendszeresen auditálják a jogosultságokat.
- [ ] Kapcsolódási időkorlátokat kell bevezetni.
Monitoring
- [ ] Naplózz biztonsági eseményeket.
- [ ] Figyeld meg az anomáliákat.
- [ ] Állíts be riasztásokat hiba esetén.
- [ ] Rendszeres biztonsági ellenőrzéseket végezzenek.