Nginxの設定
フロントエンドとバックエンドを分離した上で、静的サーバーとしてnginxを使用し、リバースプロキシ方式によりクロスドメインインターフェースを実現することで、開発コストを削減する一方で、調達コストなど多くの問題を抱えています。クライアントの実際の IP の。
リスク管理や支払いプロセスなどの一部の特殊なシナリオでは、ユーザーの IP 情報を取得する必要があることがよくありますが、nginx リバース プロキシはサーバーのリクエストのソースを完全に変更し、ユーザーとサーバー間の接続を分離しながら実現します。クロスドメイン、以下に示すように
ユーザーがフロントエンド ページ「https://a.test.com/index/html」にアクセスして支払いインターフェイスを呼び出すと、支払いインターフェイスのアドレスは「https://a.test.com/goPay」になります。 、その後、nginx プロキシによってサーバー側の「https://b.test.com/goPay」に反転されます。このとき、サーバー側にとって、受信するリクエストはすべて nginx サーバーからのものであり、サーバー側が取得するデフォルトの IP は nginx サーバーの IP です。これは私たちが望んでいることではありません。現時点では、次の構成を追加する必要があります。
-
proxy_set_header X-Real-IP $remote_addr;
-
proxy_set_header X-Real-Port $remote_port;
-
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
3 つのヘッダーは次を表します。
-
X-Real-IP 客户端ip
-
X-Real-Port 客户端或上一级端口
-
X-Forwarded-For 包含了客户端和各级代理ip的完整ip链路
このうち、X-Real-IP は必須で、最後の 2 つの項目はオプションです。nginx プロキシのレベルが 1 つだけの場合、X-Real-IP と X-Forwarded-For は一致します。プロキシのレベルが複数ある場合、X-Forwarded-For は次の形式になります。
X-Forwarded-For: 客户端ip, 一级代理ip, 二级代理ip...
X-Forwarded-For はクライアント IP を取得するプロセスではオプションですが、セキュリティ上の問題が発生したときにログ ファイルに従ってソースを追跡できるように、個人的には保持しておくことをお勧めします。
穴があります:
上記の設定部分に加えて、ネチズンはホストヘッダーも提供しました
proxy_set_header Host $host;
まず第一に、このヘッダーは必要ありません。第二に、ホスト ヘッダーと proxy_pass 転送によって生成されたホスト ヘッダーが競合し、その結果インターフェイス 502 が発生します。ただし、この構成を更新した後は、テストで nginx -t を使用するなど、nginx を再起動してもエラーは報告されません。
ジャワ取得
シナリオ: サーバーがクライアント要求を受信すると、通常、署名検証、クライアント IP 制限などを実行する必要があります。クライアント IP 制限を実行するときは、最初に実際の IP を取得する必要があります。一般に次の 2 つの状況に分けられます。
方法 1: クライアントはプロキシを使用せずにサーバー (nginx、squid、haproxy) に直接アクセスします。
方法 2: クライアントはマルチレベル プロキシを通過し、最終的にサーバー (nginx、squid、haproxy) に到達します。
クライアント要求情報は HttpServletRequest に含まれており、クライアント IP は getRemoteAddr() メソッドを通じて取得できます。このとき、方法 1 を使用している場合は、クライアントの実 IP を直接取得できます。また、方法 2 のプロキシ形式の場合、この時点でマルチレベル リバース プロキシの後、メソッド getRemoteAddr() ではクライアントの実 IP を取得できず、転送されたリクエスト情報は x- で取得できます。転送されました。クライアント要求が転送されると、IP が追加され、カンマで区切られます (例: 10.47.103.13,4.2.2.2,10.96.112.230)。
リクエスト内のパラメータ:
request.getHeader("x-forwarded-for") : 10.47.103.13,4.2.2.2,10.96.112.230
request.getHeader("X-Real-IP") : 10.47.103.13
request.getRemoteAddr():10.96.112.230
クライアント アクセスが転送されると、IP が追加され、カンマで区切られます。最終的な正確な顧客情報は次のとおりです。
- x-forwarded-for が空でない場合、それはカンマの前の最初の IP です。
- X-Real-IP が空でない場合、それは IP です。
- それ以外の場合は getRemoteAddr();
コード例:
このとき、通常の状況では、クライアントの実際の IP を取得できます。なお、サーバー側の負荷の形態については、x-forwarded-forを設定して保存する必要があります。現在のロード形式には、haproxy、nginx、その他の形式が含まれます。構造図は次のとおりです。
/**
* 获取用户真实IP地址,不使用request.getRemoteAddr()的原因是有可能用户使用了代理软件方式避免真实IP地址,
* 可是,如果通过了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP值
*
* @return ip
*/
private String getIpAddr(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
System.out.println("x-forwarded-for ip: " + ip);
if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
// 多次反向代理后会有多个ip值,第一个ip才是真实ip
if( ip.indexOf(",")!=-1 ){
ip = ip.split(",")[0];
}
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
System.out.println("Proxy-Client-IP ip: " + ip);
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
System.out.println("WL-Proxy-Client-IP ip: " + ip);
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
System.out.println("HTTP_CLIENT_IP ip: " + ip);
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
System.out.println("HTTP_X_FORWARDED_FOR ip: " + ip);
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("X-Real-IP");
System.out.println("X-Real-IP ip: " + ip);
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
System.out.println("getRemoteAddr ip: " + ip);
}
System.out.println("获取客户端ip: " + ip);
return ip;
}