如何在 WordPress 中使用 Cloudflare Turnstile 防止垃圾留言?

架設網站讓訪客能自在、方便的留言與登入網站是與訪客、會員、訂閱者們保持互動的最好作法。然而,這些功能一開啟就得面對機器人與駭客的持續侵擾。

導入 CAPTCHA 驗證機制,雖然可以防止大多數的垃圾留言與嘗試登入,卻會造成其他的問題。訪客為了完成 CAPTCHA 驗證,每次留言、登入都得要重複的輸入英數字、選擇圖案,不僅耗費時間也大幅影響網頁載入的效率。

而人類每天花費在 CAPTCHA 的驗證時間加總超過 500 年。

Cloudflare 為了解決這個問題,提供訪客更好的體驗、更健全的隱私權,提出了替代 CAPTCHA 的方案 – Cloudflare Turnstile。能夠自動辨識是否為真人、不騷擾訪客,並且免費提供。

為什麼要在網站中使用人機驗證功能?

垃圾郵件、垃圾留言不僅對 WordPress 網站,對任何網站來說都是個大問題,對於疏於管理的網站來說,可能會讓管理員、訪客點擊到不安全的連結造成資安危機。

當一個網站充滿了許多垃圾留言,不僅會影響網站體驗、訪客觀感,時間久了更會損害網站的 SEO。

許多站長會採用 Google 提供的 CAPTCHA 或 reCPATCHA 來阻止機器人或自動化腳本的侵擾,雖然網站的管理目的達成了,但訪客體驗的評價卻也真實反映出「沒有人喜歡突然被打擾進行驗證」,也會間接讓訪客的停留時間、轉換率下降。

然而兩害相權取其輕之下,我們還是得需要用到人機驗證功能。

但是,是不是有更好的解決方案呢?

什麼是 Cloudflare Turnstile?

Cloudflare Turnstile 是 Cloudflare 開發用來替代 CAPTCHA 的免費人機驗證服務,用來辨識網站訪客是真人還是機器人,使用一系列非侵擾性的挑戰 (Challenge) 在瀏覽器的背景自行完成驗證檢查,而訪客完全不需要再進行「輸入英數字、選擇圖案」等測驗問題了。

Cloudflare 目前開放所有網站都可以免費使用 Cloudflare Turnstile 服務,無需使用 Cloudflare 的 CDN 服務,只需要在網站用戶端與伺服器端加入一小段程式碼,就能在網站中的表單自動插入 Cloudflare Turnstile 驗證小工具。

取得 Cloudflare Turnstile 金鑰

註冊帳號

如果還沒有 Cloudflare 的帳號的話,首先,到 Cloudflare Turnstile 頁面上找到 Turnstile 免費方案並點擊「開始使用」或「免費開始使用」按鈕。

Turnstile-Free vs Enterprise Plan

填寫電子郵件與密碼之後就能快速完成註冊了。Cloudflare 會寄送電子郵件驗證信件,記得到郵箱中完成郵件驗證。

Cloudflare-register

新增 Turnstile 服務網站

接著來到 Cloudflare 的管理頁面,在左側的選單中找到「Turnstile」,點擊「新增網站」按鈕。

Cloudflare-turnstile-setup

在「新增網站」頁面中,輸入網站名稱、使用 Turnstile 服務的網域名稱。

Cloudflare-turnstile-add-website

小工具模式提供了三種選項:

  • 受控 (Managed)
    Cloudflare 會使用來自訪客的資訊決定是否要採用非互動式的挑戰驗證,如果顯示了互動式的小工具,訪客需要勾選核取方塊才能完成人機驗證。
  • 非互動式 (Non-Interactive)
    在執行挑戰驗證時,訪客會看到一個載入狀態圖示,訪客無須與驗證小工具互動。
  • 隱藏 (Invisible)
    訪客在頁面上不會看到任何小工具或需要執行驗證的指示,一切都在瀏覽器的背景執行,短短幾秒的時間就完成。

完成後按下「建立」按鈕就能在這個網域的頁面中加入 Turnstile 服務了。

Cloudflare-turnstile-widget

取得金鑰

成功建立之後會顯示兩組金鑰,分別是「網站金鑰」與「秘密金鑰」。

Cloudflare-turnstile-Keys
  • 網站金鑰 (sitekey)
    需要放在網站用戶端,也就是需要使用到小工具驗證功能的登入、註冊、聯絡、留言表單中。
  • 秘密金鑰 (secret key)
    會在伺服器端驗證時使用,千萬不能放在網站前端,否則訪客、機器人在檢視網頁原始碼的時候就會看到秘密金鑰。

我們稍後會使用到這兩組金鑰。

安裝 Cloudflare Turnstile

在 WordPress 網站上安裝 Cloudflare Turnstile 有兩種方式,因為 Cloudflare 的開發人員文件寫得相當詳細,如果是有技術背景的站長,可以直接撰寫程式碼加入 Code Snippets 就能完成 Cloudflare Turnstile 小工具 (widget) 的安裝。

另一種當然就是透過 WordPress 社群提供的外掛了,對大多數站長都是最方便、輕鬆的方式。

我們先從「Simple Cloudflare Turnstile」外掛開始介紹。

Simple Cloudflare Turnstile 外掛

Simple Cloudflare Turnstile 是目前使用者最多、第三方表單支援數量相對多,而且充分具備繁體中文翻譯 (感謝阿力獅) 的 Cloudflare Turnstile 功能整合外掛。

首先,到「外掛」>「安裝外掛」搜尋 Simple Cloudflare Turnstile。

Simple Cloudflare Turnstile plugin

並點擊「立即安裝」。

安裝完成後進入「設定」>「Cloudflare Turnstile」。

Simple Cloudflare Turnstile-Settings-menu

輸入剛剛的兩組金鑰之後,測試 API 回應是否成功。

Simple Cloudflare Turnstile-API-Key-Settings

確認成功後,按照需要的功能勾選啟用。

Simple Cloudflare Turnstile 外掛支援的第三方外掛數量還在持續增加中,支援的外掛安裝之後就能在這個設定中找到啟用的功能了。

Simple Cloudflare Turnstile-enable-turnstile-on-your-forms

啟用之後,接著到相關表單查看,就能看到 Cloudflare Turnstile 的小工具了!

回到 Cloudflare 網站看到相關統計數據就大功告成了。

自行撰寫 Code Snippets

雖然安裝外掛就能直接開始使用 Turnstile 小工具,但 WordPress 世界中的佈景主題、頁面編輯器、區塊編輯器、表單外掛等各式外掛種類繁多,提供 Cloudflare Turnstile 功能整合的外掛 (如上面介紹的 Simple Cloudflare Turnstile) 需要時間才能陸續將一些知名的表單功能整合進去,如果有使用到 Simple Cloudflare Turnstile 尚未支援的表單功能,就無法直接安裝外掛使用 Turnstile 服務了。

另一方面,當這類外掛提供越來越多其他外掛表單功能的支援之後,外掛的功能與頁面載入效能也會有受到負面影響的擔憂。

因此就會有想要直接使用 Code Snippets 把 Cloudflare Turnstile 功能加入網站的需求了。

對此我也尋找了一下前人已經做過的努力 (畢竟 Turnstile 已經問世一段時間了),包含 Cloudflare 官方提供的 Github 範本WPCodeBox 社群有人在 Reddit 提供的導引

總結來說,在用戶端的部分加入程式碼是相對簡單的,只需要考慮到這兩個步驟。

在頁面中載入 Cloudflare 提供的 JS 程式碼:

<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>

在需要驗證功能的表單中加入 Turnstile 小工具:

<div class="cf-turnstile" data-sitekey="yourSitekey" data-callback="javascriptCallback"></div>

Cloudflare 提供了 2 種渲染、加入 Turnstile 小工具的方式,可以使用適合自己網站的方式。

而伺服器端的驗證流程程式碼就複雜多了,可能不適合程式小白照本宣科的直接按照開發人員文件就能完成的。

不過這部分我倒是找到了另一個網站 WPEXPLORER 提供了相當清楚的說明,不僅針對 WordPress 留言的 Turnstile 驗證提供完成 PHP 程式碼,也對其中的每一個步驟詳細說明。

其中 SITE_KEY、SECRET_KEY 就是前面提到的「網站金鑰」與「秘密金鑰」,需要在 ” 中放入金鑰字串。

if ( ! class_exists( 'WPEX_CloudFlare_Turnstile' ) ) {

	class WPEX_CloudFlare_Turnstile {

		/**
		 * Our Turnstile site key.
		 */
		private const SITE_KEY = 'YOUR_SITE_KEY_GOES_HERE';

		/**
		 * Our Turnstile secret key.
		 */
		private const SECRET_KEY = 'YOUR_SECRET_KEY_GOES_HERE';

		/**
		 * Holds the instance of our class.
		 */
		private static $instance;

		/**
		 * Create or retrieve our class instance.
		 */
		public static function instance() {
			if ( is_null( self::$instance ) ) {
				self::$instance = new self();
				self::$instance->init_hooks();
			}
			return self::$instance;
		}

		/**
		 * Init Hooks.
		 */
		public function init_hooks() {
			add_action( 'wp_enqueue_scripts', [ $this, 'load_api' ] );
			add_action( 'comment_form_after_fields', [ $this, 'add_comment_form_fields' ] );
			add_action( 'pre_comment_on_post', [ $this, 'verify_comment' ] );
		}

		/**
		 * Load the api script.
		 */
		public function load_api() {
			if ( ! is_singular() || ! comments_open() ) {
				return;
			}

			wp_enqueue_script(
				'cloudflare-turnstile',
				'https://challenges.cloudflare.com/turnstile/v0/api.js',
				[],
				'v0',
				false
			);
		}

		/**
		 * Inserts the turnstile API div into our comment form.
		 */
		public function add_comment_form_fields( $fields ) {
			echo '<div class="cf-turnstile" data-sitekey="' . self::SITE_KEY . '"></div>';
		}

		/**
		 * Verifies our comment on submission.
		 */
		public function verify_comment( $comment_post_id ) {
			if ( is_user_logged_in() ) {
				return;
			}

			if ( ! array_key_exists( 'cf-turnstile-response', $_POST ) ) {
				wp_die( '<strong>CAPTCHA ERROR:</strong> Please click the captcha checkbox.<p><a href="javascript:history.back();">« Go back</a></p>' );
			}

			if ( ! $this->turnstile_check( $_POST['cf-turnstile-response'] ) ) {
				wp_die( 'WE DON\'T TAKE KINDLY TO BOTS AROUND HERE.' );
			}
		}

		/**
		 * Turnstile check.
		 */
		public function turnstile_check( $turnstile_response ): bool {
			if ( ! $turnstile_response ) {
				return false;
			}

			$url = 'https://challenges.cloudflare.com/turnstile/v0/siteverify';
			$args = [
				'body' => [
					'secret'   => self::SECRET_KEY,
					'response' => $turnstile_response
				]
			];

			$post = wp_remote_post( $url, $args );

			if ( ! $post || is_wp_error( $post ) ) {
				return false;
			}

			$response = json_decode( wp_remote_retrieve_body( $post ) );

			return ( ! empty( $response->success ) && $response->success );
		}

	}

	WPEX_CloudFlare_Turnstile::instance();

這段程式碼在使用上有一些預設條件:

  1. 非單頁、未啟用留言功能的頁面不會載入
  2. 只針對未登入訪客顯示 Turnstile 小工具驗證
  3. Turnstile 小工具嵌入的鉤點位置為 add_action( ‘comment_form_after_fields’ )

如果想要對所有訪客 (已登入 + 未登入) 都進行驗證的話,需要:

  • 修改 verify_comment() 函數將其中的 is_user_logged_in() 檢查移除
  • 在 init_hooks() 函數中將 add_action( ‘comment_form_logged_in_after’ ) 鉤點也加入

如果想要改變 Turnstile 小工具嵌入的鉤點位置:

只需要把這段程式碼用 Code Snippets 的方式 (我們是用 WPCodeBox) 加入到 WordPress 網站,在文章頁面的留言區塊就能看到 Cloudflare Turnstile 小工具了!

Turnstile Analytics

安裝完成後,回到 Cloudflare 網站就能看到相關統計數據。

Cloudflare-turnstile-analytics

一個完整的 Turnstile Challenge Token Flow 包含 3 個階段:

  1. 挑戰已渲染完成 (rendered/issued)
  2. 挑戰已經在前端解決,並且取得 token (solved)
  3. Token 已送至 siteverify 進行驗證,並且驗證完成 (siteverified)

訪客解決率 (Visitor Solve Rate) 是驗證流程走到第 2 階段 (solved) 相較於渲染完成 (issued) 的比率,而系統判斷沒有必要完成第 3 階段的驗證。

API 解決率 (API Solve Rate) 則是完成第 3 階段驗證 (siteverified) 相較於渲染完成 (issued) 的比率。

點擊小工具名稱 (如上圖為 Quants Note – Turnstile) 還可以看到更詳細的解決率 (Solve Rate)、小工具流量 (Widget Traffic) 在過去一段時間的統計紀錄。

此外,在網頁上使用 Inspect 檢查載入資源的狀態時,如果發現 401 Unauthorized 錯誤訊息時不用感到驚慌或是懷疑安裝步驟、程式碼是否不正確。

cloudflare-turnstile-401-unauthorized-pat

會出現 401 錯誤是因為 Cloudflare 向網站請求了你的裝置或瀏覽器尚未支援的 Private Access Token (PAT)。

Private Access Tokens: eliminating CAPTCHAs on iPhones and Macs with open standards

結語

不管會不會寫程式碼,架設 WordPress 網站的站長們真的是幸福許多。

根據上面介紹的方法,不想要寫程式碼的站長們可以使用外掛快速完成 Cloudflare Turnstile 的安裝,熟悉撰寫程式碼的站長們可以直接將一小段程式碼加入網站就能安裝好 Cloudflare Turnstile 小工具。

熟悉之後,整體流程下來不用超過 10 分鐘,真的是滿佩服 Cloudflare 能提供這麼方便的人機驗證服務。

希望上面的介紹能夠幫助大家大幅減少垃圾留言的數量,少花一些管理垃圾留言的時間就能產出更多、更好的內容了!

如果有什麼心得、想法或建議,也歡迎大家加入社團一起討論唷!

The-Plugin-With-the-Best-Video-Experience-440X231

4 則留言

  1. 謝謝站長的教學,最近垃圾留言越來越多了,跟著教學做看看,希望可以不要再有 spam 啦
    PS在【在「新增網站」頁面中,輸入網站名稱、使用 Turnstile 服務的網域名稱。】這一步,我是選隱藏小工具~

      • 我來回報了,真的所有的垃圾留言都被阻擋下來了!這幾天網站格外清淨!感謝 Quants Note 的教學!

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *