Skip to main content

Cyber AI România

Sâmbătă, 7 noiembrie 2026

Cum rotești cheile și sărurile WordPress după plecarea unui administrator

Un administrator care a avut acces la server ar fi putut vedea conținutul fișierului wp-config.php, inclusiv secretele folosite de WordPress pentru autentificare. După încheierea colaborării, schimbarea parolei contului său nu rezolvă singură această expunere: trebuie revocate metodele de acces, apoi regenerate cele opt chei și săruri WordPress fără a le afișa în terminal sau în loguri.

La finalul procedurii, fostul cont este eliminat cu articolele realocate, parolele de aplicație sunt revocate, iar wp config shuffle-salts înlocuiește secretele din wp-config.php. Cookie-urile de autentificare existente devin nevalide, toți utilizatorii trebuie să se conecteze din nou, iar site-ul rămâne funcțional. Scenariul acoperă un site WordPress individual, nu o rețea Multisite.

Fixăm intervenția la un site administrat prin WP-CLI

Exemplul folosește Ubuntu Server 24.04 LTS, PHP 8.3 și WP-CLI 2.12.0. Site-ul se află în /var/www/example.com/public, iar fișierele sale sunt deținute de utilizatorul dedicat wp-example. Domeniul example.com este rezervat documentației; înlocuiește-l cu domeniul propriu.

Ai nevoie de acces sudo, de un cont WordPress administrator care rămâne în firmă și de aproximativ 30 de minute. Operațiunea nu cere oprirea PHP-FPM sau a serverului web, dar îi va deconecta pe toți utilizatorii autentificați. Anunță echipa și evită intervalele în care editorii lucrează la formulare nesalvate.

Verifică mediul fără să citești conținutul wp-config.php:

cat /etc/os-release
php --version | head -n 1
wp --info
sudo -u wp-example -- wp --path=/var/www/example.com/public core version
sudo -u wp-example -- wp --path=/var/www/example.com/public core is-installed
sudo stat -c 'proprietar=%U grup=%G permisiuni=%a fișier=%n' 
  /var/www/example.com/public/wp-config.php

Un rezultat compatibil arată astfel; versiunile patch și calea executabilului pot diferi:

PRETTY_NAME="Ubuntu 24.04 LTS"
PHP 8.3.x (cli)
WP-CLI version: 2.12.0
6.x sau o versiune ulterioară instalată
proprietar=wp-example grup=www-data permisiuni=640 fișier=/var/www/example.com/public/wp-config.php

Mesajul Success: WordPress is installed. confirmă că --path indică instalarea corectă. Permisiunea 640 este potrivită numai dacă proprietarul poate scrie fișierul, iar grupul serverului web are nevoie să-l citească. Documentația WordPress recomandă ca wp-config.php să poată fi citit doar de proprietar și, dacă arhitectura o cere, de serverul web.

Pachetele locale folosite de procedură se instalează într-un singur pas:

sudo apt update
sudo apt install --yes ca-certificates php-cli

ca-certificates permite validarea conexiunii HTTPS către serviciul oficial care furnizează valori aleatoare, iar php-cli verifică sintaxa configurației. WP-CLI trebuie instalat conform instrucțiunilor oficiale și disponibil prin comanda wp; nu descărca executabile din surse neoficiale.

Dacă serverul găzduiește mai multe instalări, separarea utilizatorilor și a pool-urilor PHP-FPM reduce accesul transversal la configurații. Procedura este explicată în ghidul despre izolarea site-urilor WordPress cu PHP-FPM.

Păstrăm doar trei artefacte și nu copiem secretele în consolă

Intervenția folosește următoarea structură:

/var/www/example.com/public/wp-config.php
  Configurația activă a site-ului; valorile secrete nu sunt afișate.

/usr/local/sbin/rotate-wordpress-salts
  Scriptul executat de root, care verifică, salvează și rotește valorile.

/var/backups/wordpress/example.com/
  Director accesibil doar root, în care se păstrează copia anterioară.

Copia nu trebuie salvată în directorul public al site-ului și nici într-un ticket, e-mail sau repository Git. Ea conține credențialele bazei de date și vechile chei, chiar dacă tutorialul nu le afișează.

Pasul 1 — Identificăm contul plecat și administratorul care preia conținutul

De ce: înaintea oricărei ștergeri trebuie să confirmi că lucrezi pe site-ul corect și că există un administrator nominal care va primi articolele fostului coleg.

În exemplu, contul plecat este fost-admin, iar cel rămas este admin-operational. Înlocuiește aceste două valori cu numele reale de autentificare:

SITE_PATH='/var/www/example.com/public'
FORMER_LOGIN='fost-admin'
SUCCESSOR_LOGIN='admin-operational'

sudo -u wp-example -- wp --path="$SITE_PATH" option get siteurl
sudo -u wp-example -- wp --path="$SITE_PATH" user list 
  --role=administrator 
  --fields=ID,user_login,display_name 
  --format=table

FORMER_ID="$(
  sudo -u wp-example -- wp --path="$SITE_PATH" user get "$FORMER_LOGIN" --field=ID
)"
SUCCESSOR_ID="$(
  sudo -u wp-example -- wp --path="$SITE_PATH" user get "$SUCCESSOR_LOGIN" --field=ID
)"

printf 'Cont retras: ID %snCont succesor: ID %sn' 
  "$FORMER_ID" "$SUCCESSOR_ID"

option get siteurl previne intervenția pe alt site. --fields limitează tabelul la datele necesare, iar --field=ID furnizează identificatorul pe care îl cer comenzile următoare.

Exemplu de rezultat:

https://example.com
+----+-------------------+----------------------+
| ID | user_login        | display_name         |
+----+-------------------+----------------------+
| 7  | fost-admin        | Administrator extern |
| 12 | admin-operational | Echipa operațională  |
+----+-------------------+----------------------+
Cont retras: ID 7
Cont succesor: ID 12

Punct de control: dacă domeniul, numele sau rolurile nu corespund, oprește-te și verifică valoarea SITE_PATH; nu presupune identitatea unei persoane doar după numele afișat.

Pasul 2 — Revocăm parolele de aplicație și sesiunile fostului administrator

De ce: rotirea sărurilor invalidează cookie-urile WordPress, dar nu trebuie tratată ca înlocuitor pentru revocarea celorlalte credențiale. Application Passwords sunt credențiale distincte folosite, de exemplu, de integrări prin REST API.

Listează întâi parolele de aplicație fără a afișa secretul inițial, apoi revocă-le și distruge sesiunile contului:

SITE_PATH='/var/www/example.com/public'
FORMER_LOGIN='fost-admin'

FORMER_ID="$(
  sudo -u wp-example -- wp --path="$SITE_PATH" user get "$FORMER_LOGIN" --field=ID
)"

sudo -u wp-example -- wp --path="$SITE_PATH" 
  user application-password list "$FORMER_ID" 
  --fields=uuid,name,created,last_used 
  --format=table

sudo -u wp-example -- wp --path="$SITE_PATH" 
  user application-password delete "$FORMER_ID" --all

sudo -u wp-example -- wp --path="$SITE_PATH" 
  user session destroy "$FORMER_ID" --all

Câmpurile name, created și last_used ajută la identificarea integrărilor care trebuie mutate pe un cont tehnic controlat de firmă. Opțiunea --all revocă toate parolele de aplicație, respectiv toate sesiunile asociate utilizatorului indicat.

Exemplu de confirmare:

Success: All application passwords deleted.
Success: Destroyed all sessions for user 7.

Formularea exactă poate varia între versiunile WP-CLI, dar fiecare comandă trebuie să se încheie cu Success și un cod de ieșire zero.

Punct de control: dacă o integrare legitimă se oprește după revocare, creează ulterior o credențială nouă pentru un cont dedicat; nu reactiva parola fostului administrator.

Pasul 3 — Ștergem contul fără să ștergem articolele publicate

De ce: păstrarea unui cont inactiv cu rol de administrator creează o cale inutilă de revenire. WordPress poate realoca articolele către administratorul care rămâne.

Avertisment: comanda următoare șterge utilizatorul. Confirmă încă o dată cele două ID-uri și existența unui backup al bazei de date înainte de execuție.

SITE_PATH='/var/www/example.com/public'
FORMER_LOGIN='fost-admin'
SUCCESSOR_LOGIN='admin-operational'

FORMER_ID="$(
  sudo -u wp-example -- wp --path="$SITE_PATH" user get "$FORMER_LOGIN" --field=ID
)"
SUCCESSOR_ID="$(
  sudo -u wp-example -- wp --path="$SITE_PATH" user get "$SUCCESSOR_LOGIN" --field=ID
)"

printf 'Va fi șters ID %s; conținutul ajunge la ID %s.n' 
  "$FORMER_ID" "$SUCCESSOR_ID"

sudo -u wp-example -- wp --path="$SITE_PATH" 
  user delete "$FORMER_ID" 
  --reassign="$SUCCESSOR_ID" 
  --yes

if sudo -u wp-example -- wp --path="$SITE_PATH" 
  user get "$FORMER_LOGIN" >/dev/null 2>&1; then
  printf 'EROARE: contul există încă.n' >&2
  exit 1
fi

printf 'OK: contul retras nu mai există.n'

--reassign mută conținutul către ID-ul succesorului, iar --yes confirmă operațiunea fără un prompt interactiv. Acțiunea nu înlocuiește verificarea accesului SSH, a panoului de hosting, a registrarului, a CDN-ului, a copiilor de siguranță și a conturilor de e-mail.

Rezultatul așteptat este:

Success: Removed user 7 from https://example.com.
OK: contul retras nu mai există.

Punct de control: dacă WP-CLI raportează că utilizatorul nu poate fi șters sau că ID-ul de realocare nu există, nu relansa comanda cu alte valori până nu verifici tabelul de administratori.

Pasul 4 — Scriem un script care rotește opt secrete fără să le afișeze

De ce: editarea manuală poate lăsa o cheie veche, poate introduce o eroare PHP sau poate copia secretele în istoricul terminalului. Scriptul verifică toate cele opt constante, creează o copie protejată și restaurează configurația dacă rotația ori validarea eșuează.

Fișierul /usr/local/sbin/rotate-wordpress-salts trebuie creat integral:

sudo tee /usr/local/sbin/rotate-wordpress-salts >/dev/null <<'BASH'
#!/usr/bin/env bash
set -euo pipefail

SITE_PATH='/var/www/example.com/public'
SITE_USER='wp-example'
CONFIG="${SITE_PATH}/wp-config.php"
BACKUP_DIR='/var/backups/wordpress/example.com'
WP_BIN="$(command -v wp)"
STAMP="$(date -u +%Y%m%dT%H%M%SZ)"
BACKUP="${BACKUP_DIR}/wp-config.php.${STAMP}"

KEYS=(
  AUTH_KEY
  SECURE_AUTH_KEY
  LOGGED_IN_KEY
  NONCE_KEY
  AUTH_SALT
  SECURE_AUTH_SALT
  LOGGED_IN_SALT
  NONCE_SALT
)

fail() {
  printf 'EROARE: %sn' "$1" >&2
  exit 1
}

restore_backup() {
  cp --archive -- "$BACKUP" "$CONFIG"
  printf 'EROARE: rotația a eșuat; copia %s a fost restaurată.n' 
    "$BACKUP" >&2
}

[[ "${EUID}" -eq 0 ]] || fail 'rulează scriptul cu sudo.'
[[ -f "$CONFIG" ]] || fail "lipsește ${CONFIG}."
id "$SITE_USER" >/dev/null 2>&1 || fail "lipsește utilizatorul ${SITE_USER}."
[[ "$(stat -c '%U' "$CONFIG")" == "$SITE_USER" ]] ||
  fail "wp-config.php nu este deținut de ${SITE_USER}."
sudo -u "$SITE_USER" -- test -w "$CONFIG" ||
  fail "wp-config.php nu poate fi scris de ${SITE_USER}."

for key in "${KEYS[@]}"; do
  if ! sudo -u "$SITE_USER" -- "$WP_BIN" --path="$SITE_PATH" 
    config has "$key"; then
    fail "lipsește constanta ${key}."
  fi
done

install -d -o root -g root -m 0700 "$BACKUP_DIR"
cp --archive -- "$CONFIG" "$BACKUP"

if ! php -l "$CONFIG"; then
  fail 'configurația inițială nu trece verificarea PHP.'
fi

BEFORE_HASH="$(sha256sum "$CONFIG" | cut -d' ' -f1)"

if ! sudo -u "$SITE_USER" -- "$WP_BIN" --path="$SITE_PATH" 
  config shuffle-salts; then
  restore_backup
  exit 1
fi

if ! php -l "$CONFIG"; then
  restore_backup
  exit 1
fi

for key in "${KEYS[@]}"; do
  if ! sudo -u "$SITE_USER" -- "$WP_BIN" --path="$SITE_PATH" 
    config has "$key"; then
    restore_backup
    exit 1
  fi
done

AFTER_HASH="$(sha256sum "$CONFIG" | cut -d' ' -f1)"
[[ "$BEFORE_HASH" != "$AFTER_HASH" ]] || {
  restore_backup
  fail 'fișierul nu s-a modificat.'
}

printf 'OK: cele opt chei și săruri au fost rotite.n'
printf 'Backup protejat: %sn' "$BACKUP"
BASH

sudo chown root:root /usr/local/sbin/rotate-wordpress-salts
sudo chmod 0750 /usr/local/sbin/rotate-wordpress-salts
sudo bash -n /usr/local/sbin/rotate-wordpress-salts

set -euo pipefail oprește scriptul la o comandă eșuată, la o variabilă nedefinită sau la o eroare ascunsă într-un pipeline. config has confirmă existența constantelor fără să le imprime valorile. Hash-urile sunt comparate în memorie și nu sunt afișate.

wp config shuffle-salts rotește implicit cheile și sărurile standard WordPress. Nu utiliza opțiunea --insecure: aceasta ar dezactiva verificarea TLS, mascând o problemă de certificate.

Comanda bash -n nu modifică site-ul; validează sintaxa scriptului. Lipsa oricărui mesaj indică succes.

Punct de control: dacă bash -n afișează o linie cu eroare, nu executa scriptul și compară fișierul cu blocul complet de mai sus.

Pasul 5 — Executăm rotația și acceptăm deconectarea globală

De ce: numai acum, după revocarea accesului individual și validarea scriptului, înlocuim secretele care protejează cookie-urile și nonce-urile WordPress.

Salvează orice formular deschis în WordPress înainte de comandă:

sudo /usr/local/sbin/rotate-wordpress-salts

Exemplu de rezultat:

No syntax errors detected in /var/www/example.com/public/wp-config.php
Success: Shuffled the salt keys.
No syntax errors detected in /var/www/example.com/public/wp-config.php
OK: cele opt chei și săruri au fost rotite.
Backup protejat: /var/backups/wordpress/example.com/wp-config.php.20261002T090000Z

Momentul din numele copiei va fi diferit. În urma schimbării, sesiunile autentificate anterior nu mai trebuie acceptate. Utilizatorii vor vedea din nou formularul de login, iar formularele deschise înaintea rotației pot cere reîncărcarea paginii.

Această măsură completează, nu înlocuiește, controalele descrise în ghidul despre securizarea unui site WordPress în prima zi, precum conturile nominale, actualizările și backupul verificat.

Punct de control: dacă WP-CLI nu poate contacta serviciul de generare, rezolvă DNS-ul, ora sistemului sau certificatele CA și repetă procedura; nu copia săruri dintr-un generator neoficial.

Confirmăm site-ul, loginul nou și respingerea cookie-ului vechi

Deschide înaintea rotației o sesiune autentificată într-un browser separat. După execuție, reîncarcă acea pagină: WordPress trebuie să ceară din nou autentificarea.

Apoi rulează testul de capăt:

SITE_PATH='/var/www/example.com/public'

sudo -u wp-example -- wp --path="$SITE_PATH" core is-installed
sudo -u wp-example -- wp --path="$SITE_PATH" option get siteurl
sudo -u wp-example -- wp --path="$SITE_PATH" user list 
  --role=administrator 
  --fields=ID,user_login 
  --format=table

curl --silent --show-error --output /dev/null 
  --write-out 'HTTP %{http_code}n' 
  https://example.com/

Rezultatul așteptat pentru scenariul nostru este:

Success: WordPress is installed.
https://example.com
+----+-------------------+
| ID | user_login        |
+----+-------------------+
| 12 | admin-operational |
+----+-------------------+
HTTP 200

Un răspuns 301 sau 302 poate fi legitim dacă domeniul redirecționează către adresa canonică. Verifică destinația cu curl --location și confirmă că răspunsul final este cel configurat de site.

Autentifică-te cu administratorul rămas, deschide o pagină de administrare și salvează un draft de test. Nu verifica rotația prin afișarea constantelor: faptul că valorile există, hash-ul fișierului s-a schimbat și vechiul cookie a fost respins este suficient.

Cinci mesaje care localizează problema

EROARE: rulează scriptul cu sudo. apare când scriptul nu are dreptul de a crea backupul protejat. Rulează sudo /usr/local/sbin/rotate-wordpress-salts.

EROARE: lipsește /var/www/example.com/public/wp-config.php. indică o cale greșită. Localizează instalarea prin configurația serverului web și corectează SITE_PATH; nu căuta global afișând conținutul fișierelor.

EROARE: wp-config.php nu este deținut de wp-example. arată că modelul de proprietate diferă. Verifică stat și identifică utilizatorul real de deployment. Nu aplica automat chmod 777 și nu schimba proprietarul fără să înțelegi configurația PHP-FPM.

EROARE: lipsește constanta AUTH_KEY. — sau alt nume din listă — înseamnă că fișierul nu conține setul standard complet. Oprește intervenția și verifică dacă secretele sunt încărcate din variabile de mediu ori din alt fișier; shuffle-salts nu trebuie forțat peste o arhitectură necunoscută.

EROARE: rotația a eșuat; copia ... a fost restaurată. apare dacă WP-CLI sau verificarea PHP eșuează după backup. Rulează din nou php -l și verifică accesul HTTPS către api.wordpress.org. Nu folosi --insecure pentru a ocoli o eroare de certificat.

Restaurăm numai dacă configurația nu mai poate fi încărcată

Deconectarea utilizatorilor nu este motiv de rollback; acesta este rezultatul urmărit. Restaurarea vechilor săruri poate face din nou acceptabile cookie-uri vechi, de aceea copia se folosește doar temporar dacă site-ul nu mai poate încărca configurația.

Pentru a identifica cea mai recentă copie fără a-i afișa conținutul:

BACKUP="$(
  sudo find /var/backups/wordpress/example.com 
    -maxdepth 1 -type f -name 'wp-config.php.*' 
    -printf '%T@ %pn' |
  sort -nr |
  head -n 1 |
  cut -d' ' -f2-
)"

printf 'Copia selectată: %sn' "$BACKUP"

Avertisment: restaurarea reactivează vechile valori. Fă operațiunea doar cât repari problema, apoi rulează din nou rotația înainte de a considera intervenția închisă.

sudo cp --archive -- "$BACKUP" 
  /var/www/example.com/public/wp-config.php

sudo php -l /var/www/example.com/public/wp-config.php
sudo /usr/local/sbin/rotate-wordpress-salts

După ce site-ul a funcționat stabil și backupul general al firmei a rulat, scriptul și copia punctuală pot fi eliminate.

Avertisment: comenzile următoare șterg artefactele create în tutorial, nu configurația activă:

sudo rm -- /usr/local/sbin/rotate-wordpress-salts
sudo rm -- "$BACKUP"
sudo rmdir /var/backups/wordpress/example.com 2>/dev/null || true

Nu dezinstala php-cli sau ca-certificates de pe un server WordPress de producție doar pentru că intervenția s-a încheiat; pot fi folosite de mentenanță și de alte componente.

Lista de control pentru închiderea accesului

  • ☐ Domeniul returnat de wp option get siteurl este cel vizat.
  • ☐ Există un administrator nominal care rămâne în firmă.
  • ☐ Application Passwords ale fostului administrator au fost revocate.
  • ☐ Sesiunile fostului administrator au fost distruse.
  • ☐ Contul plecat a fost șters, iar conținutul a fost realocat.
  • ☐ Cele opt constante există fără ca valorile lor să fi fost afișate.
  • ☐ php -l confirmă sintaxa fișierului wp-config.php.
  • ☐ O sesiune deschisă înaintea rotației este trimisă la login.
  • ☐ Administratorul rămas se poate autentifica și salva un draft.
  • ☐ Accesul SSH, hostingul, registrarul, CDN-ul și backupurile au fost verificate separat.

Următorul proiect logic este mutarea automatizărilor de pe conturile personale pe conturi tehnice cu drepturi minime. Pentru echipele care administrează mai multe site-uri, aceeași rotație poate fi inclusă într-un runbook de offboarding, cu inventarul domeniilor și o confirmare separată pentru fiecare instalare.

Întrebări frecvente

Rotirea sărurilor îi deconectează și pe administratorii care rămân?

Da. Cookie-urile autentificate anterior nu mai sunt acceptate, astfel că toți utilizatorii trebuie să se conecteze din nou.

Trebuie să copiez noile valori din generatorul WordPress?

Nu. wp config shuffle-salts le generează și le scrie fără să fie nevoie să le copiezi sau să le afișezi în terminal.

Rotirea sărurilor revocă și Application Passwords?

Nu trebuie presupus acest lucru. Tutorialul le listează și le șterge explicit înainte de rotație, deoarece sunt credențiale distincte de cookie-urile browserului.

Pot restaura copia dacă utilizatorii au fost deconectați?

Nu doar din acest motiv. Deconectarea este efectul urmărit, iar revenirea la vechile valori poate face din nou utilizabile cookie-uri anterioare.

Surse

Facebook
X
WhatsApp
Cum rotești cheile și sărurile din wp-config.php după plecarea unui administrator

Te-ar putea interesa si: