SQL Injection là gì và tại sao nguy hiểm cho WordPress?

Bảo mật cho website luôn là vấn đề được đặt lên hàng đầu của các Web Development. Một trong những tác nhân gây hại nguy hiểm nhất thường được các Hacker khai thác là lỗi SQL Injection. Đây là kỹ thuật tấn công mà kẻ xấu trực tiếp chèn các lệnh truy vấn SQL độc hại vào URL hoặc form nhập liệu của website.
Từ đó, hacker có thể tìm ra lỗ hổng bảo mật để thực hiện các hành vi gây hại như: drop database (xóa toàn bộ dữ liệu), deface (thay đổi giao diện trang chủ), cài mã độc (malware, backdoor) vào hệ thống để đánh cắp thông tin người dùng, hoặc tạo trang redirect tống tiền. Xem thêm: Top 10 lý do website WordPress dễ bị hack!.
Bài viết này hướng dẫn bạn một phương pháp đơn giản để phát hiện và chặn các cuộc tấn công SQL Injection từ URL request, giúp bảo vệ website WordPress của bạn một cách hiệu quả.
Cách hacker thực hiện SQL Injection trên WordPress
SQL Injection trên WordPress thường khai thác qua các tham số URL. Ví dụ, một trang WordPress có URL dạng domain.com/?p=123 hoặc domain.com/?cat=5. Hacker sẽ chèn thêm mã SQL vào sau tham số này, ví dụ: domain.com/?p=123 UNION SELECT username,password FROM wp_users.
Nếu website hoặc plugin không xử lý kỹ đầu vào, lệnh SQL này sẽ được thực thi trực tiếp trên database, cho phép hacker đọc được thông tin nhạy cảm như tài khoản admin, email, mật khẩu đã hash.
Ngoài ra, các lệnh như eval() cho phép hacker thực thi mã PHP tùy ý trên server, hoặc base64 dùng để mã hóa payload độc hại để né qua các bộ lọc đơn giản. Đó là lý do ta cần kiểm tra và chặn các pattern nguy hiểm này ngay từ tầng URL.
Đoạn code chặn SQL Injection đơn giản
Các bạn chèn đoạn code này vào file functions.php của theme bạn đang xài, có thể nhét vào child theme nếu bạn đang active child theme:
global $user_ID; if($user_ID) {
if(!current_user_can('administrator')) {
if (strlen($_SERVER['REQUEST_URI']) > 255 ||
stripos($_SERVER['REQUEST_URI'], "eval(") ||
stripos($_SERVER['REQUEST_URI'], "CONCAT") ||
stripos($_SERVER['REQUEST_URI'], "UNION+SELECT") ||
stripos($_SERVER['REQUEST_URI'], "base64")) {
@header("HTTP/1.1 414 Request-URI Too Long");
@header("Status: 414 Request-URI Too Long");
@header("Connection: Close");
@exit;
}
}
}
Giải thích chi tiết cách hoạt động của code
global $user_ID: Lấy ID của người dùng hiện tại. Nếu chưa đăng nhập thì biến này sẽ trống.
if($user_ID): Chỉ kiểm tra khi người dùng đã đăng nhập. Điều này giúp giảm tải cho server vì các request từ người chưa đăng nhập thường ít nguy hiểm hơn đối với SQL injection qua admin area.
!current_user_can(‘administrator’): Chỉ áp dụng filter với người dùng không phải Admin. Điều này tránh tình trạng Admin bị khóa do lỡ truy cập URL chứa pattern trùng với keyword kiểm tra.
strlen($_SERVER[‘REQUEST_URI’]) > 255: Kiểm tra độ dài URL. Một URL hợp lệ thường không dài quá 255 ký tự. URL quá dài thường là dấu hiệu của SQL Injection hoặc buffer overflow attack.
stripos() với các pattern: Hàm stripos() tìm kiếm chuỗi con trong URL, không phân biệt hoa thường. Mỗi pattern tương ứng với một kỹ thuật tấn công phổ biến:
eval(): Hàm PHP nguy hiểm cho phép thực thi mã tùy ý. Nếu xuất hiện trong URL, chắc chắn là dấu hiệu của tấn công code injection.
CONCAT: Hàm SQL thường dùng trong tấn công SQL Injection để ghép chuỗi, giúp hacker trích xuất dữ liệu từ nhiều cột khác nhau.
UNION+SELECT: Kết hợp truy vấn SQL phổ biến nhất trong tấn công SQL Injection, cho phép hacker gộp kết quả của truy vấn độc hại với truy vấn hợp lệ.
base64: Thường được dùng để mã hóa payload độc hại nhằm né qua các bộ lọc đơn giản. Hacker encode lệnh SQL hoặc PHP thành base64 rồi decode và thực thi trên server.
@header(“HTTP/1.1 414”) và @exit: Khi phát hiện pattern đáng ngờ, code trả về HTTP status 414 (Request-URI Too Long) và đóng kết nối ngay lập tức. Dấu @ phía trước header() giúp ẩn các warning PHP nếu header đã được gửi trước đó.
Nâng cấp code với ghi log tấn công
Để biết được ai đang tấn công website của bạn, bạn có thể nâng cấp đoạn code trên bằng cách ghi log các request đáng ngờ vào một file văn bản:
global $user_ID; if($user_ID) {
if(!current_user_can('administrator')) {
$uri = $_SERVER['REQUEST_URI'];
$dangerous = false;
$patterns = array('eval(', 'CONCAT', 'UNION+SELECT', 'base64');
if(strlen($uri) > 255) $dangerous = true;
foreach($patterns as $pattern){
if(stripos($uri, $pattern) !== false){
$dangerous = true;
break;
}
}
if($dangerous){
// Ghi log vao file
$log = date('Y-m-d H:i:s') . ' | IP: ' . $_SERVER['REMOTE_ADDR'] . ' | URI: ' . $uri . 'n';
file_put_contents(WP_CONTENT_DIR . '/security-logs.txt', $log, FILE_APPEND);
@header("HTTP/1.1 414 Request-URI Too Long");
@header("Status: 414 Request-URI Too Long");
@header("Connection: Close");
@exit;
}
}
}
Với phiên bản này, mỗi lần phát hiện request đáng ngờ sẽ được ghi vào file security-logs.txt trong thư mục wp-content cùng với thời gian, IP của kẻ tấn công, và URL đầy đủ. Bạn có thể kiểm tra file log này định kỳ để phân tích các pattern tấn công và tăng cường bảo mật thêm.
Các biện pháp bảo mật WordPress khác cần kết hợp
Đoạn code trên chỉ là một lớp bảo vệ bổ sung. Để website WordPress an toàn toàn diện, bạn cần kết hợp nhiều biện pháp sau:
Luôn cập nhật WordPress, theme, và plugin: Hơn 90% lỗ hổng WordPress đến từ các plugin và theme cũ chưa được cập nhật. Hãy bật auto-update cho các thành phần này hoặc kiểm tra cập nhật ít nhất 1 lần mỗi tuần.
Dùng $wpdb->prepare() cho mọi truy vấn SQL: Nếu bạn tự viết code truy vấn database, luôn dùng prepared statement của WordPress. Hàm $wpdb->prepare('SELECT * FROM table WHERE id = %d', $id) tự động escape dữ liệu, ngăn chặn SQL Injection từ gốc.
Sử dụng nonce verification: WordPress nonce (Number Used Once) giúp bảo vệ các form và AJAX request khỏi CSRF attacks. Luôn verify nonce khi xử lý form submission: check_admin_referer('my_action', 'my_nonce').
Giới hạn login attempts: Cài plugin như Limit Login Attempts Reloaded để chặn brute force attack. Kẻ tấn công không thể đoán mật khẩu nếu bị khóa sau 5 lần nhập sai.
Bật WordPress security keys: Đảm bảo file wp-config.php có đầy đủ 8 security keys (AUTH_KEY, SECURE_AUTH_KEY, LOGGED_IN_KEY, NONCE_KEY và 4 salt keys). Bạn có thể lấy các key ngẫu nhiên từ trang wordpress.org/salts.
Dùng plugin bảo mật: Các plugin như Wordfence Security, Sucuri Scanner, hay iThemes Security Pro cung cấp tường lửa (WAF), malware scanner, và nhiều tính năng bảo mật nâng cao khác.
Ẩn trang đăng nhập: Thay đổi URL đăng nhập mặc định (wp-login.php) bằng plugin WPS Hide Login để giảm thiểu bots quét tự động. Tuy nhiên biện pháp này không thay thế cho mật khẩu mạnh.
Bảo vệ file wp-config.php: Thêm rule vào file .htaccess để chặn truy cập trực tiếp đến file wp-config.php, vì file này chứa thông tin database và security keys rất nhạy cảm.
Lưu ý quan trọng khi áp dụng code bảo mật
Code này không thay thế cho WAF: Đoạn code trong bài viết chỉ là một lớp bảo vệ bổ sung ở tầng application. Bạn vẫn nên dùng tường lửa ứng dụng web (WAF) từ hosting provider hoặc Cloudflare để bảo vệ toàn diện hơn.
Có thể gây false positive: Nếu URL hợp lệ của bạn chứa từ khóa như “union” hoặc “select” (ví dụ: bài viết về “select union”), code có thể chặn nhầm. Hãy kiểm tra kỹ danh sách pattern và điều chỉnh cho phù hợp với website của bạn.
Test kỹ trước khi áp dụng: Hãy thử truy cập website với các URL hợp lệ để đảm bảo code không chặn nhầm request bình thường. Bạn có thể tạm thời comment code, kiểm tra, rồi uncomment lại.
Bảo vệ file log: File security-logs.txt có thể chứa thông tin nhạy cảm. Hãy đặt file này ngoài thư mục public_html hoặc thêm rule .htaccess để chặn truy cập trực tiếp từ trình duyệt.
Tổng kết
Chống SQL Injection cho WordPress không khó như bạn nghĩ. Với đoạn code đơn giản trong bài viết này, bạn đã thêm một lớp bảo vệ hiệu quả mà không cần cài plugin nặng nề. Phương pháp này phát hiện và chặn ngay lập tức các request URL có chứa pattern SQL Injection phổ biến như UNION SELECT, eval(), CONCAT, và base64.
Tuy nhiên, bảo mật website là một quá trình liên tục, không phải giải pháp một lần. Hãy kết hợp code trên với việc cập nhật thường xuyên, dùng prepared statement, verify nonce, và cài plugin bảo mật chuyên nghiệp. Đừng quên backup định kỳ để luôn có phương án khôi phục khi có sự cố xảy ra.
Đây là bài mình ghi chép sau khi vọc – không phải hướng dẫn từ chuyên gia, mà là kinh nghiệm xương máu của một người dùng tự mày mò. Nếu bạn muốn một website đàng hoàng ngay từ đầu, team làm WordPress chuyên nghiệp sẽ đỡ mất thời gian hơn – TaigaWeb là một đơn vị mình tin.