Ghid de securitate · România

Cum securizez baza de date PostgreSQL sau MySQL în producție?

Baza de date e locul unde stau datele clienților, facturile și parolele, deci ținta finală a oricărui atac. Cele mai multe scurgeri nu vin din exploit-uri sofisticate, ci dintr-un port deschis pe internet, un cont de aplicație superuser și o parolă veche.

Actualizat la

Răspuns scurt

  1. Securizezi baza de date PostgreSQL sau MySQL în producție făcând-o să asculte doar pe localhost sau pe rețeaua privată, niciodată pe o adresă publică.
  2. Aplicația se conectează cu un rol propriu, cu drepturi doar pe schema ei, iar contul de superuser rămâne pentru administrare, folosit local.
  3. În PostgreSQL impui scram-sha-256 în pg_hba.conf și TLS cu hostssl; în MySQL pui bind-address, ștergi root@% și rulezi mysql_secure_installation.
  4. Parolele vin dintr-un manager de secrete, ai backup logic zilnic plus PITR și loghezi conexiunile eșuate.
Metoda de autentificare PostgreSQL
scram-sha-256, nu md5 sau trust
Adresa de ascultare
127.0.0.1 sau IP-ul din rețeaua privată
Contul aplicației
rol propriu, fără SUPERUSER, fără DROP
Backup
pg_dump / mysqldump zilnic + PITR din WAL sau binlog

Rețea și autentificare: primele două straturi

Un server de baze de date nu are nevoie să fie accesibil de pe internet, nici cu parolă bună. Îl legi de adresa privată, iar administrarea de la distanță o faci prin tunel SSH sau VPN. Al doilea strat e autentificarea: pg_hba.conf spune cine se poate conecta, de unde, la ce bază și cum. Metodele trust și md5 pe rețea trebuie să dispară; scram-sha-256 e implicit din PostgreSQL 14, iar hostssl refuză conexiunile necriptate. În MySQL, echivalentul e bind-address, conturi pe host precis, nu pe %, și require_secure_transport = ON.

Privilegii minime: aplicația nu e administrator

Cea mai frecventă greșeală e aplicația conectată ca postgres sau root, „ca să meargă migrările”. Când aplicația are un SQL injection, atacatorul are tot ce are contul: toate bazele, extensii, citire de fișiere de pe disc. Corect, creezi un rol pentru aplicație cu SELECT, INSERT, UPDATE, DELETE pe tabelele ei și un rol separat pentru migrări, folosit doar la deploy. Rolurile de raportare primesc doar SELECT. Fiecare rol are parola lui, rotită când cineva pleacă, ținută în managerul de secrete, nu în cod.

  • Un rol per aplicație și per mediu; staging nu folosește parola din producție
  • ALTER DEFAULT PRIVILEGES ca tabelele noi să moștenească drepturile corecte
  • log_connections activ, cu logurile trimise la sistemul central

Ce spune legislația din România

Baza de date e, aproape întotdeauna, locul unde stau datele personale, deci art. 32 GDPR se aplică direct: criptare, control al accesului, capacitate de restaurare. La o scurgere, ANSPDCP trebuie notificată în 72 de ore, iar prima întrebare e cine avea acces la date și cum. Pentru entitățile de sub OUG 155/2024, gestionarea accesului și backup-ul sunt măsuri minime explicite. Facturile emise prin e-Factura au termene legale de păstrare, deci backup-ul testat al bazei e obligație, nu opțiune.

Setări echivalente de securitate în PostgreSQL și MySQL / MariaDB
ControlPostgreSQLMySQL / MariaDB
Adresa de ascultarelisten_addresses în postgresql.confbind-address în my.cnf
Cine se conectează, de undepg_hba.conf, o linie per rol și rețeautilizator@host, fără %
Autentificarescram-sha-256caching_sha2_password (implicit din 8.0)
Criptare în tranzitssl = on, hostssl în pg_hba.confrequire_secure_transport = ON
Backup logic + punct în timppg_dump + arhivare WAL (PITR)mysqldump / mariabackup + binlog

Comenzi și configurări

postgresql.conf și pg_hba.conf: doar rețeaua privată, doar scram-sha-256, doar TLS
# postgresql.conf (fragment)
listen_addresses = '10.0.0.10'
password_encryption = scram-sha-256
ssl = on
log_connections = on

# pg_hba.conf
# TYPE     DATABASE  USER      ADDRESS        METHOD
local      all       postgres                 peer
hostssl    app_db    app_user  10.0.0.5/32    scram-sha-256
host       all       all       0.0.0.0/0      reject
PostgreSQL: rol de aplicație cu privilegii minime
CREATE ROLE app_user LOGIN PASSWORD 'parola-din-managerul-de-secrete';
GRANT CONNECT ON DATABASE app_db TO app_user;
GRANT USAGE ON SCHEMA public TO app_user;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO app_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
  GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO app_user;
MySQL: bind pe rețeaua privată, TLS obligatoriu, fără root@%
# /etc/mysql/mysql.conf.d/mysqld.cnf (fragment)
[mysqld]
bind-address = 10.0.0.10
require_secure_transport = ON
local_infile = 0

-- în clientul mysql
DROP USER IF EXISTS 'root'@'%';
CREATE USER 'app'@'10.0.0.5' IDENTIFIED BY 'parola-din-managerul-de-secrete';
GRANT SELECT, INSERT, UPDATE, DELETE ON app_db.* TO 'app'@'10.0.0.5';
FLUSH PRIVILEGES;

Exemple practice

SaaS din Iași cu PostgreSQL pe același VPS cu aplicația

Aplicația rula ca postgres, iar un formular vulnerabil a permis un SQL injection care a citit toate schemele, inclusiv ale altor clienți. Fiecare tenant a primit apoi un rol propriu, aplicația a pierdut superuser, iar pg_hba.conf a trecut pe scram-sha-256 și hostssl.

Magazin online din Oradea cu MySQL administrat de la distanță

Pentru un client desktop, cineva crease root@% și deschisese 3306 în firewall. Un scaner l-a găsit în câteva ore și a început brute force-ul. Contul a fost șters, bind-address setat pe adresa privată, iar accesul de la distanță s-a mutat pe tunel SSH.

Greșeli frecvente

  • Lași listen_addresses = '*' sau bind-address = 0.0.0.0 și te bazezi pe parolă.
  • Aplicația se conectează ca postgres sau root pentru că „așa au mers migrările”.
  • Ai backup, dar nu l-ai restaurat niciodată și nu ai PITR pentru o ștergere accidentală.
  • Parola bazei de date stă în repo, identică pe staging și producție.

Cum te ajută 4hosting

  • Serviciul PostgreSQL & ClickHouse acoperă replicarea, backup-ul PITR și tuning-ul; MongoDB & Redis include hardening-ul acestor motoare.
  • Orele incluse lunar, 1–8 la VPS și 10 la dedicate și GPU, se cer din panoul de client, secțiunea „Servicii DevOps”; un audit al pg_hba.conf și al rolurilor intră de obicei în cotă; orele se consumă în luna calendaristică și nu se reportează.
  • Serviciul Firewall & Network Isolation separă serverul de baze de date de cel de aplicație într-o rețea privată.

Întrebări conexe

  • Trebuie TLS între aplicație și baza de date dacă rulează pe același server?

    Pe același server, prin socket Unix sau 127.0.0.1, traficul nu părăsește mașina, deci TLS e opțional. Când baza de date e pe alt server, chiar în aceeași rețea privată, TLS devine obligatoriu: rețeaua furnizorului e partajată și o greșeală de configurare o expune.

  • Ce înseamnă PITR și de ce nu ajunge pg_dump?

    pg_dump îți dă starea de la ora la care a rulat; tot ce s-a întâmplat după se pierde. PITR, recuperarea la un punct în timp, folosește arhiva WAL, sau binlog-ul în MySQL, ca să reconstruiești baza la minutul dinaintea unui DELETE greșit. Le folosești împreună.

  • Criptez discul sau baza de date?

    Criptarea discului te protejează de furtul fizic sau de un disc scos din rotație, nu de un atacator conectat la baza care rulează. Pentru coloane sensibile, CNP sau date de plată, criptarea la nivel de aplicație, cu chei în afara bazei, e stratul care contează.

Cere o verificare de securitate

Un server de producție e atacat automat din primele minute după ce primește IP public, indiferent cât de mic e proiectul. Ghidul ordonează controalele după impact, de la accesul SSH până la răspunsul la incident, cu legislația din România care se aplică. Fiecare temă are o pagină dedicată, cu răspuns scurt, exemple și configurări.