微信服务器IP地址详解,并判断该地址是否来自微信

公众号官网说明:点击进去官方文档

如果公众号基于消息接收安全上的考虑,需要获知微信服务器的IP地址列表,以便识别出哪些消息是微信官方推送给你的,哪些消息可能是他人伪造的,可以通过该接口获得微信服务器IP地址列表。

接口调用请求说明

http请求方式: GET
https://api.weixin.qq.com/cgi-bin/getcallbackip?access_token=ACCESS_TOKEN

参数说明

参数是否必须说明
access_token公众号的access_token

返回说明

正常情况下,微信会返回下述JSON数据包给公众号:

{
	"ip_list":["127.0.0.1","127.0.0.1"]
}
参数说明
ip_list微信服务器IP地址列表

错误时微信会返回错误码等信息,JSON数据包示例如下(该示例为AppID无效错误):

{"errcode":40013,"errmsg":"invalid appid"}

企业号官网说明:点击进去官方文档

获取微信服务器的ip段

  • 请求说明

Https请求方式: GET

https://qyapi.weixin.qq.com/cgi-bin/getcallbackip?access_token=ACCESS_TOKEN

  • 参数说明
参数必须说明
access_token调用接口凭证
  • 返回结果
{
   "ip_list": ["101.226.103.*", "101.226.62.*"]
}



把自己公众号的accesstoken 替换请求地址的ACCESS_TOKEN,然后get请求就可以换取到服务器的ip地址列表了,

但是有一些需要注意的地方(请看返回数据下面的内容);

公证号的ipv4地址段
{
"ip_list": [

"101.226.62.77",
"101.226.62.78",
"101.226.62.79",
···
"180.163.15.170",
"101.226.103.0\/25",
"101.226.233.128\/25",
"58.247.206.128\/25",
"182.254.86.128\/25",
"103.7.30.21",
"103.7.30.64\/26",
"58.251.80.32\/27",
"183.3.234.32\/27",
"121.51.130.64\/27"]
}
企业号的ipv4地址段
{
"ip_list": [

"101.226.103.*",
"101.226.125.*",
"101.226.62.*",
"103.7.30.*",
"112.5.138.*",
"112.90.78.*",
"117.135.171.*",
"120.198.199.*",
"140.207.54.*",
"183.61.32.*",
"203.205.167.*"]
}

请注意:

在返回的数据的地址数据中,公众号中有"101.226.103.0\/25",其中的\/是转义字符/,该地址就是"101.226.103.0/25" ,也就是说这是一个带有子网掩码的ip地址;

打印来自微信的请求头

host:你的服务器网址
user-agent:Mozilla/4.0
content-length:534
accept:*/*
cache-control:no-cache
content-type:text/xml
pragma:no-cache
x-real-ip:58.247.206.153

所以我们不能通过request.getRemoteAddr()获取微信请求的地址,

所以通过request.getHeader("x-real-ip");


同时你也应该发现ip地址58.247.206.153并没有在上面获取的ip地址列表里面

这是觉需要去利用那些带有子网掩码的ip地址了,

	/**
	 * 判断目标ip是否属于某个ip子网
	 * @param subIp		带有子网掩码的ip
	 * @param ip		目标ip
	 * @return			成功true,失败false
	 */
	private static boolean isSubnet(String subIp, String ip) {
		String[] subs = subIp.split("/");
		int[] subnetMask = getSubnetMask(Integer.parseInt(subs[1]));
		int[] ipArray = getIpv4Array(subs[0]);
		String subnet = getSubnet(subnetMask,ipArray);
		int[] ipArray2 = getIpv4Array(ip);
		String subnet2 = getSubnet(subnetMask, ipArray2);
		if (subnet.equals(subnet2))
			return true;
		return false;
	}

	/**
	 * 获取子网掩码数组
	 * @param num	子网掩码长(暨带子网掩码的ip/后面的数字)
	 * @return		长度为4的int数组
	 */
	private static int[] getSubnetMask(int num) {
		int[] masks = new int[4];
		int index = num / 8;
		int remainder = num % 8;
		String remainderToBinary = "";
		for (int i = 0; i < index; i++)
			masks[i] = 255;
		for (int i = 0; i < 8; i++) {
			int j = 0;
			if (i < remainder)
				j = 1;
			remainderToBinary = remainderToBinary + j;
		}
		int sublast = Integer.valueOf(remainderToBinary, 2);
		masks[index] = sublast;
		if (index < masks.length - 1) {
			for (int i = index + 1; i < masks.length; i++)
				masks[i] = 0;
		}
		return masks;
	}
	
	/**
	 * 分解ip地址
	 * @param ip	ip地址
	 * @return		长度为4的int数组
	 */
	private static int[] getIpv4Array(String ip) {
		int[] ipArray = new int[4];
		String[] ips = ip.split("\\.");
		for (int i = 0; i < ips.length; i++) 
			ipArray[i] = Integer.parseInt(ips[i]);
		return ipArray;
	}
	
	/**
	 * 通过子网掩码数组和,ip地址数组获取主机地址
	 * @param masks		子网掩码数组
	 * @param ipArray	ip数组
	 * @return		主机地址
	 */
	private static String getSubnet(int[] masks, int[] ipArray) {
		String subnet = "";
		if (masks.length != ipArray.length) {
			try {
				throw new Exception("子网掩码长度和ip地址长度不一样");
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		for (int i = 0; i < ipArray.length; i++) {
			int and = masks[i] & ipArray[i];
			subnet = subnet + and;
			if (i < ipArray.length -1) 
				subnet = subnet + ".";
		}
		return subnet;
	}


所以,那些带掩码的ip,代表的是在该主机下的所有地址,/25,表示有128个地址,这时就需要计算来得到,而不是简单的字符串匹配!


企业号的就号很多,全部是.*,所以只需要判断前3个数字就可以了!







版权声明:本文为rilaohn原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。