Android NanoHttp超长请求头死循环问题

场景:

项目中集成了NanoHttp,用于在Android端搭建了http与https服务访问。

问题:

①:新版本开发时,某一次安全扫描中,出现了一次设备执行网络安全扫描后,http服务无法访问,但是https服务能正常访问,重启设备后恢复。当时版本由于安全修改了安全策略,日志中无法打印请求头信息,并且后续再次触发安全扫描也没复现。

②:2个月后,在老版本维护项目中,在安全扫描后,出现http服务能访问,但设备响应较慢问题。同样,https服务访问正常,没有出现响应慢问题。由于老版本还没在日志中限制对请求头的打印,于是可以进行模拟请求来复现与排查。

排查:

①:通过两个份日志排查出,在出现http服务响应异常时,均为一条“/src/acloglogin.php”的url一直在循环请求,导致http通路一直被占用。但在设备处于死循环状态时,通过tcpdump对设备http端口抓包,但并没有抓到对应的请求,说明并非外部循环请求导致,而是内部代码逻辑出现了问题。

②:通过第2份日志可以获取到该条http请求中的header内容,异常点:headers中,参数字符长度非常长。使用Http服务的demo进行模拟复现,通过ApiFox来模拟该条“/src/acloglogin.php”请求,并结合tcpdump抓包。

③:通过抓包可以看出,整个请求的长度为8343 byte,实际请求一次,就会出现死循环问题。

④:使用同样的请求,删减掉 headers 中大部分字段长度,发起请求,没有出现死循环问题。
由上述信息可证实,由 headers 中超长串的参数字符导致。
⑤:于是,查看 nanohttp 源码的请求解析过程,发现其 buffer 最大为 8kb。并且通过 debug
调试,接收超长 header 后,一直循环在执行 execute 解析过程。
⑥:通过 debug 调试可以分析出,核心问题为 nanohttp 对流处理不恰当导致。由于请求头
header 长度已经超过了 buffer 的大小,导致解析 header 时,未能找请求头末尾节点,
splitbyte=0,进而导致后续判断中,调用 inputstream 的 skip 方法时一直传入的是 0(这里
调用 skip 的目的是为了跳过已读取的流),导致出现死循环读取。
⑦:Github 上最新源码中,该问题依然存在

解决:

①:加入测试代码,在 splitbyte == 0 时,认为需要跳过整个 buffer 长度,测试发现不在出现
死循环问题。
②:修改方案:采用服务端拒绝连接方式,计算请求中的 headers 总长度 totalHeaderSize。
当 totalHeaderSize >= 阈值 MAX_HEADERS_PARAM_SIZE 时,则返回 http 标准错误码 431,
对应的。
③:修改后的抓包请求,存在 431 返回值,修改完成。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值