Table of Contents
1.现象
自从公司的服务从合作伙伴的机房切换到腾讯云,监控邮件不断收到一些接口的报错日志,典型的如下
JSON parse error: Can not deserialize instance of java.lang.Integer out of START_ARRAY token
报错的后端接口基于Spring RESTful,客户端通过发送基于Json数组来查询订单,传参可以简化为
{
"id": [1,2,3]
}
出现这种错误一般是调用方传错了参数,没通过参数校验。该接口调用方分前端组跟中间件组。考虑到中间件开发语言也为Java,公司已经将远程接口封装为Java实现的Web Service Client 。众所周知Java是一种强类型语言,对数据类型有严格要求, 中间件组写错参数的话直接在编译阶段就会发现问题。那问题应该出现在前端组。
2.定位问题
联系前端组同事审查代码,前端JavaScript客户端代码并没有填写错参数,查看客户端日志打印也显示正常。看到前端同事一脸委屈的样子,问题陷入僵局。由于中间件服务器跟前端服务器都会通过负载均衡调用服务端,又缺少必要的监控,一时很难定位到是哪台服务器发起了错误的调用。后来想到可以把前端服务器跟后端服务器之间的负载平衡摘掉,临时改成直连。经过运维同事的配置,摘掉负载改成直连后如下图所示。服务端实例比前端服务器实例多一台,多出的一台不接受来自前端的调用,当做对比。
再次查看日志监控系统,发现第三台服务器Service3已经没有任何报错,排除服务器自身问题。
- Service1的报错都触发自Client1
- Service2的报错都触发自Client2
可以确定错误的传参就是来自前端服务器。继续请运维同事抓包,在前端Linux服务器上通过tcpdump抓包工具生成抓包文件,把抓包文件导入强大的图形化抓包工具Wireshark分析,根据接口关键字筛选出所有的调用,最终发现某个外部IP(爬虫)频繁通过前端接口传递错误的参数,解析为Json如下,本该传一个数组却传递了一个数组中的数组。
{
"id": [[1]]
}
3.分析
外部爬虫不断地通过穷举的方式调用端口爬取数据,前端JavaScript缺少类型校验。公司迁移到腾讯云后反爬虫套件尚需磨合,给爬虫可乘之机。最后运维同事临时屏蔽掉爬虫的IP,同时升级反爬虫规则。