摘要:但是在通過了,等反向代理軟件就不能獲取到客戶端的真實地址了。下面是一個參考獲取客戶端地址的方法如果使用的是連接池,可以參考使用方法,但這個是經過多級代理的地址,需要自己處理下獲取第一個。
在JSP里,獲取客戶端的IP地址的方法是:request.getRemoteAddr(),這種方法在大部分情況下都是有效的。但是在通過了Apache,Squid等反向代理軟件就不能獲取到客戶端的真實IP地址了。
如果使用了反向代理軟件,將http://192.168.1.110:2046/的URL反向代理為http://www.abc.com/的URL時,用request.getRemoteAddr()方法獲取的IP地址是:127.0.0.1或192.168.1.110,而并不是客戶端的真實IP。
經過代理以后,由于在客戶端和服務之間增加了中間層,因此服務器無法直接拿到客戶端的IP,服務器端應用也無法直接通過轉發(fā)請求的地址返回給客戶端。但是在轉發(fā)請求的HTTP頭信息中,增加了X-FORWARDED-FOR信息。用以跟蹤原有的客戶端IP地址和原來客戶端請求的服務器地址。
當我們訪問http://www.abc.com/index.jsp/時,其實并不是我們?yōu)g覽器真正訪問到了服務器上的index.jsp文件,而是先由代理服務器去訪問http://192.168.1.110:2046/index.jsp,代理服務器再將訪問到的結果返回給我們的瀏覽器,因為是代理服務器去訪問index.jsp的,所以index.jsp中通過request.getRemoteAddr()的方法獲取的IP實際上是代理服務器的地址,并不是客戶端的IP地址。
外界流傳的JAVA/PHP服務器端獲取客戶端IP都是這么取的:
偽代碼:
1)ip = request.getHeader("X-FORWARDED-FOR ")
2)如果該值為空或數(shù)組長度為0或等于"unknown",那么:
ip = request.getHeader("Proxy-Client-IP")
3)如果該值為空或數(shù)組長度為0或等于"unknown",那么:
ip = request.getHeader("WL-Proxy-Client-IP")
4)如果該值為空或數(shù)組長度為0或等于"unknown",那么:
ip = request.getHeader("HTTP_CLIENT_IP")
5)如果該值為空或數(shù)組長度為0或等于"unknown",那么:
ip = request.getHeader("X-Real-IP")
6)如果該值為空或數(shù)組長度為0或等于"unknown",那么:
ip = request.getRemoteAddr ()
先說說這些請求頭的意思
X-Forwarded-For
這是一個 Squid 開發(fā)的字段,只有在通過了HTTP代理或者負載均衡服務器時才會添加該項。
格式為X-Forwarded-For:client1,proxy1,proxy2,一般情況下,第一個ip為客戶端真實ip,后面的為經過的代理服務器ip。現(xiàn)在大部分的代理都會加上這個請求頭。
Proxy-Client-IP/WL- Proxy-Client-IP
這個一般是經過apache http服務器的請求才會有,用apache http做代理時一般會加上Proxy-Client-IP請求頭,而WL-Proxy-Client-IP是他的weblogic插件加上的頭。
HTTP_CLIENT_IP
有些代理服務器會加上此請求頭。
X-Real-IP
nginx代理一般會加上此請求頭。
下面是一個參考獲取客戶端IP地址的方法:
public static String getIpAddress(HttpServletRequest request) { String ip = request.getHeader("x-forwarded-for"); if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); } if (ip.contains(",")) { return ip.split(",")[0]; } else { return ip; } }
如果使用的是Druid連接池,可以參考使用:com.alibaba.druid.util.DruidWebUtils#getRemoteAddr方法,但這個是經過多級代理的IP地址,需要自己處理下獲取第一個。
有幾點要注意
這些請求頭都不是http協(xié)議里的標準請求頭,也就是說這個是各個代理服務器自己規(guī)定的表示客戶端地址的請求頭。如果哪天有一個代理服務器軟件用oooo-client-ip這個請求頭代表客戶端請求,那上面的代碼就不行了。
這些請求頭不是代理服務器一定會帶上的,網絡上的很多匿名代理就沒有這些請求頭,所以獲取到的客戶端ip不一定是真實的客戶端ip。代理服務器一般都可以自定義請求頭設置。
即使請求經過的代理都會按自己的規(guī)范附上代理請求頭,上面的代碼也不能確保獲得的一定是客戶端ip。不同的網絡架構,判斷請求頭的順序是不一樣的。
最重要的一點,請求頭都是可以偽造的。如果一些對客戶端校驗較嚴格的應用(比如投票)要獲取客戶端ip,應該直接使用ip=request.getRemoteAddr(),雖然獲取到的可能是代理的ip而不是客戶端的ip,但這個獲取到的ip基本上是不可能偽造的,也就杜絕了刷票的可能。(有分析說arp欺騙+syn有可能偽造此ip,如果真的可以,這是所有基于TCP協(xié)議都存在的漏洞),這個ip是tcp連接里的ip。
參考
http://blog.csdn.net/sgx42502...
http://blog.csdn.net/fengwind...
推薦:成為架構師的十階段學習資料
推薦:Spring Boot & Cloud 最強技術教程
如果對你有用,歡迎分享到朋友圈
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/71372.html
摘要:為什么叫重入鎖呢,我們把它拆開來看就明了了。釋放鎖,每次鎖持有者數(shù)量遞減,直到為止。 相信大家在工作或者面試過程中經常聽到重入鎖這個概念,或者與關鍵字 synchrozied 的對比,棧長面試了這么多人,80%的面試者都沒有答對或沒有答到點上,或者把雙重效驗鎖搞混了,哭笑不得。。 那么你對重入鎖了解有多少呢?今天,棧長幫大家撕開重入鎖的面紗,來見識下重入鎖的真實容顏。。 什么是重入鎖 ...
摘要:請欣賞手把手教程后端博客系統(tǒng)文章系統(tǒng)掘金本期主要是文章保存功能,涉及到草稿文章發(fā)布歷史這三個要點。一談談連接管理后端掘金連接管理概述最近重讀了權威指南部分章節(jié),結合來對部分內容進行印證并記錄下來。 Spring Boot干貨系列:(四)開發(fā)Web應用之Thymeleaf篇 | 掘金技術征文 - 掘金原文地址:Spring Boot干貨系列:(四)開發(fā)Web應用之Thymeleaf篇博客...
以下是Java技術棧微信公眾號發(fā)布的關于 Java 的技術干貨,從以下幾個方面匯總。 Java 基礎篇 Java 集合篇 Java 多線程篇 Java JVM篇 Java 進階篇 Java 新特性篇 Java 工具篇 Java 書籍篇 Java基礎篇 8張圖帶你輕松溫習 Java 知識 Java父類強制轉換子類原則 一張圖搞清楚 Java 異常機制 通用唯一標識碼UUID的介紹及使用 字符串...
閱讀 870·2021-11-18 10:02
閱讀 1670·2019-08-30 15:56
閱讀 2570·2019-08-30 13:47
閱讀 2639·2019-08-29 12:43
閱讀 851·2019-08-29 11:19
閱讀 1783·2019-08-28 18:23
閱讀 2669·2019-08-26 12:23
閱讀 3007·2019-08-23 15:29