PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / 2.7.0
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO v2.7.0
2.7.0 2.6.0 2.5.0 2.4.0 2.3.0 2.2.0 2.1.1 2.1.0 2.0.2 2.0.1 2.0.0 1.32.0 1.31.0 1.30.0 1.29.0 1.28.0 1.27.0 1.26.0 1.25.0 trunk 1.0.0 1.0.1 1.0.2 1.1.0 1.10.0 All 48 releases
thinkrank / includes / api / traits / trait-csrf-protection.php

trait-csrf-protection.php in ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO 2.7.0, at includes/api/traits/trait-csrf-protection.php

183 lines 5.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * CSRF Protection Trait
4 *
5 * Provides Cross-Site Request Forgery (CSRF) protection for API endpoints
6 * by implementing WordPress nonce verification. This trait ensures that all
7 * state-changing operations require valid nonce tokens to prevent unauthorized
8 * requests from malicious websites.
9 *
10 * @package ThinkRank
11 * @subpackage API\Traits
12 * @since 1.0.0
13 */
14
15 declare(strict_types=1);
16
17 namespace ThinkRank\API\Traits;
18
19 use WP_REST_Request;
20 use WP_Error;
21
22 // Prevent direct access
23 if (!defined('ABSPATH')) {
24 exit;
25 }
26
27 /**
28 * CSRF Protection Trait
29 *
30 * Implements WordPress nonce-based CSRF protection for REST API endpoints.
31 * This trait provides methods to verify request authenticity and prevent
32 * cross-site request forgery attacks.
33 *
34 * @since 1.0.0
35 */
36 trait CSRF_Protection {
37
38 /**
39 * Verify request nonce for CSRF protection
40 *
41 * Checks for valid WordPress nonce in either the X-WP-Nonce header
42 * (preferred for REST API) or as a request parameter fallback.
43 *
44 * @since 1.0.0
45 *
46 * @param WP_REST_Request $request Request object
47 * @return bool Whether nonce is valid
48 */
49 private function verify_request_nonce(WP_REST_Request $request): bool {
50 // Get nonce from header (preferred method for REST API)
51 $nonce = $request->get_header('X-WP-Nonce');
52
53 // Fallback to parameter if header not present
54 if (!$nonce) {
55 $nonce = $request->get_param('_wpnonce');
56 }
57
58 // Verify nonce against WordPress REST API nonce action
59 if (!$nonce || !wp_verify_nonce($nonce, 'wp_rest')) {
60 return false;
61 }
62
63 return true;
64 }
65
66 /**
67 * Check CSRF permissions for state-changing operations
68 *
69 * Combines user capability checks with CSRF protection to ensure
70 * both authorization and request authenticity.
71 *
72 * @since 1.0.0
73 *
74 * @param WP_REST_Request $request Request object
75 * @return bool|WP_Error Permission status or error
76 */
77 public function check_csrf_permissions(WP_REST_Request $request) {
78 // Check if user is logged in
79 if (!is_user_logged_in()) {
80 return new WP_Error(
81 'rest_forbidden',
82 __('You must be logged in to perform this action.', 'thinkrank'),
83 ['status' => 401]
84 );
85 }
86
87 // Check user capability
88 if (!current_user_can('edit_posts')) {
89 return new WP_Error(
90 'rest_forbidden',
91 __('You do not have permission to perform this action.', 'thinkrank'),
92 ['status' => 403]
93 );
94 }
95
96 // Verify CSRF protection
97 if (!$this->verify_request_nonce($request)) {
98 return new WP_Error(
99 'rest_forbidden',
100 __('Invalid security token. Please refresh the page and try again.', 'thinkrank'),
101 ['status' => 403]
102 );
103 }
104
105 return true;
106 }
107
108 /**
109 * Check CSRF permissions for management operations
110 *
111 * Higher privilege check for operations that require content management
112 * capabilities, such as publishing or managing site-wide settings.
113 *
114 * @since 1.0.0
115 *
116 * @param WP_REST_Request $request Request object
117 * @return bool|WP_Error Permission status or error
118 */
119 public function check_manage_csrf_permissions(WP_REST_Request $request) {
120 // Check if user is logged in
121 if (!is_user_logged_in()) {
122 return new WP_Error(
123 'rest_forbidden',
124 __('You must be logged in to perform this action.', 'thinkrank'),
125 ['status' => 401]
126 );
127 }
128
129 // Check higher privilege for management operations
130 if (!current_user_can('publish_posts')) {
131 return new WP_Error(
132 'rest_forbidden',
133 __('You do not have permission to manage this resource.', 'thinkrank'),
134 ['status' => 403]
135 );
136 }
137
138 // Verify CSRF protection
139 if (!$this->verify_request_nonce($request)) {
140 return new WP_Error(
141 'rest_forbidden',
142 __('Invalid security token. Please refresh the page and try again.', 'thinkrank'),
143 ['status' => 403]
144 );
145 }
146
147 return true;
148 }
149
150 /**
151 * Check read-only permissions (no CSRF required)
152 *
153 * For GET operations that don't change state, CSRF protection
154 * is not required, but basic authentication is still needed.
155 *
156 * @since 1.0.0
157 *
158 * @param WP_REST_Request $request Request object
159 * @return bool|WP_Error Permission status or error
160 */
161 public function check_read_permissions(WP_REST_Request $request) {
162 // Check if user is logged in
163 if (!is_user_logged_in()) {
164 return new WP_Error(
165 'rest_forbidden',
166 __('You must be logged in to access this resource.', 'thinkrank'),
167 ['status' => 401]
168 );
169 }
170
171 // Basic read capability
172 if (!current_user_can('read')) {
173 return new WP_Error(
174 'rest_forbidden',
175 __('You do not have permission to access this resource.', 'thinkrank'),
176 ['status' => 403]
177 );
178 }
179
180 return true;
181 }
182 }
183