iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 16
2
Modern Web

成為 Modern PHPer系列 第 16

Day 16: 正確取得 IP 位址

前言

PHP 的歷史悠久常常是優勢也是包袱。一個初來乍到的開發者,可能會因為希望實現某個功能而去 Google

PHP IP位址

值得慶幸的是,資安公司 DEVCORE 已經寫過一篇 如何正確的取得使用者的 IP,而且在 Google 的索引分數非常高。

然而,PHP 的教學常常見到「一鍋粥裡只有一粒粥,其它都是老鼠屎」的荒謬現象,以下隨便舉幾個例子:

這還僅僅只是 Google 第一頁的結果,其中甚至不乏 2017 年的文章。

前導知識

在今天的文章開始之前,請各位務必先看過 DEVCORE 的 如何正確的取得使用者的 IP,我會從這篇文章的內容下去做擴充。

IP 儲存方式

其實,上面被說成「錯誤」的 IP 取得範例,在設計時都有其理由。

最簡單的方式是直接判斷 $_SERVER['REMOTE_ADDR'],這是在前面沒有設計 Load Balancer 或是使用類似 Cloudflare 為前提才適用的方式。

Remote Address 的定義是:最後一個來源的 IP 位址,它來自於 TCP 協定的的來源 IP,無法透過 HTTP Header 的方式修改,在不考慮被應用程式修改的前提下,這個值是可信任的。

然而,因為它是「最後一個來源」的 IP,也就是說如果我的應用程式躲在 Load Balancer、Reverse Proxy 或是使用 Cloudflare 之類的服務,此值就僅能取得這些設備的 IP。


|---------|       |-------------|
| Client  |======>| Application |
| 1.2.3.4 |       | 11.11.11.11 |
|---------|       |-------------|

狀況一:在 Application 伺服器上,利用 $_SERVER['REMOTE_ADDR'] 會拿到 1.2.3.4,這是我們要的

|---------|       |---------------|        |-------------|
| Client  |======>| Reverse Proxy | ======>| Application |
| 1.2.3.4 |       | 22.22.22.22   |        | 11.11.11.11 |
|---------|       |---------------|        |-------------|

狀況二:在 Application 伺服器上,利用 $_SERVER['REMOTE_ADDR'] 會拿到 22.22.22.22,這不是我們要的

一般來說,Reverse Proxy 會把拿到的 $_SERVER['REMOTE_ADDR'] 放進另一個 HTTP Header(每個實作不儘相同,應該詳閱說明),通常會放在 $_SERVER['HTTP_X_FORWARDED_FOR']。

所以在這個例子中,Application 會拿到 $_SERVER['HTTP_X_FORWARDED_FOR'] = '1.2.3.4,22.22.22.22'(中間會用逗號分隔,以便有多個 Reverse Proxy 時可以使用)

IP 獲取方式

也因為現代應用程式越來越多是放在 Reverse Proxy 或 Load Balance 之後,所以才會衍生出如上述那些「錯誤」的教學場景。

遺憾的是,$_SERVER['HTTP_X_FORWARDED_FOR'] 是可以被偽造的,使用者只要任意填寫就可以達到偽造 IP 的手段。

在 Symfony Framework 中,提供了一個解決方案:TrustedProxies,藉由設定「可信任的 Proxies」來取得最一個使用者的來源 IP

以上述範例來說,我信任來自 22.22.22.22 的 Reverse Proxy,所以在 $_SERVER['HTTP_X_FORWARDED_FOR] 中會去除 22.22.22.22 這個 IP 之後,就是我希望取得的使用者 IP。

註:這個 IP 仍可能是偽造出來的,畢竟 Client 端可以經由任何的 Proxy Server 去存取網頁。這樣的技巧僅能確定自己的應用程式是沒問題的。
註:這個功能是可以自己實現的,不一定要倚賴 Symfony Framework,但是通常會建議有現成的解決方案就直接套用。

後記

今天算是對 IP 的獲取做個補充,順便得罪人


上一篇
Day 15:PHP 語言快取機制
下一篇
Day 17:測試淺談
系列文
成為 Modern PHPer30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言