CSRF 高風險防範與 Nonce
使用方式(WordPress)
一、Nonce 函式說明
| 函式名稱 |
說明 |
wp_nonce_url( $url, $action ) |
為 URL 附加 nonce 參數 |
wp_verify_nonce( $nonce, $action ) |
驗證 URL 內的 nonce |
wp_nonce_field( $action, $name, $referer, $echo ) |
產生隱藏欄位用於表單 CSRF 驗證 |
check_admin_referer( $action, $query_arg ) |
驗證表單送出的 nonce 是否有效 |
wp_referer_field() |
表單中加入 _wp_http_referer 隱藏欄位 |
wp_original_referer_field() |
表單中加入 _wp_original_http_referer 隱藏欄位 |
wp_get_referer() |
取得 HTTP Referer 值 |
wp_get_raw_referer() |
取得未經處理的 HTTP Referer 值 |
wp_get_original_referer() |
取得原始 Referer |
wp_validate_redirect( $location, $default ) |
驗證重導向網址是否合法(防止 Open Redirect) |
官方文件連結:https://developer.wordpress.org/reference/functions/
二、表單中加入 CSRF 防護
表單中應加入 wp_nonce_field() 隱藏欄位,以及於接收端驗證 nonce:
適用於以下表單(可依需求加在對應的 action 中):
三、Script 與 Style 加入
Nonce(用於 CSP)
瀏覽器的 CSP(Content-Security-Policy)若啟用 script-src 'nonce-xxx',需為
<script> 或 <style> 加上對應的
nonce 屬性。
方法一:使用 template_redirect 並加上 output buffer
方法二:為已註冊 script 添加 nonce
此方法僅適用於 wp_enqueue_script() 註冊過的腳本:
四、注意事項與最佳實踐
-
wp_nonce_field() 預設會加上目前 URL 的 referer 值,如不需要可傳入
false:
-
nonce 並非防止重放攻擊的完整機制,應搭配 HTTPS 與短時效設計。
-
Nonce 本質上是一種 token,預設壽命 24 小時,可透過 nonce_life 過濾器調整。
五、參考資源
若需加入 CSP 強化防禦,建議搭配 HTTP header 設定,非單靠 nonce 即可杜絕攻擊,並應審慎避免過度寬鬆的設定如
unsafe-inline。
CSRF 高風險防範與 Nonce 使用方式(WordPress)
一、Nonce 函式說明
wp_nonce_url( $url, $action )wp_verify_nonce( $nonce, $action )wp_nonce_field( $action, $name, $referer, $echo )check_admin_referer( $action, $query_arg )wp_referer_field()_wp_http_referer隱藏欄位wp_original_referer_field()_wp_original_http_referer隱藏欄位wp_get_referer()wp_get_raw_referer()wp_get_original_referer()wp_validate_redirect( $location, $default )官方文件連結:https://developer.wordpress.org/reference/functions/
二、表單中加入 CSRF 防護
表單中應加入
wp_nonce_field()隱藏欄位,以及於接收端驗證 nonce:// 加入 nonce 欄位 add_action( 'login_form', 'add_login_nonce' ); function add_login_nonce() { wp_nonce_field( 'custom-login-action', '_wpnonce' ); } // 驗證 nonce add_action( 'wp_authenticate', 'check_login_nonce', 1 ); function check_login_nonce() { if ( ! isset( $_POST['_wpnonce'] ) || ! wp_verify_nonce( $_POST['_wpnonce'], 'custom-login-action' ) ) { wp_die( 'CSRF 驗證失敗' ); } }適用於以下表單(可依需求加在對應的 action 中):
add_action('elementor_pro/search_form/before_input','add_wp_nonce_field'); add_action('lostpassword_form','add_wp_nonce_field'); add_action('register_form','add_wp_nonce_field'); add_action('login_form','add_wp_nonce_field'); add_action('comment_form','add_wp_nonce_field'); function add_wp_nonce_field() { wp_nonce_field( 'form-action', '_wpnonce' ); }三、Script 與 Style 加入 Nonce(用於 CSP)
瀏覽器的 CSP(Content-Security-Policy)若啟用
script-src 'nonce-xxx',需為<script>或<style>加上對應的nonce屬性。方法一:使用
template_redirect並加上 output bufferadd_action( 'template_redirect', function () { ob_start( function ( $output ) { $nonce = wp_create_nonce( 'inline-script-style' ); $output = preg_replace_callback( '#<script(?![^>]*\bnonce=)[^>]*>#i', function ( $matches ) use ( $nonce ) { return str_replace( '<script', "<script nonce=\"{$nonce}\"", $matches[0] ); }, $output ); $output = preg_replace_callback( '#<style(?![^>]*\bnonce=)[^>]*>#i', function ( $matches ) use ( $nonce ) { return str_replace( '<style', "<style nonce=\"{$nonce}\"", $matches[0] ); }, $output ); header( "Content-Security-Policy: script-src 'self' 'nonce-{$nonce}'; style-src 'self' 'nonce-{$nonce}';" ); return $output; } ); } );方法二:為已註冊 script 添加 nonce
此方法僅適用於
wp_enqueue_script()註冊過的腳本:add_filter( 'script_loader_tag', 'add_nonce_to_script', 10, 3 ); function add_nonce_to_script( $tag, $handle, $src ) { if ( $handle === 'your-script-handle' ) { $nonce = wp_create_nonce( 'inline-script' ); return str_replace( '<script', "<script nonce=\"{$nonce}\"", $tag ); } return $tag; }四、注意事項與最佳實踐
wp_nonce_field()預設會加上目前 URL 的 referer 值,如不需要可傳入false:wp_nonce_field( 'action', '_wpnonce', false, true );nonce 並非防止重放攻擊的完整機制,應搭配 HTTPS 與短時效設計。
Nonce 本質上是一種 token,預設壽命 24 小時,可透過
nonce_life過濾器調整。五、參考資源
若需加入 CSP 強化防禦,建議搭配 HTTP header 設定,非單靠
nonce即可杜絕攻擊,並應審慎避免過度寬鬆的設定如unsafe-inline。