WordPress Security Hardening: Checklist Bảo Mật Production Cho Website Doanh Nghiệp

WordPress security hardening là việc biến một website WordPress từ trạng thái “chạy được” thành trạng thái “chịu được vận hành production”: có tài khoản an toàn, quyền file đúng, plugin/theme được kiểm soát, backup khôi phục được, log đủ để điều tra, và lớp phòng thủ trước brute force, malware, supply chain risk. Với website doanh nghiệp, bảo mật WordPress không phải cài một plugin rồi quên; nó là một quy trình vận hành định kỳ.

Bài viết này là checklist thực chiến cho sysadmin, DevOps và quản trị viên WordPress. Bối cảnh lab/production: WordPress chạy trên Linux với Nginx/Apache + PHP-FPM + MariaDB/MySQL, có quyền SSH/WP-CLI, website public qua HTTPS, dùng plugin SEO/cache/form phổ biến, có môi trường staging nếu cần. Mục tiêu: giảm bề mặt tấn công mà không làm hỏng trải nghiệm người dùng hoặc quy trình xuất bản nội dung.

1. Hiểu mô hình rủi ro của WordPress production

WordPress thường bị tấn công qua các hướng sau:

  • Tài khoản yếu: mật khẩu dễ đoán, dùng chung tài khoản admin, thiếu 2FA.
  • Plugin/theme lỗi thời: lỗ hổng upload file, SQL injection, XSS, privilege escalation.
  • File permission sai: web server có quyền ghi quá rộng, attacker sửa PHP sau khi chiếm một điểm vào.
  • Endpoint public: xmlrpc.php, wp-login.php, REST API, admin-ajax.php bị brute force hoặc abuse.
  • Backup kém: có backup nhưng chưa test restore, hoặc backup nằm public trong webroot.
  • Thiếu log: không biết ai đăng nhập, plugin nào đổi file, lỗi 500 bắt đầu từ lúc nào.

Hardening tốt là xếp nhiều lớp phòng thủ. Không có lớp nào tuyệt đối, nhưng mỗi lớp làm giảm xác suất và tác động của sự cố.

2. Bước 1: Kiểm kê hiện trạng bằng WP-CLI

Trước khi sửa, hãy ghi baseline. Trên server, vào thư mục WordPress rồi chạy:

cd /var/www/example.com/public
wp core version
wp plugin list
wp theme list
wp user list --fields=ID,user_login,roles,user_email
wp option get siteurl
wp option get home

Output mẫu:

+-------------------+----------+-----------+---------+
| name              | status   | update    | version |
+-------------------+----------+-----------+---------+
| wordpress-seo     | active   | none      | 24.0    |
| contact-form-7    | active   | available | 5.9.8   |
| unknown-uploader  | active   | none      | 1.0     |
+-------------------+----------+-----------+---------+

Nếu thấy plugin lạ, không có nguồn rõ ràng, hoặc plugin không được cập nhật nhiều năm, đừng xóa vội trên production. Hãy chụp backup, kiểm tra staging và xác nhận plugin có thật sự đang được dùng không.

3. Bước 2: Bảo vệ tài khoản quản trị

Tài khoản admin là lớp đầu tiên. Checklist tối thiểu:

  • Mỗi người dùng có tài khoản riêng, không dùng chung.
  • Không dùng username dễ đoán như admin cho tài khoản xuất bản hằng ngày nếu có thể đổi quy trình.
  • Bật 2FA cho administrator/editor.
  • Giảm quyền user không cần thiết: author không nên là admin.
  • Xóa hoặc khóa user cũ của nhân sự đã nghỉ.

Kiểm tra user admin bằng WP-CLI:

wp user list --role=administrator --fields=ID,user_login,user_email,user_registered
wp user list --role=editor --fields=ID,user_login,user_email

Đổi role user nếu cần:

wp user set-role alice editor

Lệnh trên chuyển user alice sang role editor. Chỉ chạy sau khi đã xác nhận user đó không cần quyền cài plugin, sửa theme hoặc thay đổi cấu hình site.

4. Bước 3: Cập nhật core, plugin, theme theo quy trình an toàn

Không cập nhật bừa trên production lúc traffic cao. Quy trình đề xuất:

  1. Backup database và files.
  2. Clone sang staging hoặc tạo snapshot VM/container.
  3. Cập nhật trên staging, test login, form, checkout, cache, sitemap, bài viết.
  4. Ghi danh sách thay đổi và rollback plan.
  5. Cập nhật production trong maintenance window.

Lệnh kiểm tra update:

wp core check-update
wp plugin list --update=available
wp theme list --update=available

Cập nhật từng plugin quan trọng:

wp plugin update wordpress-seo
wp plugin update contact-form-7

Sau update, kiểm tra lỗi PHP:

tail -n 100 /var/log/nginx/error.log
tail -n 100 /var/log/php*-fpm.log

Nếu website dùng cache/CDN, purge cache sau khi xác nhận không có lỗi.

5. Bước 4: File permission đúng cho Linux host

File permission sai là lỗi rất phổ biến. Mục tiêu: web server đọc được WordPress, chỉ ghi ở nơi cần ghi như wp-content/uploads, không cho ghi toàn bộ codebase nếu không cần.

Ví dụ với user deploy là deploy, group web server là www-data:

cd /var/www/example.com/public
sudo chown -R deploy:www-data .
sudo find . -type d -exec chmod 755 {} \;
sudo find . -type f -exec chmod 644 {} \;
sudo chmod 640 wp-config.php
sudo find wp-content/uploads -type d -exec chmod 775 {} \;
sudo find wp-content/uploads -type f -exec chmod 664 {} \;

Giải thích nhanh:

  • 755 cho thư mục: owner ghi, người khác đọc/đi qua.
  • 644 cho file: owner ghi, web server đọc.
  • wp-config.php chứa secret nên chặt hơn.
  • uploads cần ghi vì WordPress upload media.

Không dùng chmod -R 777. Đây là cách sửa nhanh nhưng mở cửa cho attacker ghi file PHP nếu khai thác được một plugin upload.

6. Bước 5: Hardening wp-config.php

Kiểm tra wp-config.php có secret key đầy đủ và debug tắt trên production:

grep -E "AUTH_KEY|SECURE_AUTH_KEY|LOGGED_IN_KEY|NONCE_KEY|WP_DEBUG|DISALLOW_FILE_EDIT" wp-config.php

Khuyến nghị production:

define('WP_DEBUG', false);
define('DISALLOW_FILE_EDIT', true);
define('DISALLOW_FILE_MODS', false);
define('FORCE_SSL_ADMIN', true);

DISALLOW_FILE_EDIT tắt trình sửa file theme/plugin trong admin, giảm rủi ro nếu tài khoản admin bị chiếm. DISALLOW_FILE_MODS có thể bật true trong môi trường GitOps, nhưng nếu team vẫn cập nhật plugin qua admin thì cần cân nhắc quy trình.

7. Bước 6: Giới hạn wp-login.php và xmlrpc.php

wp-login.php thường bị brute force. Nếu admin chỉ đăng nhập từ IP cố định hoặc VPN, có thể giới hạn tại Nginx:

location = /wp-login.php {
    allow 203.0.113.10;
    allow 10.0.0.0/8;
    deny all;
    include fastcgi_params;
    fastcgi_pass unix:/run/php/php8.2-fpm.sock;
}

Nếu không thể giới hạn IP vì nhiều biên tập viên di động, dùng rate limit hoặc plugin bảo mật có giới hạn login attempt + 2FA.

Với xmlrpc.php, nếu không dùng Jetpack/app mobile/XML-RPC publishing, có thể chặn:

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

Lưu ý: một số automation hoặc app cũ cần XML-RPC. Hãy xác nhận trước khi chặn.

8. Bước 7: WAF, CDN và security headers

WAF/CDN giúp chặn bot, exploit phổ biến và giảm tải origin. Bật các rule cơ bản:

  • Managed WAF rules cho WordPress/PHP.
  • Rate limit cho /wp-login.php, /xmlrpc.php, endpoint form.
  • Bot fight mode hoặc challenge cho request bất thường.
  • Chặn quốc gia/vùng nếu website chỉ phục vụ thị trường cụ thể và team chấp nhận trade-off.

Security headers Nginx mẫu:

add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;

Content-Security-Policy hữu ích nhưng cần test kỹ vì WordPress/plugin thường dùng nhiều script inline. Đừng bật CSP quá chặt trực tiếp trên production nếu chưa chạy report-only.

9. Bước 8: Backup phải khôi phục được

Backup không được test restore thì chỉ là hy vọng. Một backup tối thiểu gồm:

  • Database dump.
  • wp-content/uploads.
  • Theme/plugin custom nếu không có trong Git.
  • wp-config.php hoặc secret được quản lý an toàn.

Database backup mẫu:

mkdir -p /backup/wordpress/$(date +%F)
wp db export /backup/wordpress/$(date +%F)/site.sql
rsync -a wp-content/uploads/ /backup/wordpress/$(date +%F)/uploads/

Test restore vào staging:

wp db import /backup/wordpress/2026-07-15/site.sql
wp search-replace 'https://example.com' 'https://staging.example.com' --skip-columns=guid
wp cache flush

Sau restore, kiểm tra login, media, permalink, form, sitemap và một vài bài viết cũ.

10. Bước 9: Audit log và phát hiện thay đổi bất thường

Website production cần biết “ai làm gì, khi nào”. Các sự kiện nên log:

  • Đăng nhập thất bại/thành công của admin/editor.
  • Tạo/sửa/xóa user.
  • Cài, kích hoạt, vô hiệu hóa plugin/theme.
  • Sửa file trong theme/plugin.
  • Thay đổi option quan trọng: siteurl, home, permalink, SMTP, redirect.

Ở tầng Linux, có thể kiểm tra file PHP thay đổi gần đây:

find . -type f -name '*.php' -mtime -3 -print

Output bất thường có thể là file PHP mới trong uploads:

./wp-content/uploads/2026/07/cache-update.php

Uploads không nên chứa PHP executable. Với Nginx, chặn PHP trong uploads:

location ~* /wp-content/uploads/.*\.php$ {
    deny all;
}

11. Bước 10: Malware scan và integrity check

WP-CLI có thể kiểm tra core file:

wp core verify-checksums

Nếu output báo file core bị sửa:

Warning: File doesn't verify against checksum: wp-includes/version.php
Error: WordPress installation doesn't verify against checksums.

Đừng chỉ ghi đè ngay. Hãy backup hiện trạng để điều tra, kiểm tra timestamp, access log, user admin gần nhất, plugin mới cài. Sau đó có thể reinstall core sạch:

wp core download --force --skip-content

Với plugin/theme premium không có checksum public, cần so với bản gốc từ vendor hoặc repo nội bộ.

12. Troubleshooting lỗi thường gặp sau hardening

Không upload được ảnh sau khi siết permission

Kiểm tra owner/group và quyền thư mục uploads:

ls -ld wp-content/uploads
sudo -u www-data test -w wp-content/uploads && echo writable || echo not-writable

Nếu không writable, chỉnh lại group hoặc ACL. Không mở toàn bộ webroot thành 777.

Plugin update báo cần FTP credentials

WordPress không có quyền ghi vào thư mục plugin. Trong production GitOps, đây có thể là chủ ý. Nếu muốn update qua admin, cần cấu hình owner/group đúng. Có thể thêm:

define('FS_METHOD', 'direct');

Nhưng chỉ thêm khi permission đã được thiết kế an toàn.

Admin bị 403 sau khi giới hạn wp-login.php

Kiểm tra IP thực tế sau CDN/proxy. Nginx có thể thấy IP của Cloudflare/load balancer thay vì IP người dùng. Cần cấu hình real_ip_header và trusted proxy đúng.

REST API hoặc editor bị lỗi

Một số rule WAF/security plugin chặn REST API làm Block Editor lỗi. Kiểm tra browser console, access log, WAF event log và allowlist endpoint cần thiết thay vì tắt toàn bộ WAF.

13. Checklist nghiệm thu WordPress security hardening

  • Administrator/editor đã bật 2FA hoặc có chính sách mật khẩu mạnh.
  • Không còn user cũ, user lạ hoặc role cao hơn nhu cầu.
  • Core/plugin/theme đã kiểm tra update và có quy trình staging trước production.
  • File permission không dùng 777; uploads được ghi, codebase không ghi rộng.
  • DISALLOW_FILE_EDIT bật trong production.
  • wp-login.php/xmlrpc.php có rate limit, allowlist hoặc rule WAF phù hợp.
  • Backup database + uploads chạy định kỳ và đã test restore.
  • Audit log ghi nhận login, user, plugin/theme, option quan trọng.
  • Chặn PHP execution trong uploads.
  • Đã verify checksum core và điều tra file PHP bất thường.
  • Homepage, bài viết, form, sitemap, cache, đăng nhập admin vẫn hoạt động sau thay đổi.

14. Lab thực hành

  1. Dựng một WordPress lab bằng Docker hoặc VM Linux.
  2. Tạo 3 user với role administrator, editor, author; thử giảm quyền user không cần thiết.
  3. Dùng WP-CLI liệt kê plugin/theme và cập nhật một plugin trên staging.
  4. Áp permission 755/644, sau đó test upload media.
  5. Bật DISALLOW_FILE_EDIT và xác nhận menu Theme File Editor biến mất.
  6. Chặn PHP trong uploads rồi thử truy cập một file .php giả lập trong uploads.
  7. Export database, restore sang site staging và chạy search-replace URL.

Kết luận

WordPress security hardening hiệu quả nhất khi được xem như một runbook vận hành, không phải một lần cấu hình. Hãy bắt đầu từ tài khoản, cập nhật, permission, backup và logging; sau đó thêm WAF, rate limit, integrity check và quy trình staging. Khi có checklist rõ ràng, team vừa giảm rủi ro bị hack, vừa giữ website ổn định cho nội dung, SEO và hoạt động kinh doanh.

Tác giả: Mạnh Hoàng

Tôi là Hoàng Mạnh, người sáng lập blog SysadminSkills.com. Tôi viết về quản trị hệ thống, bảo mật máy chủ, DevOps và cách ứng dụng AI để tự động hóa công việc IT. Blog này là nơi tôi chia sẻ những gì đã học được từ thực tế – đơn giản, ngắn gọn và áp dụng được ngay.