iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 18
1
自我挑戰組

Wordpress 外掛開發系列 第 18

「Wordpress 外掛開發」建立REST API以及避免原生的設計造成零時差攻擊 - WP-JSON

中秋節可是我沒有烤肉吃

今天要提到Rest Api,大部分都可以知道在其他後端的語言之中,建立一個rest是滿容易的事情,可是你知道嗎?wordpress原生其實就有提供rest了,使用的方式是endpoin來做連接,不只可以收發request,也可以做到授權來做權限判斷,而在這一些經由http的過程之中,我們更需要了解那些基礎的回傳號碼是什麼。

狀態代碼

Status Code Description

  • 2xx Request 成功
  • 3xx Request 重新導向
  • 4xx Request 客戶端錯誤
  • 5xx Request 伺服器出錯

我們主要去訴求的,就是在搭建api中,能夠做到CRUD的功能,必且在撰寫的原則中需要遵守五個規則,在寫這個主題時,我是相信大部分的人對於這一些是有基礎的了解,如果還是有不懂的地方,可以參考官方網站做的http API寫的,滿詳細可以讓人從最初的http request到深入收發的使用。

  • Uniform insterface
  • client-server
  • stateless
  • cacheable
  • layered system

wordpress 提供的

wordpress對於你以post或是page的方式建立的資訊,都有相對應的Api可以去使用到,而我們主要使用的,就是w-json/v2來製作,而這一個根目錄,也是可以來查詢你的函式是否有增加成功,而對於預設的這一些API,與一般使用無差異,是可以不用特別去刪除,反正大家都可以看見你的網頁,除非有特定的漏洞會被攻擊,這樣才需要更加注意。

我們在測試endpoint有很多好的工具可以來使用,如果直接使用chrome會接到沒有排序過的json,是會頭昏眼花,建議是可以抓一些觀看json的套件在你的瀏覽器上,chrome是可以靠裝其他套件來完成看得更清楚,而其餘的瀏覽器就不清楚了,這邊推薦postman或是有json viewer這類的擴充元件可以讓回傳的結果更加正常。

而上述說到的原生api,其實都與正常使用一樣,如果你沒有登入就看不到的內容,在沒有授權的情況之下,是會回傳400給你寫著rest_invaluid_param,你可以試著寫寫看嘗試去發給locahost一個原生的api,並且會被回絕。

curl -X GET http://localhost/wp-json/wp/v2/posts?status=draft

那其實我們有個最簡單的方式,就是在發送的request中,發送自己的帳號密碼,不過這個動作請在測試之中做就好了,在正式主機上會有暴露密碼的風險,github上是有著basic auth來對wordpress endpoint做測試,對於測試環境下來說非常好用,可以參考 basic auth,basic auth單純地將你的帳號密碼每一次都寄出來做到授權,這個只適合在測試階段使用,如果是在正式機室得使用像是金鑰這些更安全的方式來設置。

建立自己的endpoints

只要是關於wordpress的相關功能,基本上都能依靠rest Api來做拓展,一個隨時都能將不錯的資料傳送正確的位置還滿吸引人的吧?我們在製作自己的endpoint時,只需要註冊後寫著就可以使用了,我們將會註冊一段回傳正確語言的訊息,而api的名稱就是phrase


function prefix_get_endpoint_phrase() { 
    return rest_ensure_response( 'Hello World, this is the WordPress REST API' );
}
 

function prefix_register_example_routes() {
    register_rest_route( 'hello-world/v2', '/phrase', array(
        'methods'  => WP_REST_Server::READABLE,
        'callback' => 'prefix_get_endpoint_phrase',
    ) );
}
 
add_action( 'rest_api_init', 'prefix_register_example_routes' );

我們這樣就可以簡單地顯示我們需要的資料,並且將我們所需的內容及相關篩選,寫在回傳的資訊之中,在於wp-json/v2之中是可以查看我們的example_routes是否有正確執行,而近一步要去測試api是否有錯誤,去對著相對應的api做get就可以看見結果

http://localhost/wp-json/hello-world/v1/phrase 

那其實這邊再接其他的參數與我們說之前說到的安全性息息相關,需要做認證,或是將輸入的與輸出的結果做sanitize,都是很必要的。

請別這樣寫,可能有被攻擊垮的可能性

而最後,Wordpress是否有可能因為API的關係,成功資安的缺口,其實這是得取決於自己撰寫的習慣,Api提供的資訊都是在於wordpress本身就已經公開(public)的狀態,所以與點選無異,如果你是rss也是可以拉得到,但有危險的地方就是多了好幾段攻擊的窗口,從安全的角度來看是給駭客們有更多的方式可以去嘗試,不過現在倒是沒有對於api的大問題發現,所以現階段不是很需要擔心可以好好使用它,但如果你還是對它不放心,或許你可以參考一下下面的filter,可以將api停用。

add_filter('rest_enabled', '_return_false');
add_filter('rest_jsonp_enabled', '_return_false');

不過因為wordpress在製作因為各個hook習習相關,在5.0發行之前,曾經是有個對於update的大問題,/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php中出了以id去取得第二個參數的滲透,使用update_item_permissions_check來做做存在id的漏洞,製造逾越權限可以執行update_item去更改ID,而這邊更改的ID其實非常危險。

大部分做sanitize來拉,都是在api的部分,但被注入惡意程式碼後,你在進到頁面如果沒有sanitize你呼叫的object,資料可能當場就再見,重則你連Server的權限都會被抹掉,甚至可以直接下載一些惡意程式做植入,不過在4.7.2之後就沒這個問題了,所以你在判斷權限的部分,你要避免下方的寫法,以防被時差攻擊。

我們初步寫入簡單取得post,而wordpress建立id的方式都是以全部數字為主,而以id注入非數字的字串,則int轉換結果會讓post有艘讓出節果

$post = get_psot($request['id']);
$this->check_update_permission($post);

$id = (int) $request['id'];

id會被轉換後,在其他函式可以被搜尋到就出現了漏洞,就是因為wordpress的編排id都是數字的關係,不過對於做交互比對是可以抵掉大部分的問題,並且在輸入口的地方,做好每一個型別是否正確,以及sainitze每一個輸入的問題,更可以去避免這種無妄之災。

reference

Routes and Endpoints
WordPress REST API and the Security Worries
Basic-auth
Custom REST API endpoint with authentication
How do I use this plugin with Custom Endpoints?
Creating Custom Endpoints for the WordPress REST API
API 是什麼? RESTful API 又是什麼?


上一篇
「Wordpress 外掛開發」版本控制與後續維護
下一篇
「Wordpress 外掛開發」商品限定VVIP,缺了些東西還是可以讓人入侵看光
系列文
Wordpress 外掛開發30

尚未有邦友留言

立即登入留言