867 字
4 分鐘
解決Cloudflare WARP無法取得使用者IP
2022-12-16
無標籤

Cloudflare WARP作為免費又強大的VPN,可用於建構企業的零信任架構,但目前使用上遇到的問題是,後端的服務無法知道使用者真實的IP,都只能得知WARP的IP。而WARP主打的功能也包含提升隱私,隱藏使用者IP的功能。我也問過CF官方,目前無法在header提供使用者IP資訊,只能在Zero Trust後台看log,才能知道使用者的IP。如果我們想用設備鑑定就得開WARP,但該怎麼讓我們的服務知道IP呢?

了解架構#

我們先想一下,哪些環節有機會取得使用者的IP並塞到header上,讓後端可以取得,而我們可以在Gateway、Access、Rules有機會可以自定義header,但起來有機會取得使用者IP的機會只有Gateway了,在Access跟Rules都只能取得WARP的IP,所以這時候在Access或Rules用IP當規則就變得沒有用。雖然Gateway有自定義header的功能,但不像Rules有彈性,可以設定動態Header,也就是說沒辦法在Cloudflare上取得IP並設定到header上,那就只能用一些奇怪的方法了。

我這邊的Service先用一個Workers來Demo,並給他一個網域whoami.example.com,他會回傳所有request的header,方便我們觀察能否取得IP。

// https://whoami.example.com
addEventListener("fetch", event => {
event.respondWith(handleRequest(event.request))
})
async function handleRequest(request) {
var h = Object.entries(Object.fromEntries(request.headers));
var result = "";
for (const [key, value] of h) {
result += `${key}: ${value}\n`;
}
return new Response(result);
}

這時候如果打開WARP來測試,會發現cf-connecting-ip、true-client-ip、x-real-ip都變成WARP的IP,無法取得使用者真實的IP。


設定網域白名單#

Cloudflare WARP是可以設定網域白名單來略過Gateway,我們從這個思路下手,可以把取得使用者IP的功能獨立成一個網域,再告知後端。那要怎麼告知後端呢?我這邊以Cookie為例,給大家參考。

這時候我們再開一個Workers用來取得使用者真實的IP,網域為ip.example.com。我們要把ip.example.com加入WARP的例外清單,就不會過WARP。

例外清單要到,Cloudflare Zero Trust後台 / Settings / Network / Firewell / Split Tunnels,將ip.example.com加入。


設定Cookie#

再來開始寫ip.example.com的Workers,我從header中取得Cf-Connecting-Ip,並將他設定到*.example.com的cookie中的IP欄位。

// https://ip.example.com
addEventListener("fetch", event => {
event.respondWith(handleRequest(event.request))
})
async function handleRequest(request) {
var ip = request.headers.get("Cf-Connecting-Ip");
return new Response(null, {
headers: {
'Access-Control-Allow-Origin' : '*',
'set-cookie' : `IP=${ip}; Domain=.example.com; Secure; HttpOnly`,
},
});
}

當使用者瀏覽到ip.example.com的時候,就會設定好cookie,並且是example.com的子網域都通用。


自動設定Cookie#

接著我們設計讓所有*.example.com的網站都會自動設定ip到cookie,
可以使用Cloudflare Apps中的Add HTML為每一頁網站新增一段script,就會在每次瀏覽網站時載入。這邊也可以用Cloudflare Zaraz做到一樣的效果。

<script>fetch("https://ip.example.com")</script>

這時候載入到任何一個sub.example.com就會發現cookie中已經設定好IP。


總結#

歸根結底,還是希望Cloudflare Gateway可以支援將使用者IP直接設在Header上取用就會方便很多,而且要考慮到Cookie是有可能會被使用者修改的,建議還是幫他加密或是用token來換,或是讓ip.example.com直接與服務溝通,增加IP來源的可靠度。雖然沒辦法很漂亮的取得使用者IP,但還是透過Cloudflare Workers, Apps來繞過去。