Skip to content

安全开发经验

应付扫描器类

扫描器规则较为死板,有很多规则较为古老,针对的是all in one的项目环境或者较为古老的技术,几乎不适用于近年的前端后分离、分布式部署项目。但某些场合下,不得不处理这些告警项。

HTTP动词篡改的认证旁路

问题原因

没有找到相关的详细资料,找到的内容均为各厂商扫描器给的描述,没有发现利用价值。但可能与WebDAV有关,WebDAV会按照HTTP动词在服务器上进行文件操作。

缓解方法

编写接口时,严格限制请求方法,明确拒绝不使用的方法(如OPTIONS、DELETE、PUT)。

检测到目标URL启用了不安全的HTTP方法

问题原因

同时开启了HTTP监听和HTTPS监听

缓解方法

如非必要,只开启HTTPS监听

前端各类问题

场景

  1. 前端类库版本低
  2. 前端注释包含了作者或其他贡献者的联系方式(尤其是email) regexp \S+@\S+\.\S+
  3. 前端注释包含了类库版本号
  4. 前端文件名包含了类库版本号
  5. 前端提示包含了管理员等中英文字样
  6. 前端提示包含了操作系统路径
  7. 前端提示包含了IP地址
  8. 发现无效链接

缓解手段

  1. 开发时,类库尽量选择最新且没有已知漏洞的RELEASE版本;
  2. 前端类库进入打包环节时,必须删除所有注释;
  3. 前端类库文件中的版本号必须清除;
  4. 及时清除无用的接口调用,有需要时通过git记录找回原来的调用代码;
  5. 容易产生误报的提示信息,转义处理,展示时通过js控制反转义显示,从而规避误报;

HTTP头部利用类

检测到目标URL存在http host头攻击漏洞

复现场景

访问项目根目录(https://xiaolong.test/),重定向到下载客户端页面(https://xiaolong.test/app)

复现步骤

  1. 使用任意拦截工具拦截发送到服务的请求;
  2. 修改请求头中的Host为任意地址(正常情况下,Host内容是xiaolong.test;恶意用户可以改为www.evil.com);
  3. 发送修改后的请求。

问题原因

Nginx在做代理时,location配置块中有如下配置

nginx
proxy_set_header Host $host:$server_port;

$host取值顺序如下:

  1. 从Request Line取;
  2. 从Headers中的Host字段取;
  3. 请求匹配到的server_name;

因为Request Line中没有Host相关信息,只有URI,所以尝试从Headers的Host中取值,恶意用户改写的Host就被用上了。与HTTP/1.1标准5.2 The Resource Identified by a Request描述一致。
业务代码中只重定向URI,所以客户端收到的302消息中Location部分的域名部分就变为了www.evil.com,整个Location就变成了https://www.evil.com/app

解决方案

扫描报告给的解决方案如下:

web应用程序应该使用SERVER_NAME而不是host header。
在Apache和Nginx里可以通过设置一个虚拟机来记录所有的非法host header。在Nginx里还可以通过指定一个SERVER_NAME名单,Apache也可以通过指定一个SERVER_NAME名单并开启UseCanonicalName选项。

扫描报告的解决方案适合to C场景,而我们的场景是在内网环境,都是通过IP访问,没有域名,也不会要求用户在DNS服务器上指定解析记录,所以固定server_name的方法行不通。
查找Nginx文档,有一个$server_addr变量,在http模块中,该变量代表接收请求的那个服务的地址(可以简单粗暴理解为接收这个http请求的网卡的IP,就算用域名访问也没用,就是IP)

上述方案可以解决这个安全问题,但是有两个弊端:

  1. nginx所在主机不能再有前置机,否则这个ip会不准(比如nginx在docker的网络中);
  2. $server_addr每次会有一次系统调用,有潜在的性能风险;

检测到目标Content-Security-Policy响应头缺失

Content-Security-Policy用来控制当前站点可以从哪里加载资源。

解决方案

只允许请求当前域的资源

nginx
server {
    ...
    add_header Content-Security-Policy "default-src 'self';";
    ...
}

检测到目标Strict-Transport-Security响应头缺失

Strict-Transport-Security用来告诉浏览器,能用HTTPS就用HTTPS。

解决方案

max-age的单位为秒,表示该头部的过期时间,includeSubdomains代表对子域是否生效。

nginx
server {
    ...
    add_header Strict-Transport-Security "max-age=3600; includeSubdomains";
    ...
}

检测到目标Referrer-Policy响应头缺失

Referrer-Policy用来控制请求头中的Referer字段值。

解决方案

strict-origin-when-cross-origin策略:同源请求发送完整的URL,包含请求字符串;跨域请求时,如果安全等级相同,则发送URL不带URI部分;如果安全等级下降,则不带Referer字段。

nginx
server {
    ...
    add_header Referrer-Policy "strict-origin-when-cross-origin";
    ...
}

检测到目标X-Permitted-Cross-Domain-Policies响应头缺失

X-Permitted-Cross-Domain-Policies 似乎不是标准的HTTP头字段,百度上找到的解释几乎抄的都是同一篇,google上找到的解释也几乎一样,是用来控制adobe产品加载跨站资源的。

解决方案

项目中未使用adobe的产品,但为了不让扫描器继续报这个风险,所以在nginx配置中添加对应配置,参数值使用master-only。

nginx
server {
    ...
    add_header X-Permitted-Cross-Domain-Policies "master-only";
    ...
}

检测到目标X-Download-Options响应头缺失

X-Download-Options是给IE8及以上浏览器使用的,告诉浏览器怎么处理下载的文件。
在IE8中,如果选择“打开”下载的HTML文件,则会在下载来源页面的上下文中执行这个HTML文件,进而实施cookie窃取等活动。

解决方案

nginx配置中添加该头部,且值设为noopen,这样下载文件时,就没有“打开”这一选项了,只能保存或取消。

nginx
server {
    ...
    add_header X-Download-Options "noopen";
    ...
}

参数校验类

XSS

攻击手段

上传表单时参数传值:

html
"<img src="https://xiaolong.test/img/installimg.png"></img>;<img src="https://xiaolong.test/img/installimg.png"></img>

html
atestu#*/-->'");><a href="http://xiaolong.test/app">LinkInjTest</a>

问题原因

  1. 服务端未对参数值进行转义;
  2. 前端或模板直接将参数值拼接到页面代码中,未进行转义;

举例

前端代码:

html
$("docuemnt").html('<input name="anything" value="'+示例代码段1+'" />')

缓解方法

  1. 服务端在保存参数时,均进行转义处理再入库;
  2. 服务端在保存参数时,去除敏感内容,如html标签;
  3. 前端在使用URL参数时,不要直接将参数值拼接到执行代码中;

文件上传类

假设如下场景:
文件上传接口为http://xiaolong.test/upload.action
表单接受文件的参数名为uploadFile
文件落盘位置为/tmp/xiaolongupload/

路径穿透

攻击手段

  1. 上传的文件名包含相对路径
  2. 上传压缩包,压缩包内的文件名包含相对路径

问题原因

文件在服务端落盘,且直接使用传入的文件名。

举例

  1. uploadFile文件名为../../../../etc/hosts,直接拼接后落盘位置变为/tmp/xiaolongupload/../../../../etc/hosts
  2. 压缩包内含有一个文件名为../../../../etc/hosts的文件,解压后实际落盘位置变为/tmp/xiaolongupload/xxx/../../../../etc/hosts

缓解方案

方案1:
不使用表单上传的文件名,使用自定义的文件名,如UUID等。
方案2:
去除文件名中包含的"."或".."等相对路径字符;或使用File API,获取拼接后的实际路径。一旦发现不在安全范围,则拒绝接口请求。

任意文件上传

攻击手段

  1. 文件重命名,修改后缀名为业务允许的后缀名并上传

问题原因

  1. 仅在客户端进行了后缀名限制,服务端未验证文件类型;
  2. 服务端验证逻辑简单,导致验证被绕过;

举例

业务要求上传pdf文件,但恶意用户将1.js文件重命名为1.pdf上传。

缓解方案

  1. 服务端对文件后缀进行校验;
  2. 服务端对文件魔数进行校验;
  3. 任何时刻都不要在服务器环境执行上传的文件;

参考资料

Nginx $host 解释
Nginx $server_addr 解释
jQuery XSSMozilla CSP 文档
前端安全配置之Content-Security-Policy(csp)
HSTS设置
Mozilla Referrer-Policy文档
Secure HTTP Headers
XDownloadOptions相关