用户
搜索

[其他安全] Nginx配置安全

  • TA的每日心情
    开心
    2018-6-5 10:38
  • 签到天数: 2 天

    连续签到: 2 天

    [LV.1]初来乍到

    SRC部落

    Rank: 7Rank: 7Rank: 7

    13

    主题

    18

    帖子

    137

    魔法币
    收听
    1
    粉丝
    0
    注册时间
    2018-6-4

    SRC部落

    发表于 2018-6-20 16:03:25 544131

    Author: JoyChou@Meili-inc
    Date:  20180620

    隐藏Nginx版本

    不发送nginx版本号在错误页面以及http的header中。

    server_tokens off;

    修改Nginx版本需要源码编译的时候,修改/src/core/nginx.h内容,这种修改方式从根本上修改。

    #define NGINX_VERSION      "1.9.15"
    #define NGINX_VER          "nginx/" NGINX_VERSION

    也可以其他通过指定Http Header的Server内容方式进行修改,具体可Google。

    防止钓鱼

    有些垃圾钓鱼页面,就用一个<iframe>,就开始进行钓鱼,成本极低。

    可通过X-Frame-Options选项来防止网站被iframeframe

    add_header X-Frame-Options SAMEORIGIN;

    X-Frame-Options还有一些其他选项,可以看文档

    防止XSS

    可通过X-XSS-Protection进行反射的XSS拦截。

    add_header X-XSS-Protection "1; mode=block";

    $uri导致的CRLF注入

    先来看下Nginx配置中3个关于$uri变量的区别:

    • $uri
    • $document_uri
    • request_uri
    变量名 取值 是否解码 对应Lua Nginx模块变量名
    $uri URL路径,不包括host和参数 URL解码 ngx.var.uri
    $document_uri URL路径,不包括host和参数 URL解码 ngx.var.uri
    $request_uri URL路径,不包括host,但包括参数 不进行URL解码 ngx.var.request_uri

    也就是说,$uri$document_uri是一样的。之所以能造成CRLF注入,是因为这两个参数会进行URL解码。

    以下nginx指令如果配置不当,就会造成CRLF注入:

    rewrite
    return
    add_header
    proxy_set_header
    proxy_pass

    比如:

    vuls_nginx_1.conf

    location /sectest {
      return 302 https://$host$uri;
    }

    Response Header如下,从返回可以看到$uri进行了URL解码。成功进行注入。

    curl -v 'joychou.org/sectest/12%203%0d%0ajoychou=1'
    
    < HTTP/1.1 302 Moved Temporarily
    < Server: nginx
    < Date: Fri, 30 Jun 2017 08:19:52 GMT
    < Content-Type: text/html
    < Content-Length: 154
    < Connection: keep-alive
    < Location: https://joychou.org/sectest/12 3
    < joychou=1
    < x-frame-options: SAMEORIGIN

    修复方式:
    $uri或者$document_uri改为$request_uri

    其他的存在漏洞的nginx配置:

    vuls_nginx_2.conf

    location / {
        rewrite ^ https://$host/$uri;
    }

    vuls_nginx_3.conf

    server {
        listen 80 default;
    
        location ~ /v1/((?<action>[^.]*)\.json)?$ {
            add_header X-Action $action;
            return 200 "OK";
        }
    }

    alias导致的任意文件读取

    漏洞配置如下:

    location /files {
      alias /home/;
    }

    很多人看到第一反应可能是这样的。

    这配置居然还能有任意文件读取

    这个常见于 Nginx 做反向代理的情况,动态的部分被 proxy_pass 传递给后端端口,而静态文件需要 Nginx 来处理,放在前端的Nginx服务器上。

    当访问http://joychou.me/files/x.txt,即访问服务器上的/home/x.txt文件。但是当我们访问files../etc/passwd,其实访问的服务器上/home../etc/passwd,也就是/etc/passwd文件。想知道漏洞原因,可以分析下nginx对alias处理的源代码。

    curl http://joychou.me/files../etc/passwd
    root:x:0:0:root:/root:/bin/bash
    bin:x:1:1:bin:/bin:/sbin/nologin
    daemon:x:2:2:daemon:/sbin:/sbin/nologin
    adm:x:3:4:adm:/var/adm:/sbin/nologin

    修复方法:

    只要不写成上面那种有漏洞的形式,其他三种方式都没问题,比如结尾都带着/字符。

    location /files/ {
      alias /home/;
    }

    看到phith0n师傅给gixy提了一个issue,gixy应该很快就能支持该漏洞扫描了 -)

    proxy_pass导致的SSRF

    SSRF出现在反向代理的配置中,反向代理的语法如下:

    proxy_pass http://ip:port/uri/;

    如果ip可控,那么反向代理的机器会对该ip发起http请求,即可造成SSRF。这种场景多出现在云WAF、CDN、高防DDOS等网络产品。

    拿云WAF举例,在填写回源IP时,此时的IP肯定可控,如果没限制内网IP,那么肯定会造成SSRF。某云厂商之前的网络类产品,全部存在SSRF,不过现在应该已经修复了。

    下图是ucloud的云WAF配置图,在填写源站IP时,如果源站IP填写ucloud的内网IP,可能就会造成SSRF。

    下图是阿里云的云WAF配置图,在填写服务器ip时,如果IP填写阿里云的内网IP,可能就会存在SSRF。

    当然,我觉得这种很傻的配置,运维应该不会配置出来吧。所以就没讨论的必要了。不过需要说明的是,proxy_pass只支持http/https协议。

    location ~ /proxy/(.*)/(.*)/(.*)$ {
        proxy_pass $1://$2/$3;
    }

    add_header重定义

    add_header官方文档

    语法

    Syntax: add_header name value [always];
    Default:    —
    Context:    http, server, location, if in location

    There could be several add_header directives. These directives are inherited from the previous level if and only if there are no add_header directives defined on the current level.

    if in location的意思是如果location区块有add_header,那么以location为准。如果location没有add_header,则继承Http和server块的add_header内容。

    那么,如下这样的配置就存在问题了。

    server {
      listen 80;
      add_header X-Frame-Options "DENY" always;
      location / {
          return 200 "index";
      }
    
      location /new-headers {
        # Add special cache control
        add_header Cache-Control "no-cache, no-store, max-age=0, must-revalidate" always;
        add_header Pragma "no-cache" always;
    
        return 200 "new-headers";
      }
    }

    访问/new-headers就不会继承server块的X-Frame-Options "DENY"

    $http_host导致host欺骗

    反向代理的时候,绝对多数都会设置请求中的host,比如:proxy_set_header Host   $host;

    错误配置如下:

    proxy_set_header Host   $http_host;

    现在来解释下为什么$http_host变量有问题。做以下测试:

    nginx配置

            location /host {
                return 200 "'$host' (host) VS '$http_host' (http_host)";
            }

    当我们用burp做如下设置时,$http_host获取到的域名是evil.com。那么问题来了,如果有代码对域名进行处理,这种情况下,域名可控,导致可能会存在各种各样的安全问题。

    1

    所以,我们需要使用$host代替$http_host。感谢gixy作者解答 -)

    当然了,nginx的配置安全绝对不止这点内容,后续如果碰到会继续扩展。

    参考文章

    1. https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#xfo
    2. https://github.com/yandex/gixy
    3. https://www.leavesongs.com/PENETRATION/nginx-insecure-configuration.html
    美丽联合安全应急响应中心(MLSRC),主要负责处理美丽联合集团旗下产品和业务的安全问题,欢迎广大安全专家、安全爱好者沟通交流(https://security.mogujie.com)~
    666666666666666666666666666666666
    使用道具 举报 回复
    感谢分享
    使用道具 举报 回复

    相互学习~
    美丽联合安全应急响应中心(MLSRC),主要负责处理美丽联合集团旗下产品和业务的安全问题,欢迎广大安全专家、安全爱好者沟通交流(https://security.mogujie.com)~
    使用道具 举报 回复
    发表于 2018-6-25 10:38:14
    学习了,另外再补充一条,我们nginx一般都要配置限制网站只能通过域名访问,避免被扫描
    if ( $host !~* 'xxx.com' ) {  
        return 403;  
    }  
    使用道具 举报 回复
    发表于 2018-10-9 11:24:53
    支持一下~
    使用道具 举报 回复
    发新帖
    您需要登录后才可以回帖 登录 | 立即注册