从限流谈到伪造 IP(nginx remote_addr) - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
ChristopherWu
V2EX    推广

从限流谈到伪造 IP(nginx remote_addr)

  •  
  •   ChristopherWu 2019-03-11 14:01:30 +08:00 8415 次点击
    这是一个创建于 2412 天前的主题,其中的信息可能已经有所发展或是发生改变。

    来自我的公众号 『 YongHao 写东西的 Cache 』 打个小广告,还是希望写的东西有人看

    分享一下见解,权当抛砖引玉


    从限流谈到伪造 IP ( nginx remote_addr )

    remote_addr

    很多流量大的网站会限流,比如一秒 1000 次访问即视为非法,会阻止 10 分钟的访问。

    通常简单的做法,就是通过 nginx 时,nginx 设置

     proxy_set_header X-Real-IP $remote_addr; 

    nginx 的 $remote_addr代表客户端的访问 ip,把它设到 http 请求的头部 X-Real-IP ;然后程序取出并存入数据库,统计访问次数。

    remote_addr 基本上不能被伪造,因为是直接从 TCP 连接信息中获取的,也就是 netstatForeign Address那栏。

    你想想, 客户端 A 与 B 服务器建立 TCP 连接,是不是 B 肯定知道 A 的公网地址是什么呢,除非客户端 A 是经过了一个代理服务器 Z, 那么就是 A -> Z -> B, 服务器 B 拿到的只能是 Z 的 ip 地址了,但这不意味就是伪造 ip,限流依然有效。

    nginx 转发

    上述应对外网访问,没有任何问题。假如公司内部需要测试,不停的访问服务器上的程序时,并且经过负载均衡或者 nginx 转发时,也就是 client -> nginx1 -> nginx2 -> server, remote_addr 就变成了 nginx2 的内网地址了。

    因此,需要在 nginx1处,e client 的 remote_addr, 再传给 nginx2,server 再取出。

    示例:

     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 

    $proxy_add_x_forwarded_for$remote_addr 加到 X-Forwarded-For 头部后面;最后设在 my_ips

    如果是需要做 ip 统计,地理信息获取,天气定位等,需要常用的另一个 http 头部, X-Forwarded-For 来做处理。通过名字就知道,X-Forwarded-For 是一个 HTTP 扩展头部。HTTP/1.1 ( RFC 2616 )协议并没有对它的定义,它最开始是由 Squid 这个缓存代理软件引入,用来表示 HTTP 请求端真实 IP。如今它已经成为事实上的标准,被各大 HTTP 代理、负载均衡等转发服务广泛使用,并被写入 RFC 7239( Forwarded HTTP Extension )标准之中。1

    然后 my_ips 就代表了请求从 client 到 server 的完整 ip 路径, 只要由后往前推,直到 找到 外网的 ip,就证明这就是 client 的真正 ip。

     bb_real_ip = request.environ.get('my_ips') bb_real_ip = bb_real_ip.replace(" ", "").split(',') for ip in reversed(bb_real_ip): if not is_private(ip): return ip # 不可能出现这种情况, 除非 LBS/nginx 没有设$proxy_add_x_forwarded_for return request.environ.get('REMOTE_ADDR') 

    这样取到的也是真实的 ip 地址,但有一个问题,假如 client 跟其他很多 client 通过同一个出口出来,共享一个外网 ip,那么如何获取它的 ip 呢?

    这个情况下,限流一样可以生效,最多就是稍微误杀下无辜,影响不大。

    伪造 ip (也就是 remote_addr )

    那么,有办法伪造 remote_addr吗? 其实本质就是,TCP 连接中,有办法伪造 ip 信息吗?

    请看如何用 hping3 工具发出伪装 ip 的包到 google.com

    $ sudo apt-get install hping3 $ sudo hping3 --icmp --spoof 6.6.6.6 baidu.com HPING baidu.com (eth0 220.181.57.216): icmp mode set, 28 headers + 0 data bytes 

    另一个控制台抓 icmp 包:

    $ sudo tcpdump -i eth0 'icmp' 21:24:58.562844 IP 6.6.6.6 > 220.181.57.216: ICMP echo request, id 11035, seq 5120, length 8 

    可以看到, 我们成功的伪装成 6.6.6.6 并向 baidu.com 发出了 ping (也就是 ICMP 包),不过由于我们的 IP 实质上并不是6.6.6.6,所以收不到 baidu.com 发往 它的 ICMP 包。

    模拟的原理是,自己重新实现系统的 tcp ( ICMP )协议栈,然后 自己改变自己的 ip。

    值得一提的八卦是,hping 的作者是 Salvatore Sanfilippo,同时他也是 redis 的作者。

    试想一下,可以通过这个办法来做借刀杀人伪造一个 ip (如4.4.4.4),大量发包给第三方(如 Google ),然后第三方返回 TCP reset 或者 ICMP unreachable 给 你伪造的 ip(4.4.4.4), 这样就可以借 Google 来 ddos 4.4.4.4了。2

    但是现在运营商的路由器都部署了 uRPF,可以根据你发过来的源 ip 检测是否在路由表中,不在就拒绝掉此请求。

    30 条回复    2019-03-12 09:38:03 +08:00
    hxsf
        1
    hxsf  
       2019-03-11 14:07:30 +08:00
    1. TCP 有握手
    2. 不能放大的攻击有啥用? 第三方 D 对面的流量 === 你 D 第三方的流量。
    tabris17
        2
    tabris17  
       2019-03-11 14:09:12 +08:00   1
    9012 年了,还有这种伪科学文章啊
    rochek
        3
    rochek  
       2019-03-11 14:10:41 +08:00 via Android   1
    过去,一般打机器的时候是做跳板的。
    后来,跳板容易被反追,有人用伪造 ip,再中途拿包转发这个妖路。

    可以了解一下。
    ChristopherWu
        4
    ChristopherWu  
    OP
       2019-03-11 14:14:40 +08:00
    yexm0
        5
    yexm0  
       2019-03-11 14:16:59 +08:00 via Android
    @Livid 公众号推广
    ChristopherWu
        6
    ChristopherWu  
    OP
       2019-03-11 14:22:10 +08:00
    @rochek 已感谢。 自己中途拿包转发,是自己容许伪造 ip 的请求过来对吧?那么效果如何,可行吗?
    ChristopherWu
        7
    ChristopherWu  
    OP
       2019-03-11 14:23:31 +08:00
    @yexm0 v 站里不允许宣传公众号吗,还是不允许宣传推广?

    我还见过每个帖子都带上自己博客的。。还有一堆博客的帖子,那些属于博客推广吗?
    ChristopherWu
        8
    ChristopherWu  
    OP
       2019-03-11 14:24:32 +08:00
    @tabris17 还是很不爽你的说法,请您说出哪里伪科学了。。。
    rochek
        9
    rochek  
       2019-03-11 14:25:55 +08:00 via Android
    @ChristopherWu 特定环境下的小聪明
    tabris17
        10
    tabris17  
       2019-03-11 14:31:34 +08:00
    @ChristopherWu

    1. 伪造 IP 源的数据包会被 ISP 的路由器丢弃
    2. 想要实现 TCP 的三次盲握手必须能猜解出对方的 IP 数据包的序列号,那你还不如直接猜出对方数据库密码呢

    标题搞个噱头,通篇文章毫无意义
    oott123
        11
    oott123  
       2019-03-11 14:54:16 +08:00
    这种文章不提一下 nginx 的 set_real_ip_from 指令吗?
    j0hnj
        12
    j0hnj  
       2019-03-11 15:03:20 +08:00
    @tabris17 #2 我也想知道怎么就伪科学了
    ChristopherWu
        13
    ChristopherWu  
    OP
       2019-03-11 15:03:36 +08:00   1
    @tabris17 你再看看我的标题? 注意是『谈到』 。。。不是做到,而且我文章也提及是做不到以及说明了原因。

    所以你的『标题搞个噱头』从何而来?接下来的『通篇文章毫无意义』更是毫无根据了。

    对你没什么用的,但是在我的角度来看,比起配置啥啥,如何安装,算法题解等重复的文章有用了一点。
    www5070504
        14
    www5070504  
       2019-03-11 15:10:15 +08:00
    抛砖引玉 这个真的是砖 感觉真没啥用。。。这个连握手第一步都过不去的吧。。
    0ZXYDDu796nVCFxq
        15
    0ZXYDDu796nVCFxq  
       2019-03-11 15:15:36 +08:00 via Android
    楼主是真的抛砖
    1134506391
        16
    1134506391  
       2019-03-11 15:28:47 +08:00
    <script>alert("aa")</script>
    goodryb
        17
    goodryb  
       2019-03-11 15:51:37 +08:00
    估计楼主也就是顺手一抄,楼上不要太较真
    VoidChen
        18
    VoidChen  
       2019-03-11 15:52:44 +08:00
    对我我这种外行来说还是能受到一点启发的
    CristopherWu
        19
    ChristopherWu  
    OP
       2019-03-11 16:00:40 +08:00
    @www5070504

    注意文中最后一句,『但是现在运营商的路由器都部署了 uRPF,可以根据你发过来的源 ip 检测是否在路由表中,不在就拒绝掉此请求。』。

    回复前,尤其是负面性评论时,能否先认真看看呢?。。
    ryd994
        20
    ryd994  
       2019-03-11 16:07:50 +08:00 via Android
    要是真听了你的就出事了,连猜 TCP 都不用,直接伪造 x-forwarded-for。
    所以必须设置 set_real_ip_from,同时前端反代必须覆盖这个 header 而不是按照默认配置拼接。

    然后你这个攻击思路一看就是拍脑袋。1.没有放大系数,其实完全没有必要反射。直接带宽上去打死就行了。没必要纠结协议。只要能路由到对方端口,都是一样的。
    2. RST 怎么就能 DDoS 了?且不说人家前面套 CDN,CDN 都是硬件清洗。就算靠自己软防火墙抗,一条 conntrack 规则就可以把这些全部 drop 掉了,不会对 CPU 构成压力。要么你占满带宽打死,那还用什么 RST ?见 1,直接暴力打就是了。
    ChristopherWu
        21
    ChristopherWu  
    OP
       2019-03-11 16:20:14 +08:00
    @ryd994

    关于`proxy_add_x_forwarded_for`, 你怎么伪造都好啊,与我无关,我取的只是最后的 `$remote_addr`,你与前端建立连接时,`$remote_addr`就几乎不可能伪造。

    > $proxy_add_x_forwarded_for
    > the “ X-Forwarded-For ” client request header field with the $remote_addr variable appended to it, separated by a comma.
    请看 http://nginx.org/en/docs/http/ngx_http_proxy_module.html


    关于攻击思路,请看 https://www.wikiwand.com/en/Denial-of-service_attack#/Backscatter,写的时候忘记放进去文章了
    ChristopherWu
        22
    ChristopherWu  
    OP
       2019-03-11 16:21:55 +08:00
    ryd994
        23
    ryd994  
       2019-03-11 17:31:03 +08:00   4
    @ChristopherWu
    “ the “ X-Forwarded-For ” client request header field with the $remote_addr variable appended to it, separated by a comma.“
    这就是我说的拼接。正确做法是在前端 proxy_set_header X-Forwarded-For $remote_addr; 在后端 set_real_ip_from。
    按你的做法,到应用内再处理,不仅开销大,而且 nginx 的 access_log 就完全没意义了。Nginx 明明做好的你不用,还要自己造轮子。

    "backscatter is a side-effect of a spoofed denial-of-service attack ”
    你英文不及格。这是副作用而不是攻击手段和主要目的。用你的例子来讲,被攻击的是 Google 的服务器,只不过 Google 会以为是另一个 IP 在 syn flood 它。但是实际上都是有硬件清洗的。硬件先和你握手,三次握手成功之后再去和服务器握手。syn flood 很难完成三次握手。除非你破解了对方的 seq 生成随机算法。对于没有足够熵源的服务器来说,这种攻击从协议上来讲是有机会的。后来的 CPU 都有熵发生器了,这种攻击也就彻底不可行了。

    写安全类文章前,不如自己搭个服务器,去 hostloc 挑衅一下,看看自己是怎么死的,再教别人。恕我直言,我认为你没有运维过一个公开服务的 nginx http 反代,很可能连服务器管理的经验也没有。
    ChristopherWu
        24
    ChristopherWu  
    OP
       2019-03-11 18:03:49 +08:00
    @ryd994 谢谢你的回复,非常有帮助。
    我确实之前不知道`set_real_ip_from`这个模块,我稍候再想想怎么改对目前的程序。

    > 恕我直言,我认为你没有运维过一个公开服务的 nginx http 反代,很可能连服务器管理的经验也没有。
    实不相瞒,我有。。而且就是这样子做的。。

    另外,写文章就是总结下自己学到的东西啊,我不可能知道很多对的事情应该怎么做,身边说不定也没有人知道,所以像现在贴上来,不就收到了你的建议了吗 - = -
    zeraba
        25
    zeraba  
       2019-03-11 19:04:20 +08:00 via Android   1
    就和 ryd994 说的一样,多层其实设置好 header 后用 realip 模块可以搞定,另外,针对同一个出口的策略也需要调整了,可以自己生成 id 作为用户识别,毕竟移动网络下,这种情况很常见,还有可以深入写下 ng 多层代理后的 header 情况
    ChristopherWu
        26
    ChristopherWu  
    OP
       2019-03-11 19:24:58 +08:00
    @zeraba
    已感谢。 请问『针对同一个出口的策略也需要调整了,可以自己生成 id 作为用户识别』可以细讲一下吗?

    『有可以深入写下 ng 多层代理后的 header 情况』这个是指啥意思呢?有哪些 header 需要关注?
    zeraba
        27
    zeraba  
       2019-03-11 20:51:31 +08:00 via Android
    @ChristopherWu 你现在限流是针对 ip 其实可以通过 cookie lua 可以 set cookie 如果项目不是基于 cookie 比如小程序之类的 可以在 url 设置某个参数标识用户 再限流,至于多层,举个例子,X-Forwarded-For 这个变量就可以展开,一层是什么情况,内网多层是什么情况,如何排除中间的 ip 其他变量当然也可以深入,可以拓宽一点理解整个 proxy 模块
    msg7086
        28
    msg7086  
       2019-03-12 01:04:56 +08:00
    我刚打开的时候就觉得这写得都什么玩意儿,谈 nginx 不谈 real_ip 那还谈什么。9012 年了还谈 forwarded-for 伪造。
    翻了下回复,看来我不是第一个这么觉得的。

    > 实不相瞒,我有。。而且就是这样子做的。。
    建议找个懂的来做运维。
    抱歉,我说话比较冲。

    如果自己不确定,那么就开贴直接问。把错误的知识写成科普性文章是很不好的行为。
    freaking
        29
    freaking  
       2019-03-12 09:07:54 +08:00 via Android
    好喷
    Paradisiaercy
        30
    Paradisiaercy  
       2019-03-12 09:38:03 +08:00 via iPhone
    以网络安全角度来看,不知道说了什么。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2679 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 23ms UTC 01:14 PVG 09:14 LAX 18:14 JFK 21:14
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86