Sari la conținut
Server și .htaccess

Reguli de securitate .htaccess pentru WordPress care chiar ajută

Cea mai mare parte din ce se vinde drept securitate .htaccess pentru WordPress e umplutură. Regulile care chiar îți schimbă suprafața de atac sunt scurte — iată care e care

Publicat

Cea mai mare parte din ce se vinde drept „securitate .htaccess pentru WordPress” e umplutură. Regulile care chiar îți schimbă suprafața de atac sunt scurte: blochează execuția PHP în wp-content/uploads, interzice accesul direct la wp-config.php și dezactivează indexarea directoarelor. Cele populare — blocarea lui xmlrpc.php „ca să oprești atacurile brute force”, ascunderea versiunii de WordPress, lipirea unei liste de 200 de linii cu user-agenți de boți răi — variază de la marginale la pur teatru. Mai jos e care e care și de ce.

Un lucru de lămurit din start: .htaccess are efect doar pe Apache (și LiteSpeed, care îl citește și el). Pe nginx e ignorat complet — fișierul stă acolo degeaba, în timp ce tu crezi că ești protejat. Dacă hostingul tău rulează nginx, nimic din toate astea nu se aplică și îți trebuie blocuri server/location în loc. Verifică cu curl -I https://siteultau.com și uită-te la antetul Server: înainte să pierzi o oră editând un fișier pe care serverul nu-l citește niciodată.

Regula care chiar contează: fără PHP în /uploads

Asta e cea care merită făcută. wp-content/uploads e writable pentru toată lumea prin design — fiecare fișier media încărcat, fiecare plugin care salvează un fișier, scrie acolo. Dacă un atacator reușește să bage un fișier .php în directorul ăla (printr-un handler de upload vulnerabil, un câmp de imagine care nu validează tipul MIME, un plugin compromis), diferența dintre o pacoste și un compromis complet cu execuție de cod la distanță este dacă serverul execută fișierul respectiv când e cerut. Interzice execuția și payload-ul încărcat rămâne doar un fișier inert pe disc.

Pune asta în wp-content/uploads/.htaccess (creează fișierul dacă nu există):

<FilesMatch "\.php$">
    Require all denied
</FilesMatch>

Asta e sintaxă Apache 2.4. Pe versiunea mai veche, 2.2, echivalentul e Order Deny,Allow / Deny from all. Amestecarea celor două dialecte în același fișier e cea mai frecventă cauză a unei erori bruște 500 Internal Server Error după „securizare” — dacă tot site-ul cade în clipa în care salvezi, aproape întotdeauna ăsta e motivul. Verifică-ți versiunea cu apachectl -v.

Protejează wp-config.php

wp-config.php conține datele de acces la baza de date și cheile de autentificare (salts). Cât timp PHP rulează, o cerere directă către el returnează o pagină goală — PHP execută fișierul în loc să-l afișeze. Riscul e cazul de eșec: dacă PHP cedează vreodată, e configurat greșit în timpul unei migrări sau handler-ul e dezactivat, Apache servește fișierul ca text simplu și dezvăluie parola bazei de date oricui o cere. Interzicerea accesului e o asigurare ieftină împotriva a cinci minute proaste:

<Files wp-config.php>
    Require all denied
</Files>

Dezactivează indexarea directoarelor

Dacă cineva vizitează un folder fără index.php și Apache are Options +Indexes activat, îi listează conținutul — fiecare fișier de backup, fiecare dump SQL rătăcit pe care l-ai uitat acolo. Dezactiveaz-o pe tot site-ul:

Options -Indexes

Severitate mică, dar reală, și nu costă nimic.

Asta e lista de bază, onestă. Poți asambla aceste reguli — plus sintaxa corectă 2.4-vs-2.2, ca să nu-ți dai site-ul peste cap cu un 500 — cu generatorul de .htaccess pentru WordPress, în loc să copiezi de pe un forum un text scris pentru versiunea greșită de Apache.

Ce să NU faci

Blocarea lui xmlrpc.php „pentru protecție împotriva brute force”. Asta e cea mare pe care o repetă toată lumea și e greșită așa cum e formulată. Da, metoda system.multicall din XML-RPC a permis istoric unui atacator să împacheteze multe încercări de login într-o singură cerere — amplificare reală. Dar vectorul de brute force covârșitor de frecvent sunt cererile POST simple către wp-login.php, iar blocarea lui xmlrpc.php nu face nimic pentru asta. Atacurile brute force sunt învinse prin limitarea ratei (rate limiting), parole puternice și 2FA — nu prin uciderea unui singur endpoint. Există un motiv legitim să dezactivezi XML-RPC: funcția lui de pingback poate fi abuzată pentru reflectare de atacuri DDoS, deci dacă nu folosești Jetpack, aplicația de mobil sau pingback-urile, închiderea lui îți micșorează suprafața de atac. Doar nu-ți spune că e apărarea ta împotriva brute force, pentru că nu e.

Ascunderea versiunii de WordPress / eliminarea tag-ului generator. Ștergerea lui readme.html și a tag-ului <meta name="generator"> pare securizare. Un atacator îți identifică versiunea din query string-urile atașate resurselor (assets), din marcajul block-editorului și din alte zece indicii, în câteva secunde. Nu ascunzi nimic; doar te faci să te simți ocupat.

Liste uriașe de blocare pentru user-agenți de boți răi și referreri. User-agentul e un simplu antet HTTP care poate fi falsificat. Listele astea sunt învechite din ziua în care le lipești, nu blochează nimic competent, iar Apache evaluează fiecare regex la fiecare cerere — plătești o taxă de performanță reală pentru zero securitate. Sari peste ele.

Blocarea lui wp-login.php pe IP. Grozav până când ISP-ul îți schimbă adresa și te-ai blocat singur în afara propriului admin. Viabil doar cu un IP cu adevărat static.

Redirecționări împotriva enumerării autorilor (?author=1). Rescrierea .htaccess pe care o lipește lumea pentru asta e incompletă de una singură — endpoint-ul REST /wp-json/wp/v2/users tot listează numele de utilizator. Blocarea unei căi în timp ce cealaltă rămâne deschisă e teatru.

Tot blocat?

Dacă o regulă dă 500 la site, e o problemă de sintaxă — scoate ultimul bloc adăugat și reîncarcă; asta îl izolează imediat. Dacă o regulă pare că nu face nimic, confirmă că ești chiar pe Apache și că AllowOverride e activat pentru directorul respectiv (multe hosturi manageriate îl restricționează). Construiește fișierul dintr-un șablon verificat cu generatorul de .htaccess, păstrează cele trei reguli care contează și renunță la rest.