应怎么防范文件上传漏洞
去年某招聘平台被曝出漏洞,应防攻击者上传了一个伪装成简历的范文WebShell,直接拿到了服务器权限。传漏事后查日志,应防发现文件上传接口只检查了Content-Type,范文而攻击者把PHP文件改成image/jpeg就绕过了。传漏这种案例太多了,应防几乎每隔几个月就能听到类似的范文事。
文件上传漏洞的传漏核心问题就一个:你让用户传上来的东西,最终跑在了你的应防服务器上。不管它叫.jpg还是范文.png,只要服务器把它当脚本执行,传漏你就输了。应防所以防范思路得从“怎么判断文件安全”转变成“怎么让不安全的范文文件永远没机会执行”。
先切断执行路径
最直接的传漏办法是让上传目录彻底失去执行权限。Nginx里加一行location /uploads { location ~ \.(php|jsp|asp|py)$ { deny all; } },Apache用<Directory>标签把php_admin_flag engine off塞进去。这样就算传了个PHP马进去,访问它只会返回源码或者403,不会执行。
但光这样不够。有些老系统把上传目录和Web根目录混在一起,或者用.htaccess重新打开了执行权限。我见过一个案例,上传目录里有个.htaccess文件写着AddType application/x-httpd-php .jpg,结果所有jpg都能当PHP跑。所以还得禁止上传.htaccess、.user.ini这类配置文件。
文件名和路径别信用户
用户传上来的文件名里可能带../../或者..%2f,直接拼接保存路径就能穿越到系统目录。更常见的坑是空字节截断,比如shell.php%00.jpg,某些旧版语言会把它当成shell.php保存。
我习惯的做法是:完全丢弃原始文件名,用UUID或者时间戳+随机数重命名。后缀名从白名单里取,比如只允许jpg、png、gif、pdf,其他一律拒绝。白名单比黑名单靠谱,因为黑名单永远列不全——你禁了php,还有phtml、php5、pht、phar。
内容检测不能只看MIME
前端传的Content-Type可以随便改,后端不能信。但后端用getimagesize()也不够,因为攻击者可以在图片末尾追加PHP代码,getimagesize()照样返回正常尺寸。更狠的是把PHP代码塞进图片的EXIF注释里,配合本地文件包含漏洞就能触发。
比较稳的方案是二次渲染。把用户上传的图片用GD或者ImageMagick重新生成一遍,所有元数据和附加数据都会被剥离。但要注意ImageMagick本身出过不少漏洞,比如ImageTragick,所以得用最新版本并且禁用危险coder。
对于非图片文件,比如PDF、Word,可以丢进沙箱或者用ClamAV扫一遍。但别指望杀毒引擎能100%查出来,它只是多一层门槛。
存储和访问要隔离
上传的文件别放在Web目录下。存到独立磁盘或者对象存储里,通过后端脚本读取再输出。比如用户访问/download?id=xxx,后端根据id查数据库找到真实路径,用readfile()输出,同时设置Content-Disposition: attachment强制下载。这样文件永远不会被Web服务器直接解析。
如果非要把文件放在Web目录,至少得让上传目录和主站不同域。比如主站是www.example.com,上传文件放在static.example.com。不同域之间Cookie不共享,就算传了XSS也能降低危害。但注意别用子目录,子目录同源,Cookie照样带过去。
日志和监控得跟上
上传接口的日志要记录原始文件名、重命名后的路径、文件大小、MIME类型、上传者IP。我见过一个攻击者连续传了20个不同后缀的WebShell,从php到phtml到php5,如果监控到短时间内大量上传失败或者异常后缀,直接封IP。
另外,定期扫描上传目录里有没有脚本文件。用find /uploads -type f -name "*.php" -o -name "*.jsp",发现就告警。别觉得重命名了就安全,万一哪天配置被改了呢。
说到底,文件上传漏洞的根因是信任了用户的输入。把用户当敌人,别信文件名、别信类型、别信内容,只信白名单和隔离。听起来麻烦,但比起被拖库,这点麻烦真不算什么。
本文地址:http://www.79wt.cn/news/1589d1499827.html
版权声明
本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。