http是應用層,ip是網路層,那麼http請求頭部的client ip是怎麼獲取到的呢?

http協議是應用層,客戶端發起http請求時,可以帶上一個client_ip的參數帶上客戶端的地址,但是在構造請求報文的時候還沒有到ip層,http如何得知client_ip填入什麼地址呢?

另外如果客戶端是處於內網,構造出來client_ip填的是私網的地址,到了NAT的設備,只把ip層的ip地址做了轉換,那http頭部的client_ip怎麼辦?誰負責轉換呢?


高票答案說了一堆完全無關的東西,順帶吹了一波,實在是難看。

日常使用的 HTTP 協議中,客戶端不會發 client_ip 頭,確切說是 X-Client-IP 和 X-Forwarded-For。

分兩種情況

  • 在沒有反向代理的情況下,伺服器程序可以直接拿到 TCP 層對方的 IP。
  • 在部署了反向代理的情況下,TCP 連接已經經過了一次,甚至多次中轉,伺服器程序在 TCP 層只能拿到反向代理的 IP,無法獲取客戶端的真實 IP。因此才設計了 X-Client-IP 和 X-Forwarded-For 這兩個頭。

所以這兩個頭是由反向代理記錄並添加,發往後端伺服器程序的。後端會通過這兩個頭,來解析到客戶端的真實 IP,執行 IP 地址相關的諸如限流,判斷來客國家等等邏輯。

由此會引申出一個安全問題:

如果你的伺服器程序在沒有部署反向代理的情況下,信任了這兩個頭,客戶端就可以通過偽造這兩個頭進行 IP 地址欺騙。X-Forwarded-Proto 也是一樣,會被拿來進行 HTTPS 欺騙。

按照標準,X-Client-IP 頭只包含客戶端 IP。在多層反代情況下,最外層反代需要濾掉客戶端可能發來的頭,填上客戶端 IP;內層反代不對這個頭做任何操作。X-Forwarded-Proto 也是類似。

同樣按照標準,X-Forwarded-For 頭要包含客戶端 IP,並追加經過的所有反代的 IP。因此,在多層反代情況下,最外層反代需要濾掉客戶端可能發來的頭,只填寫客戶端 IP; 內層反代做追加。

備註:

X-Client-IP 有時候也會寫做 X-Real-IP,看各家的實現。

X-Forwarded-For 這個接受度更廣,參見 MDN MDN - X-Forwarded-For


這個問題問的有一定水準,至少06年參與電信號碼百事通項目時,無法回答這個問題。

第一個問題:如果想把本地物理介面IP填充到Http協議頭/體,如何實現?

首先,當在windows平台使用 IPCONFIG /all,會顯示本地的所有物理介面的IP參數信息,包括IP,這是一個小程序,通過調用TCP/IP協議介面函數來實現的,如果喜歡,甚至可以獲得本地的物理網卡的硬體MAC。

同理,可以在客戶端程序里調用類似的Socket介面函數,如果把http + TCP Header + IP Header + Ethernet Header 這一行為看作數據平面,那麼通過管理介面函數獲得底層IP、MAC這一行為,可以看作管理平面。

第二個問題:誰來為http 里私有IP地址做NAT?
通常NAT設備只做三四層的NAT,即IP+ Port,但由於應用層數量龐大,如果NAT設備支持七層的NAT,則實現的代碼將會非常龐大(需要理解應用層協議),所以通常使用應用層網關ALG來實現,需要為哪個應用層做NAT,只需要將對應的應用層ALG打開,這樣系統裝入的代碼最小化。

以SIP協議為例,SIP協議幾乎完全模仿Http協議,可以用於電話呼叫信令協議,當主叫、被叫位於NAT設備兩側,由於SIP/SDP協議嵌入的私有IP,當對方拿著對方的私有IP來跑UDP/RTP語音通話時,很顯然無法通信。

解決方案
只需要NAT設備,打開SIP ALG功能,SIP ALG負責SIP/SDP協議里嵌入的私有/公網IP + 埠號轉換,這樣語音就可以雙向流動了。

如何解決SIPS加密,而ALG無法對密文做NAT?
通常,由於SIPS不是端對端加密,而是跳對跳加密,所以完全可以將ALG與NAT設備放在一台物理設備上,按照NAT、ALG、加密的先後順序,就可以達到預期的效果。


http協議是應用層,客戶端發起http請求時,可以帶上一個client_ip的參數帶上客戶端的地址,但是在構造請求報文的時候還沒有到ip層,http如何得知client_ip填入什麼地址呢?

在高層準備數據前,底層確實還沒有開始準備該層對應的數據,但底層協議棧初始化必然是已經完成了的。協議棧初始化完成,則IP之類的底層參數一定是確認了的。粗略一點講,從HTTP往下面的協議棧都由OS負責初始化且確立可用後,OS才會接受你調用sock API去建立連接發送數據,此時你用相應API獲得例如本機IP這樣的底層參數,再帶入HTTP數據中,是沒有順序問題和邏輯矛盾的。

另外如果客戶端是處於內網,構造出來client_ip填的是私網的地址,到了NAT的設備,只把ip層的ip地址做了轉換,那http頭部的client_ip怎麼辦?誰負責轉換呢?

沒人做,除非你需要做且自己負責完成。舉個例子,FTP一種工作模式需要一個額外的控制埠,此埠分配是FTP伺服器自己完成且附送在控制命令里發送的,NAT就翻譯不了這個埠,於是需要額外的NAT Helper來完成這個事情。

至於你說的client_ip因為沒有詳細說明不好斷定到底是什麼場景。

  • 假如是指socks API里的本端地址,可以不寫由OS分配本機可用IP。同時因為是四層TCP協議的五元組之一,NAT可以處理;
  • 如果你是指HTTP請求經由HTTP Proxy帶的那個X-Forwarded-For頭,那個是Proxy填寫的,屬於協議RFC推薦,實現與否取決於Proxy是否良心;
  • 再如果只是你自己的應用需要帶這麼個參數在HTTP請求數據里,那假如沒人替你做轉換的情況下,你絕大多數可能是收到一個NAT後面的私有IP。

第一個問題的答案是應用客戶端自己通過控制平面直接查詢獲取本機IP插入到報文七層頭部里去的。

這種在七層頭部插入IP欄位的用途有兩種使用場景

一種是用在有源nat的負載均衡,所有客戶端的源地址都被nat成一個地址去訪問應用的時候,負均衡器通過識別客戶端插入在報文七層頭部的IP和埠欄位進行負載分發。這種情況下不會對七層頭部里的IP欄位進行nat。

另外一種應用場景是語音而不是http,語音網關會在做三層nat的同時把七層頭部里的IP欄位也一起也nat了。

至於如你題中所說的把http的七層頭部IP欄位也一起nat, 我是沒直接接觸過這種應用案例。搞這種飛機的一般都是大型機構間私有網路直接對接私有網路里跑的共用私有應用,應用網關都是定製開發,負載一般都是基於源埠進行負載分發的。這種案例非常少,而且理論也很簡單粗暴,沒必要花時間在這上面去深究鑽牛角尖,真用到的時候現學現賣就可以了。


不太清楚題主說的是什麼情下有這種用法。

嚴格意義上說,http不一定要運行於tcp-ip協議之上,連在url裡面使用ip地址都應該盡量避免。在http頭部加入client的ip地址是沒有必要的。


最好不要這樣用協議。如果是http還好,nat可以幫忙把內網ip改成外網。如果是https,nat可幫不上忙,協議會失敗


只能在伺服器端拿到(包括反向代理),客戶端不會加上這個頭,提問前提是錯的。


據我所知http頭根本就不需要設置client IP欄位


http請求頭什麼時候有clientip了……

是哪個header....

X-Forward-For的話只是一個約定俗稱給代理放實際ip的地方,不是真正的實際ip啊。

這個應該是tcp這一層獲取的啊。

題主應該是框架用的比較多,沒去好好看各個語言的http庫的實現吧,又或者是用的語言的Http庫過於奇葩?


客戶端 ip 是在 TCP 建立連接的階段就確定好的,所以根本不需要 HTTP 去獲取 ip 地址。

請求頭包含 ip 地址,是 HTTP Receive 端做的,也就是 HTTP Server。目測是直接將連接中的 ip 包裝包協議頭中了。

你可以自己實現一個監聽 80 埠的 TCP 程序,你試試能不能從請求頭中看到客戶端 ip。


好問題。

首先協議層的意思是包含,也就是說,網路和傳輸層是在應用層外面,http協議里根本沒有這個信息。

[ip層數據[tcp層數據[http層數據]]]

但這個信息並不是拿不到,因為7層伺服器都是由4層實現而來,4層協議的api能拿到client的ip地址,絕大多數框架是會把客戶端ip傳給你的,或者如果你自己實現一個http伺服器,也必須用tcp的api搭起來,同樣能得到4層的srcaddr,所以沒問題,你是能從框架里找到的。

如果找不到你說說你用的啥伺服器。

如果用了反向代理參考別的同學說的用header傳給後端,同樣也是四層介面告訴反向代理伺服器,反向代理伺服器傳給應用伺服器的。

不可以客戶端自己在應用層傳ip過來,不安全。

最後一個問題,NAT裡面的clientIp沒有意義,你需要的只是廣域網的那個接入ip而已。


一般是服務端的反向代理從tcp協議的頭裡拿的添加到http header的,比如X-Real-Ip和X-Forwarded-For,後者可能客戶端會攜帶(偽造),代理把它拿到的client ip追加到末尾。

如果服務端沒有反向代理,也是從tcp協議包頭取到的ip。


幾句話的事情,怎麼搞的好像無比複雜一樣……
簡單地說,http協議中並沒有client ip這個東西,但這不妨礙在具體實踐中各種http伺服器從tcp連接中得到tcp client的地址。在nat的情況下,這個地址當然只能是client的外部ip。

除此之外,在http頭中又定義了x-forward-for欄位給代理伺服器使用,代理伺服器應該按順序在其中填入client ip。

因此,web伺服器實際上會使用多種辦法確定client ip。即使如此,因為這些方法都依賴外部網路設備對標準的遵從,最後仍然可能得不到準確ip。


前面回答已經很全了,我這裡針對Java Servlet中是如何獲取客戶端IP解釋一下。Servlet規範中HttpServletRequest定義了getRemoteAddr()來獲取遠程客戶端的IP,手頭上正好有tomcat6.x的源碼,結合tomcat的實現可以看出實際上是通過獲取socket鏈接的對端地址得到的。

} else if (actionCode == ActionCode.ACTION_REQ_HOST_ADDR_ATTRIBUTE) {

if ((remoteAddr == null) (socket != null)) {
InetAddress inetAddr = socket.getInetAddress();
if (inetAddr != null) {
remoteAddr = inetAddr.getHostAddress();
}
}
request.remoteAddr().setString(remoteAddr);

}

這裡和HTTP協議本身已經沒有關係了。


首先請複習一下網路模型,網路是分層的,你想發送的數據在應用層是數據流,在從應用層到IP層數據會被工作在該層的協議拆解成一個一個的數據報並在每個包上添加目的IP與發件人IP後轉到第二層鏈路層該層工作的協議將收到的IP報上加裝Mac地址後轉發到物理層發送,數據到達目的後收件人的網路設備與伺服器會已相反的順序逐步將數據從各封包里解出最後還原到應用層流數據


這個問題需要分解為兩個問題來回答。
第一個問題是在不考慮子網的情況下,客戶端應用如何獲取本地IP地址作為ClientIP添加到HTTP頭域?
客戶端獲取本地IP需要考慮編程語言和操作系統的不同,採取不同的方式進行獲取,同時結合第三方HTTP庫添加到頭域。
第二個問題是考慮子網時,客戶端的本地IP作為ClientIP存在哪些問題?
由於子網的地址轉換,客戶端的本地IP對伺服器來說已經不是唯一的,此頭域就失去意義了。通過網路設備,如路由器,去添加這個頭域的話,對其不存在普遍適用性,得不償失。
說一句題外話,這個頭域只是為了標記與客戶端的通信途徑,只要能與客戶端相互通信即可,是不是真的客戶端IP並無大礙。


很多人提到nat,這跟nat半毛錢關係都沒有。nat是IP層的東西,才不管你http是什麼玩意,就像火車司機不關心車上的乘客在幹什麼。

首先,從來沒在http請求頭見過這個欄位。 即使有也是填入的私有地址,跟伺服器收到的很可能不是同一個。
在發起請求之前操作系統已經初始化了網卡信息,能通過api拿到地址。


http頭沒有放ip的地方,只有一個xff是給代理用的


首先,什麼是tcp/ip協議,什麼是socket,
http其實建立在socket上,一般都是一次會話,短連接,socket能得到對方的ip,伺服器方面,框架會有api取得,如果是互聯網,只能得到客戶端最終出去的外網ip,這是由路由控制,一般都是路由器。
如果是得到本身的ip,操作系統api會解決


第一個問題,我覺得瀏覽器會針對client ip(如果有這個首部選項的話)這個首部選項查本機路由表;第二個問題,路由器是可以做到識別http報文,並在nat時候將http首部中的client ip進行轉換的,但https就不行了。


這個提問感覺不完整,啥場景下,怎麼使用沒有說清楚,有設備能做到給你帶上終端地址,但是會有一些限制的,並且如上面有的回復,如果使用https是很難搞定的


推薦閱讀:

基於傳輸層TCP、UDP協議的自定義應用層協議如何實現?
前端工程師應該對 HTTP 了解到什麼程度?從哪些途徑去熟悉更好?
為什麼國內視頻網站多採用HTTP協議傳輸視頻,而國外多使用RTMP等專門的流媒體協議?

TAG:計算機網路 | HTTP |