Sử dụng Nonce để tăng cường tính bảo mật trong WordPress

Trong khi xây dựng 1 website thì vấn đề quan trọng không thể thiếu đó là . Có rất nhiều cách để tăng cường tính trong WordPress. Bạn Thạch cũng đã có bài viết về một số cách trong WordPress. Các bạn có thể xem lại tại đây. Trong bài viết này mình sẽ hướng dẫn thêm cho các bạn cách bảo mật với Nonce, một cách hiệu quả để hạn chế việc tấn công theo kỹ thuật Cross Site Request Forgery (CSRF).

nonce trong wordpress

1. Nonce là gì?

Hiểu đơn giản nó là 1 chuỗi duy nhất được tạo ra bởi WordPress cho mỗi người dùng. Nó giúp bảo vệ website khỏi những request tự tạo với mục đích xấu.

Ví dụ như thế này cho các bạn dễ hiểu. Giả sử mình có 1 link dùng để xóa bài viết như thế này:

1
<a href="http://domain/?action=delete&id=1">Xóa</a>

Khi mình click vào link thì bài viết sẽ được xóa bình thường. Ok, không vấn đề gì. Nhưng vấn đề xảy ra nếu người dùng có dụng ý xấu. Họ sử dụng 1số thủ thuật nào đó để thông qua quyền của mình và thực hiện việc chạy lại đường link trên với 1 id khác thì sao? Bài viết khác có thể bị xóa cho dù mình không click vào nút xóa. Bây giờ các bạn đã thấy vấn đề rồi chứ. Ngoài ra thì khi dùng form để submit dữ liệu cũng vẫn bị vấn đề trên.

Vậy làm sao để xác định được chính xác 1 request do người dùng thực hiện thông qua click link hay submit form ?

Việc cần làm là chúng ta phải tạo ra thêm 1 nonce cho request và trang xử lý phải xác nhận cái nonce này. Nếu nonce không hợp lệ thì không xử lý request. Làm như vậy thì chúng ta mới xác định được chính xác thao tác đấy(click link, submit form) là thực sự của người dùng tạo ra.

2. Các sử dụng

Như đã nói ở trên nonce là 1 chuỗi vậy chuỗi này được tạo ra như thế nào? Mở file wp_config.php lên và tìm đến 2 hằng NONCE_KEYAUTH_SALT. Các bạn thấy chưa ạ? Một dãy các ký tự đúng không nào? WordPress đã sử dụng dụng 2 hằng này và hash cùng với một số thông số khác sau như action, user id … sau đó cắt ra 1 đoạn để tạo ra nonce đấy.

Cách đơn giản và linh động nhất là các bạn sử dụng hàm wp_create_nonce($action) để tạo nonce và dùng hàm wp_verify_nonce($nonce, $action) để xác nhận.

Giả sử với link xóa bài như bên trên, mình cần tạo ra 1 nonce, đưa nonce này vào query string, bên trang xử lý sẽ xác nhận nonce thông qua query string.

1
2
3
$nonce = wp_create_nonce(' delete_1'); //tạo nonce
echo '<a href="http://domain/?action=delete&id=1&_nonce='.$nonce.'">Xóa</a>';

Các bạn thấy đấy, mình đã tạo thêm 1 nonce với $action truyền vào là delete_1. Và mình đã đưa nó vào query string để verify bên trang xử lý. Tên _nonce các bạn có thể đổi lại tùy ý. Lưu ý: với $action các bạn đặt như thế nào thì trang xử lý các bạn phải verify lại như thế đó.

Bên trang xử lý các bạn chỉ cần xác nhận cái nonce này trước khi xử lý. Không hợp lệ thì ngưng xử lý:

1
2
3
if(!wp_verify_nonce($_GET['_nonce'], 'delete_'.$_GET['id'])) exit();
//code xử lý ở đây ....

Bên trang xử lý chúng ta verify nonce thông qua hàm wp_verify_nonce. Với $nonce là $_GET[‘_nonce’], và $action là ‘delete_’.$_GET[‘id’]. Vì ở trên nonce được tạo từ ‘delete_1′ nên trang xử lý cần verify đúng $action đó theo dạng delete_{id}.

Thực chất hàm này sẽ tạo ra 1 nonce khác theo $action và so sánh nó với nonce get được.

Đơn giản thế thôi, ngoài cách sử dụng trên wordpress còn cung cấp các hàm để tạo và kiểm tra nonce khác để áp dụng vào từng trường hợp cụ thể.

Để tạo nonce cho url, ngoài cách trên ra chúng ta có thể sử dụng thêm hàm wp_nonce_url( $actionurl, $action, $name ) hàm này sẽ trả về cho chúng ta 1 đường dẫn đầy đủ chứa nonce.

Tham số:

  • $actionurl chính là đường dẫn để add nonce vào.
  • $action tương tự trên.
  • $name là tên của nonce, mặc định là _wpnonce

Cũng với ví dụ trên mình sử dùng hàm wp_nonce_url() để tạo:

1
2
3
$nonce_url = wp_nonce_url('http://domain/?action=delete&id=1', 'delete_1');
echo '<a href="'. $nonce_url.' ">Xóa</a>';

Khi xem thì các bạn thấy đường dẫn nó cũng tương tự cách trên, _wpnonce chính là tham số $name mặc định, các bạn muốn đổi thành tên khác thì tùy chỉnh tại tham số này.

1
http://domain/?action=delete&id=1&_wpnonce=e73a52569c

Tiếp tục để tạo nonce cho 1 form các bạn có thể dùng thêm hàm wp_nonce_field( $action, $name, $referer, $echo ). Các tham số như $action và $name thì tương tự trên. Tham số $referer sẽ nhận giá trị true hoặc false, quyết định hiển thị thêm 1 field ẩn chứa đường dẫn hiện tại. $echo cũng nhận giá trị true hoặc false, quyết định hàm wp_nonce_field() sẽ hiển thị hay trả về kết quả.

Khi sử dụng hàm này với $referer là true các bạn sẽ thấy trong form có thêm 2 trường dạng như thế này:

1
2
3
<input type="hidden" id="_nonce" name="_nonce" value="43bc8cf75e" />
<input type="hidden" name="_wp_http_referer" value="/phanmem/ " />

Về cách verify nonce thì WordPress cung cấp thêm cho chúng ta 2 hàm nữa khác là check_admin_referer()check_ajax_referer().

Hàm check_admin_referer() sẽ dùng để verify nonce trong trang quản lý. Hàm này nhận 2 tham số là $action$query_arg với $action thì tương tự, $query_arg chính là $name của nonce. Hàm này sẽ trả về true nếu nonce hợp lệ và ngược lại là false.

Giả sử có 1 form dạng như thế này:

1
2
3
4
5
6
7
<form method="post">
    //.......
   <?php wp_nonce_field( 'myaction','mynonce' ); ?>
</form>

Thì khi verify các bạn làm như sau:

1
2
3
if(!check_admin_referer('myaction', 'mynonce')) die();
 

Hàm check_ajax_referer() sẽ verify nonce thông qua Ajax. Hàm này nhận 3 tham số, 2 tham số đầu là $action$query_arg tương tự hàm trên, với tham số thứ 3 là $die, nếu nonce không hợp lệ, và tham số này set true thì sẽ ngưng xử lý, nếu false thì bỏ qua. Mặc định là true.

Thời gian sống mặc định của 1 nonce là 24 giờ. Các bạn vẫn có thể chỉnh sửa lại thông qua hook nonce_life.

1
add_filter( 'nonce_life', function () { return 4 * HOUR_IN_SECONDS; } );

Hằng HOUR_IN_SECONDS sẽ trả về số giây trên giờ (3600).

3. Lời kết

Mình đã hướng dẫn xong cho các bạn cách bảo mật WordPress với Nonce để hạn chế việc tấn công theo kỹ thuật CSRF trong khi phát triển theme và plugin. Hy vọng với những kiến thức này có thể giúp các bạn bảo vệ website của mình tốt hơn.

Related posts:

Leave a Reply

Your email address will not be published. Required fields are marked *