Bài viết này trình bày hai trường hợp phổ biến cần log ngay tại thời điểm phát sinh lỗi 403, giúp Init Sentinel ghi nhận đúng ngữ cảnh, đúng hành vi và tránh log thừa.
Nguyên tắc: Log tại điểm quyết định, không log tại điểm trả kết quả
Một lỗi 403 có thể xuất hiện ở nhiều lớp, nhưng Init Sentinel chỉ quan tâm đến nơi hành vi bị đánh giá là không hợp lệ. Log quá muộn sẽ mất ngữ cảnh, log quá sớm sẽ tạo nhiễu.
Với REST API, hai vị trí đáng log nhất là permission_callback và các nhánh kiểm tra quyền bên trong callback.
Trường hợp 1: Bị chặn quyền ngay trong permission_callback
permission_callback là lớp bảo vệ đầu tiên của REST API. Nếu request bị từ chối tại đây, nghĩa là hành vi đó không bao giờ nên đi sâu hơn vào hệ thống.
Đây là nơi lý tưởng để log một security event với action rõ ràng và endpoint cụ thể.
// Create post
register_rest_route('init-api/v1', '/create-post', [
'methods' => 'POST',
'callback' => 'init_rest_create_post',
'permission_callback' => function () {
if ( ! current_user_can('publish_posts') ) {
init_html_log_security_event(
'api/create-post',
'permission_denied_create_post',
403
);
return new WP_Error(
'rest_forbidden',
__('You do not have permission to create posts.', 'init'),
['status' => 403]
);
}
return true;
},
]);
Ở ví dụ này, log được ghi đúng thời điểm quyền bị từ chối, trước khi WordPress trả response, giúp Init Sentinel ghi nhận chính xác hành vi bị chặn.
Trường hợp 2: Bị chặn quyền bên trong callback REST
Không phải endpoint nào cũng có thể xác định quyền truy cập ngay từ permission_callback. Với các endpoint đọc hoặc chỉnh sửa tài nguyên cụ thể, quyền thường phụ thuộc vào dữ liệu đầu vào.
Trong trường hợp này, log nên được đặt ngay tại nhánh kiểm tra quyền thất bại bên trong callback.
// Get post
function init_rest_get_post( WP_REST_Request $request ) {
$post_id = absint( $request->get_param('post_id') );
if ( ! $post_id || get_post_type( $post_id ) !== 'post' ) {
return new WP_REST_Response( [ 'message' => 'Invalid post ID.' ], 400 );
}
if ( ! current_user_can( 'edit_post', $post_id ) ) {
init_html_log_security_event(
'api/get-post',
'unauthorized_get_post',
403
);
return new WP_REST_Response( [ 'message' => 'Unauthorized' ], 403 );
}
$post = get_post( $post_id );
$data = [
'ID' => $post->ID,
'post_title' => $post->post_title,
'post_content' => $post->post_content,
'status' => $post->post_status,
'author' => $post->post_author,
'thumbnail' => get_the_post_thumbnail_url( $post_id, 'full' ),
];
return rest_ensure_response( $data );
}
Ở đây, log chỉ được ghi khi xác định rõ rằng user không có quyền truy cập post cụ thể, tránh ghi log cho các lỗi dữ liệu không liên quan đến bảo mật.
Vì sao không log ở template_redirect hay rest_pre_serve_request
Các hook tổng quát như template_redirect hoặc rest_pre_serve_request không có đủ ngữ cảnh về hành vi và ý định của request.
Log tại đó thường chỉ cho biết “có 403 xảy ra”, nhưng không cho biết “vì sao” và “liên quan đến hành động nào”.
Đặt tên endpoint và action để log có giá trị
Endpoint và action không phải để hiển thị cho người dùng mà để phân tích hành vi. Chúng nên ổn định, ngắn gọn và mang ý nghĩa nghiệp vụ.
Ví dụ tốt là permission_denied_create_post hoặc unauthorized_get_post, vì chúng mô tả rõ hành vi bị chặn.
Kết luận
Ghi log 403 đúng thời điểm giúp Init Sentinel trở thành hệ thống quan sát hành vi, không chỉ là bộ đếm lỗi.
Ở bài tiếp theo, chúng ta sẽ đi vào việc xoay log, dọn log và giữ bảng init_sentinel_security_log luôn nhẹ dù chạy lâu dài.
Bình luận