この章では、javaを使用して実際のIPアドレスと関連するセキュリティを取得する方法について説明し、次にMongoDBの不適切な構成によって引き起こされるセキュリティの問題について説明します。
1.実際のIPアドレスを取得します
1.1IPアドレスを取得するタイミング
私のアプローチは、URLを取得するときと同じようにController
、各実行の前に要求されたIPアドレスを取得することです。同様に、各要求に対応するものを取得しHttpServletRequest
ます。コードは次のとおりです。
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
org.springframework.web.context.request.ServletRequestAttributes
ソースコードはパッケージを使用してThreadLocal
各リクエストのHttpServletRequest
オブジェクトを保存します。後で空いた場合は詳細に説明できます
1.2getRemoteAddr与x-forwared-for
HttpServletRequest
オブジェクトを 取得した後、getRemoteAddr()
内部の関数を呼び出してリモートクライアントのIPを取得できますが、同時にhttpプロキシのシナリオでは、プロキシの後、クライアントとサービスの間に中間層が追加されているため、サーバーはオブジェクトを直接取得できません。クライアントのIPに対して、サーバー側のアプリケーションは、要求されたアドレスを転送してクライアントに直接戻ることはできません。ただし、転送要求のHTTPヘッダー情報には、情報が追加されX-FORWARDED-FOR
ます。元のクライアントのIPアドレスと元のクライアントによって要求されたサーバーアドレスを追跡するために使用されます。
RFC2616によると、HTTPメソッドは大文字と小文字を区別しますが、ヘッダーはそうではないことに注意してください。URIのプロトコル名とドメイン名は大文字と小文字を区別せず、パスはサーバーによって異なります。
したがって、我々は最初に決定することができるHttpServletRequest
にhttp header
対応するフィールドがあれば、そこにあるか否かをそのx-forwared-for
値、および複数のIP値は文字列であり、その後、採取x-forwared-for
以外に最初unknown
の有効なIP列コードとして以下れます。
public static String getClinetIpByReq(HttpServletRequest request) {
// 获取客户端ip地址
String clientIp = request.getHeader("x-forwarded-for");
if (clientIp == null || clientIp.length() == 0 || "unknown".equalsIgnoreCase(clientIp)) {
clientIp = request.getHeader("Proxy-Client-IP");
}
if (clientIp == null || clientIp.length() == 0 || "unknown".equalsIgnoreCase(clientIp)) {
clientIp = request.getHeader("WL-Proxy-Client-IP");
}
if (clientIp == null || clientIp.length() == 0 || "unknown".equalsIgnoreCase(clientIp)) {
clientIp = request.getRemoteAddr();
}
/*
* 对于获取到多ip的情况下,找到公网ip.
*/
String sIP = null;
if (clientIp != null && !clientIp.contains("unknown") && clientIp.indexOf(",") > 0) {
String[] ipsz = clientIp.split(",");
for (String anIpsz : ipsz) {
if (!isInnerIP(anIpsz.trim())) {
sIP = anIpsz.trim();
break;
}
}
/*
* 如果多ip都是内网ip,则取第一个ip.
*/
if (null == sIP) {
sIP = ipsz[0].trim();
}
clientIp = sIP;
}
if (clientIp != null && clientIp.contains("unknown")){
clientIp =clientIp.replaceAll("unknown,", "");
clientIp = clientIp.trim();
}
if ("".equals(clientIp) || null == clientIp){
clientIp = "127.0.0.1";
}
return clientIp;
}
public static boolean isInnerIP(String ipAddress) {
boolean isInnerIp;
long ipNum = getIpNum(ipAddress);
/**
私有IP:A类 10.0.0.0-10.255.255.255
B类 172.16.0.0-172.31.255.255
C类 192.168.0.0-192.168.255.255
当然,还有127这个网段是环回地址
**/
long aBegin = getIpNum("10.0.0.0");
long aEnd = getIpNum("10.255.255.255");
long bBegin = getIpNum("172.16.0.0");
long bEnd = getIpNum("172.31.255.255");
long cBegin = getIpNum("192.168.0.0");
long cEnd = getIpNum("192.168.255.255");
isInnerIp = isInner(ipNum, aBegin, aEnd) || isInner(ipNum, bBegin, bEnd) || isInner(ipNum, cBegin, cEnd)
|| ipAddress.equals("127.0.0.1");
return isInnerIp;
}
private static long getIpNum(String ipAddress) {
String[] ip = ipAddress.split("\\.");
long a = Integer.parseInt(ip[0]);
long b = Integer.parseInt(ip[1]);
long c = Integer.parseInt(ip[2]);
long d = Integer.parseInt(ip[3]);
return a * 256 * 256 * 256 + b * 256 * 256 + c * 256 + d;
}
private static boolean isInner(long userIp, long begin, long end) {
return (userIp >= begin) && (userIp <= end);
}
もちろん、すべてのプロキシサーバーが
x-forwared-for
各ホップの値のみを記録するわけではなく、別のヘッダーを使用する場合もあれば、まったく記録しない場合もあります。
1.3IPアドレスに基づいて実際のアドレスを取得する
場合によっては、IPアドレスに基づいて対応する地理的位置を照会することもあります。このとき、Baiduのインターフェイスを参照できます。コードは次のとおりです。
public static String getAddressByIP(String strIP) {
if(strIP.equals("127.0.0.1")||strIP.equals("0:0:0:0:0:0:0:1"))
return "本地局域网";
try {
URL url = new URL("http://api.map.baidu.com/location/ip?ak=F454f8a5efe5e577997931cc01de3974&ip="+strIP);
URLConnection conn = url.openConnection();
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
String line = null;
StringBuffer result = new StringBuffer();
while ((line = reader.readLine()) != null) {
result.append(line);
}
reader.close();
String ipAddr = result.toString();
try {
JSONObject obj1= new JSONObject(ipAddr);
if("0".equals(obj1.get("status").toString())){
JSONObject obj2= new JSONObject(obj1.get("content").toString());
JSONObject obj3= new JSONObject(obj2.get("address_detail").toString());
return obj3.get("province").toString()+ obj3.get("city").toString()+obj3.get("district").toString()+obj3.get("street").toString();
}else{
return "国外";
}
} catch (JSONException e) {
e.printStackTrace();
return "读取失败";
}
} catch (IOException e) {
return "读取失败";
}
}
1.4x-forwared-練習用
実際のIPアドレスを認識できるかどうかをローカルで確認してみましょう。Webサイトのローカルアドレスは、引き続きhttp://localhost
マシンのローカルIPアドレスです。10.59.13.225
次のように構成します。
10.59.13.240
次のように構成プロキシサーバ、nginx.conf断面プロファイルを逆nginxの:
server
{
listen 80;
server_name 10.59.13.240;
location / {
proxy_pass http://10.59.13.225;
#proxy_rediect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
- で
10.59.13.221
ホストアクセスhttp://10.59.13.240
、結果は図1に示されています。
- 同時に、
localhost
図2に示すように、データベースに記録したIPアドレスを確認します。
10.59.13.221
リバースプロキシサーバーのIPアドレスの代わりに、 サーバーが最初に送信された要求を記録できることがわかります。10.59.13.240
1.5x-forwared-for安全
x-forwared-for
偽造される可能性があります。アプリケーションのシナリオは通常、IPスワイプです。たとえば、1つのIPは1日に1つの投票にしか投票できず、Cookieの検証、検証コードの検証などのテクノロジーは使用されないため、対応する攻撃を実行できます。実際のIPアドレスを取得するように設計する一方x-forwared-for
で、偽造を防ぐために、Cookie検証、検証コード検証などの他のテクノロジーも使用する必要があります。
2.苦い経験
私のCuteKeWebサイトアーキテクチャをまだ覚えていますか?Tencent CloudにデプロイされたサービスはすべてMongoDbを使用してファイルデータを記録しますが、MongoDbの構成が正しくないとセキュリティの問題が発生する可能性があります。
2.1まだデフォルト設定を使用していますか?
MongoDbのデフォルト構成(何も変更しない場合)は安全ではありません。CuteKeWebサイトのファイルサーバーは、いくつかの自動ツールによってスキャンされることが多く、MongoDbもスキャンされて盗まれます。ハッカーは新しく作成された警告データベースには、このデータベースの下にReadmeテーブルがあります。スクリーンショットは次のとおりです。
トゥカオは0.2ビットコインを送ろうとしています、ライオンは口を開けました!しかし、それは私自身の過失だったので、MySQLの構成をすぐに変更しました
2.2MongoDbを安全に構成する
この経験の後、セキュリティ構成の重要性に気づきました。MongoDbを安全に構成するために段階的に見ていきましょう。
- 外部IPを監視しないでください
- デフォルトのポート27017度には適用されません
- 認証モードをオンにする
mongod.cfg
ファイルの内容は次のとおりです。
systemLog:
destination: file
path: e:\mongoDate\log\mongod.log
storage:
dbPath: d:\mongoDate\db
net:
bindIp: 127.0.0.1
port: 27001
security:
authorization: enabled
同時に、ファイルサーバーapplication.properties
構成のuriも変更されます。
spring.data.mongodb.uri=mongodb://use1:123456@localhost:27001/test
ユーザー追加の具体的なプロセスについては、リファレンス5を参照してください。同時に、データの損失がまだ心配な場合は、mongodbデータを毎日バックアップすることを忘れないでください。
3.参考文献
[1] Javaはクライアントユーザーの実際のIPアドレスを取得します
[2] javaのIPアドレスはそれが属するエリアを決定します(baiduインターフェイス)
[3] WEBセキュリティ-偽造X-転送-サーバーのIPアドレスフィルタリングをバイパスするため
[4]なぜ自己構築mongodb突然データが失われました
[5] mongodbは外部ネットワークへのアクセスとアカウントの追加を禁止しています