前言
是这样的一个情况, 最近 我们服务存在这样的一个问题
是在登录界面, 假设我用户名 或者 密码输入错误, 能够得到真确的结果, 拿到了 正常的 http 响应, 回来 "用户名 或者 密码 不正确 "
但是 假设是在 隐私模式下面, 同样的输入, 同样的服务, 但是结果 不一样, 等待 十多秒之后 请求挂了, CONNECTION RESET
错误信息 大概是如下, 呵呵 这个很神奇
另外 还有一个问题就是 当我启动 fiddler 之后, 这个网站的服务就发送发送不出去了
效果 和上面的这个一样, 但是 差别是在于 上面的会 pending 15秒, 但是 启动 fiddler 之后里面就请求失败
问题的调试
通过 抓包 发现, 隐私模式下面发送的请求
发送了一次 /token 请求之后, 后面又进行了 五六次的 tcp 重传
大概的猜测就是 对方服务器 拿到了 tcp 请求之后, 丢弃了该 tcp 包??
呵呵 所以 我写了一套 checksum 计算, 来校验 隐私模式下面出问题的包的 checksum, 但是 发现是 完全对的上的
wireshark 抓包, 发送方正常情况如下
wireshark 抓包, 发送方异常情况如下
通过 http 请求的对比, tcp 整个报文的对比, 发现 二者报文 没有太大的差异
但是 异常情况下, 对方服务器没有确认该包, 然后 发送方进行了重传
tcpdump 抓包, 接收方来查看请求情况如下
我测试的时候, 正常情况测试了三次, 异常情况测试了 三次
但是 抓包的结果, 只能看到 正常情况的这三次请求
另外 tcpdump 日志信息如下, 没有被 内核丢弃的包
[root@localhost sxxzx2019]# tcpdump tcp -i ens192 port 80 -w target.cap
tcpdump: listening on ens192, link-type EN10MB (Ethernet), capture size 262144 bytes
^C47954 packets captured
48001 packets received by filter
0 packets dropped by kernel
但是 还有不确认的地方就是
我们客户端 -> 网闸 -> 互联网服务器, 这个过程中, 网闸上面的情况 我们接触不到
所以 网闸是否接收到 "/token" 的 tcp 包, 这个我们确认不了
另外 这整个问题也很奇怪
这里的配置 之前是有一个 vpn 的, 但是我删除了之后(不确定是否重启) 似乎 隐私模式下面就能够正常访问了? 是因为请求被代理到了这个 vpn??
当然 这个结论待证实
但是打开 fiddler 之后, 来访问该网站, 还是报错
这个 也是遗留下来的问题, 日志如下
# 开启 fidder 之后 发送 http 请求失败
-= Fiddler Event Log =-
17:11:02:7699 [Fiddler] No HTTP request was received from (chrome:6800) new client socket, port 54233.
17:11:04:0902 Fiddler.Network.AutoProxy> AutoProxy Detection failed.
17:11:04:0902 AutoProxy failed. Disabling for this network.
17:11:24:1592 [Fiddler] No HTTP request was received from (chrome:6800) new client socket, port 54247.
17:11:24:2568 [Fiddler] No HTTP request was received from (chrome:6800) new client socket, port 54248.
17:11:24:4004 [Fiddler] No HTTP request was received from (chrome:6800) new client socket, port 54249.
17:11:24:5367 [Fiddler] No HTTP request was received from (chrome:6800) new client socket, port 54252.
chrome 中的错误日志如下
Access to XMLHttpRequest at 'http://61.185.228.1:33111/auth/oauth/token' from origin 'http://61.185.228.1:33111' has been blocked by CORS policy: The request client is not a secure context and the resource is in more-private address space `local`.
auth/oauth/token:1 Failed to load resource: net::ERR_FAILED
可以参考这篇文章
The request client is not a secure context and the resource is in more-private address ...
https://blog.csdn.net/tianzhonghaoqing/article/details/124328920
chrome://flags/#block-insecure-private-network-requests
允许发送 不安全的私有网络请求 即可
Block insecure private network requests.
Prevents non-secure contexts from making sub-resource requests to more-private IP addresses. An IP address IP1 is more private than IP2 if 1) IP1 is localhost and IP2 is not, or 2) IP1 is private and IP2 is public. This is a first step towards full enforcement of CORS-RFC1918: https://wicg.github.io/cors-rfc1918 ®C Mac, Windows, Linux, Chrome OS, Android
#block-insecure-private-network-requests
客户端 本身的域是 61.185.228.1:33111
然后 fiddler 启动之后, 将 61.185.228.1:33111 请求先走 127.0.0.1:8888, 然后 fiddler 代理到目标服务 61.185.228.1:33111
走的是 more-private 的域, 因此 触发了 浏览器的 CROS 保护策略
至于这个 more-private 怎么定义, 多半是一个是 外网, 一个是 本地, 本地会比外网 more private 把
fiddler 一分钟定时捕获失败
默认的 8888 端口是否被占用, 如果被占用, 调整 代理端口
找到 可疑 的 vpn 服务, 关闭
Test01CalcTcpChecksum
为了这个问题, 特地写了一个 tcp 的 checksum 的计算的小程序, 呵呵 分享一下
tcpBody 就贴 从 wireshark 中复制出来的二进制的报文即可
/**
* Test01CalcTcpChecksum
*
* @author Jerry.X.He
* @version 1.0
* @date 2022/10/31 16:20
*/
public class Test01CalcTcpChecksum {
private static int startIpOffset = 0x1a;
private static int tcpLenOffset = 0x2d;
private static int ethHeaderSize = 14, ipHeaderSize = 20, tcpHeaderSize = 20;
private static int totalHeaderSize = ethHeaderSize + ipHeaderSize + tcpHeaderSize;
// Test01CalcTcpChecksum
public static void main(String[] args) {
String tcpBody = "0000 58 25 75 c3 9c b7 b0 6e bf cf 63 db 08 00 45 00\n" +
"0010 05 8a 23 a8 40 00 80 06 b1 51 c0 a8 33 38 3d b9\n" +
"0020 ee da f2 73 83 b0 02 59 f3 05 73 ab 0e 0b 50 18\n";
int[] bytes = loadByteStream(tcpBody);
int tcpBodySize = bytes.length - totalHeaderSize;
Integer zeroAndProtocol = 0x0006;
Integer tcpHeaderAndDataSize = tcpHeaderSize + tcpBodySize;
int dummyHeaderCheckSum = locateInteger(bytes, startIpOffset) + locateInteger(bytes, startIpOffset + 2)
+ locateInteger(bytes, startIpOffset + 4) + locateInteger(bytes, startIpOffset + 6)
+ zeroAndProtocol + tcpHeaderAndDataSize;
int tcpHeaderCheckSum = calcTcpHeaderCheckSum(bytes);
int tcpBodyCheckSum = calcTcpDataCheckSum(bytes, tcpBodySize);
int totalSum = dummyHeaderCheckSum + tcpHeaderCheckSum + tcpBodyCheckSum;
int trimmedTotalSum = ((totalSum & 0xffff0000) >> 16) + (totalSum & 0xffff);
int reversedTotalSum = ~trimmedTotalSum;
String checkSumHexStr = Integer.toHexString(reversedTotalSum).substring(4);
int checkSumInPacket = locateInteger(bytes, ethHeaderSize + ipHeaderSize + tcpHeaderSize - 4);
String checkSumInPacketStr = Integer.toHexString(checkSumInPacket);
// 0x2a80
System.out.println(String.format("%s - %s", checkSumHexStr, checkSumInPacketStr));
if (!Objects.equals(checkSumHexStr, checkSumInPacketStr)) {
throw new RuntimeException(" unexpected checksum ");
}
int x = 0;
}
public static int[] loadByteStream(String lines) {
List<Integer> list = new ArrayList<>();
for (String line : lines.split("\n")) {
String[] splits = line.split("\\s+");
for (int i = 1; i < splits.length; i++) {
int b = Integer.parseInt(splits[i], 16);
list.add(b);
}
}
int[] result = new int[list.size()];
for (int i = 0; i < list.size(); i++) {
result[i] = list.get(i);
}
return result;
}
public static int locateInteger(int[] bytes, int startIdx) {
int byteWeight = (1 << 8);
// 如果是最后一个元素, 补充 0
if (startIdx + 1 >= bytes.length) {
return bytes[startIdx] * byteWeight + 0x00;
// return 0x00 * byteWeight + bytes[startIdx];
}
return bytes[startIdx] * byteWeight + bytes[startIdx + 1];
}
public static int calcTcpHeaderCheckSum(int[] bytes) {
int checkSum = 0;
int checkSumOffset = ethHeaderSize + ipHeaderSize, checkSumIteMax = tcpHeaderSize / 2;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < checkSumIteMax; i++) {
int checkSumByte = locateInteger(bytes, checkSumOffset);
// if is checksum, update checksum to 0
if (i == (checkSumIteMax - 2)) {
checkSumByte = 0;
}
checkSum += checkSumByte;
checkSumOffset += 2;
sb.append(" ").append(Integer.toHexString(checkSumByte));
}
// System.out.println(sb.toString());
return checkSum;
}
public static int calcTcpDataCheckSum(int[] bytes, int tcpBodySize) {
int checkSum = 0;
int checkSumOffset = ethHeaderSize + ipHeaderSize + tcpHeaderSize, checkSumIteMax = (tcpBodySize + 1) / 2;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < checkSumIteMax; i++) {
int checkSumByte = locateInteger(bytes, checkSumOffset);
checkSum += checkSumByte;
checkSumOffset += 2;
sb.append(" ").append(Integer.toHexString(checkSumByte));
}
// System.out.println(sb.toString());
return checkSum;
}
}
执行效果如下
Test02CalcIpChecksum
为了这个问题, 特地写了一个 ip 的 checksum 的计算的小程序, 呵呵 分享一下
tcpBody 就贴 从 wireshark 中复制出来的二进制的报文即可
package com.hx.test14;
import java.util.Objects;
import static com.hx.test14.Test01CalcTcpChecksum.loadByteStream;
import static com.hx.test14.Test01CalcTcpChecksum.locateInteger;
/**
* Test01CalcTcpChecksum
*
* @author Jerry.X.He
* @version 1.0
* @date 2022/10/31 16:20
*/
public class Test02CalcIpChecksum {
private static int startIpOffset = 0x1a;
private static int tcpLenOffset = 0x2d;
private static int ethHeaderSize = 14, ipHeaderSize = 20, tcpHeaderSize = 20;
private static int totalHeaderSize = ethHeaderSize + ipHeaderSize + tcpHeaderSize;
// Test01CalcTcpChecksum
public static void main(String[] args) {
String tcpBody = "0000 58 25 75 c3 9c b7 b0 6e bf cf 63 db 08 00 45 00\n" +
"0010 05 8f 23 a4 40 00 80 06 b1 50 c0 a8 33 38 3d b9\n" +
"0020 ee da f2 1f 83 b0 e9 62 05 3b cb 80 60 a8 50 18\n";
int[] bytes = loadByteStream(tcpBody);
int ipHeaderCheckSum = calcIpHeaderCheckSum(bytes);
int totalSum = ipHeaderCheckSum;
int trimmedTotalSum = ((totalSum & 0xffff0000) >> 16) + (totalSum & 0xffff);
int reversedTotalSum = ~trimmedTotalSum;
String checkSumHexStr = Integer.toHexString(reversedTotalSum).substring(4);
int checkSumInPacket = locateInteger(bytes, ethHeaderSize + ipHeaderSize - 10);
String checkSumInPacketStr = Integer.toHexString(checkSumInPacket);
// 0xb150
System.out.println(String.format("%s - %s", checkSumHexStr, checkSumInPacketStr));
if (!Objects.equals(checkSumHexStr, checkSumInPacketStr)) {
throw new RuntimeException(" unexpected checksum ");
}
int x = 0;
}
public static int calcIpHeaderCheckSum(int[] bytes) {
int checkSum = 0;
int checkSumOffset = ethHeaderSize, checkSumIteMax = ipHeaderSize / 2;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < checkSumIteMax; i++) {
int checkSumByte = locateInteger(bytes, checkSumOffset);
// if is checksum, update checksum to 0
if (i == (checkSumIteMax - 5)) {
checkSumByte = 0;
}
checkSum += checkSumByte;
checkSumOffset += 2;
sb.append(" ").append(Integer.toHexString(checkSumByte));
}
System.out.println(sb.toString());
return checkSum;
}
}
执行效果如下
完