`ob_start('ob_gzhandler');` 执行错误 和 `header("Content-type: image/png");` 显示图片出错
经过昨天的 PHP 脚本注入代码分析,在删除了相关注入代码后并保存后,今早官网访问又异常了。页面显示空白,与昨日场景如出一辙,但我查看那个公共文件,并没有发现注入代码,似乎一切都很正常。
在彻底卸载相关软件后,依然没有恢复。没办法,只能通过设置输出锚点来确认产生错误的位置。
查找到产生错误的位置(destoon - b2b 框架):
后台开启了 gzip 压缩,所以默认会执行 ob_start('ob_gzhandler')
,也就是这一句出现了错误。
在 PHP 4.0 后开启 zlib 模块就能支持 gzip 压缩,检查 IIS 服务器,压缩静态动态压缩都有勾选,没有问题。
在网上找到一个一篇解决方案:PHP ob_start('ob_gzhandler')提示内容编码错误问题的解决方法:
ob_start()
函数将打开输出缓冲。当输出缓冲激活后,脚本将不会输出内容(除 http 标头外),相反需要输出的内容被存储在内部缓冲区中。但是有时在使用的时候会提示内容编码错误,大概就是两个原因。原因一:
服务器不支持这种压缩格式,解决方案
ob_start('ob_gzhandler')
改成ob_start()
;原因二:
使用
ob_start('ob_gzhandler')
时前面已经有内容输出,解决方案,使用ob_end_clean()
来清除输出的内容;
因为怀疑是之前安装的安全软件导致服务器 gzip 压缩无法使用,所以先尝试了原因一的解决方案:
ob_start('ob_gzhandler')
改成 ob_start()
,并将原来的判断语句直接注释掉。
问题确实解决了,首页访问正常了。但后续又陆续出现的一些错误让我意识到事情没有那么简单。
之后同事反馈获取图形验证码失败了,通过前面的设置输出锚点来确认产生错误的位置:
照理说这是很正常的 http 头部设置了,因为要返回的就是图片。搞不清楚,就去问了百度,看到这篇 header("Content-type: image/png"); 显示图片出错,提到 发送 http 报头前面不能有数据输出。这让我联想到之前ob_start('ob_gzhandler')
报错原因二 使用 ob_start('ob_gzhandler')
时前面已经有内容输出,恍然大悟。问题的根源就是公共文件里在调用这两个函数之前存在内容输出。
找到问题后再去排查,通过设置 ob_end_clean()
代码位置,找到了出现问题的地方:还是昨天的那个被注入的公共文件。打开错误提示,显示 176 行存在内容输出,原来他把注入代码写到后面去了。。。
被注入的公共文件
注入的代码正常情况下是没有输出的,但注入代码标签跟文件原有代码标签之间存在换行输出,这导致了页面空白或警告错误。
好吧,删除相关注入代码,删除 PHP 闭合标签之外的空白行,完工!
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。