10月02日-三方汇率:7.98(仅供参考)
更多
APP下载
合作
商城
签到

产业资讯 产业资讯 由论坛频繁遭CC和DDOS而想到的

[复制链接]
  • TA的每日心情
    开心
    2024-7-27 12:46
  • 签到天数: 56 天

    96

    主题

    226

    伯币

    2611

    积分

    吉普尼乘客

    积分
    2611
    发表在  2023-9-7 21:43:56 | 显示全部楼层 | 阅读模式
       最近,某位攻城狮私下找我诉苦,说我们论坛又被攻击啦,我说,咋样,又被D啦还是被C啦?他说一会儿被D,一会儿被C,烦求得很,公司都准备买高仿IP啦。于是就有了下文。在楼主的精心搜索和实践下,有了下面的一篇类原创,切勿照搬,可以模仿。

           其实很多时候,各种防攻击的思路我们都明白,比如限制IP啊,过滤攻击字符串啊,识别攻击指纹啦。可是要如何去实现它呢?用守护脚本吗?用PHP在外面包 一层过滤?还是直接加防火墙吗?这些都是防御手段。不过本文将要介绍的是直接通过nginx的普通模块和配置文件的组合来达到一定的防御效果。

    1. 验证浏览器行为
       1.1. 简易版
    我们先来做个比喻。社区在搞福利,在广场上给大家派发红包。而坏人派了一批人形的机器人(没有语言模块)来冒领红包,聪明工作人员需要想出办法来防止红包被冒领。于是工作人员在发红包之前,会给领取者一张纸,上面写着“红包拿来”,如果那人能念出纸上的字,那么就是人,给红包,如果你不能念出来,那么请自觉。于是机器人便被识破,灰溜溜地回来了。是的,在这个比喻中,人就是浏览器,机器人就是攻击器,我们可以通过鉴别cookie功能(念纸上的字)的方式来鉴别他们。下面就是nginx的配置文件写法:
    • if ($cookie_say != "helloboniu"){
    •     add_header Set-Cookie "say=helloboniu";
    •     rewrite .* "$scheme://$host$uri" redirect;
    • }


    复制代码
          让我们看下这几行的意思,当cookie中say为空时,给一个设置cookie say为helloboniu的302重定向包,如果访问者能够在第二个包中携带上cookie值,那么就能正常访问网站了,如果不能的话,那他永远活在了302中。你也可以测试一下,用CC攻击器或者webbench或者直接curl发包做测试,他们都活在了302世界中。
          当然,这么简单就能防住了?当然没有那么简单。
       1.2. 增强版
       仔细的你一定会发现配置文件这样写还是有缺陷。如果攻击者设置cookie为say=helloboniu(CC攻击器上就可以这么设置),那么这个防御就形同虚设了。我们继续拿刚刚那个比喻来说明问题。坏人发现这个规律后,给每个机器人安上了扬声器,一直重复着“红包拿来,红包拿来”,浩浩荡荡地又来领红包了。这时,工作人员的对策是这样做的,要求领取者出示有自己名字的户口本,并且念出自己的名字,“我是xxx,红包拿来”。于是一群只会嗡嗡叫着“红包拿来”的机器人又被撵回去了。当然,为了配合说明问题,每个机器人是有户口本的,被赶回去的原因是不会念自己的名字,虽然这个有点荒诞,唉。
    <span]这样的写法和前面的区别是,不同IP的请求cookie值是不一样的,比如IP是1.2.3.4,那么需要设置的cookie是say=helloboniu1.2.3.4。于是攻击者便无法通过设置一样的cookie(比如CC攻击器)来绕过这种限制。你可以继续用CC攻击器来测试下,你会发现CC攻击器打出的流量已经全部进入302世界中。
    <span]1.3. 完美版
    <span]很可惜,nginx默认是无法进行字符串散列的,由于楼主最近在学习lua,偶然发现了nginx的一个模块,于是我们借助nginx_lua模块来进行实现。详情请看 https://github.com/loveshell/ngx_lua_waf
    • rewrite_by_lua '
    •      local say = ngx.md5("helloboniu" .. ngx.var.remote_addr)
    •      if (ngx.var.cookie_say ~= say) then
    •     ngx.header["Set-Cookie"] = "say=" .. say
    •     return ngx.redirect(ngx.var.scheme .. "://" .. ngx.var.host .. ngx.var.uri)
    •      end
    • ';


    复制代码
    <span]这段配置是可以被放在任意的location里面,如果你的网站有对外提供API功能的话,建议API一定不能加入这段,因为API的调用也是没有浏览器行为的,会被当做攻击流量处理。并且,有些弱一点爬虫也会陷在302之中,这个需要注意。
    <span]那么,攻击是不是完全被挡住了呢?只能说那些低级的攻击已经被挡住而来,如果攻击者必须花很大代价给每个攻击器加上webkit模块来解析js和执行set-cookie才行,那么他也是可以逃脱302地狱的,在nginx看来,确实攻击流量和普通浏览流量是一样的。那么如何防御呢?下节会告诉你答案。
    1.2. 请求频率限制
    不得不说,很多防CC的措施是直接在请求频率上做限制来实现的,但是,很多都存在着一定的问题。
          那么是哪些问题呢?
    <span]于是你会说,我用SESSION来限制就有这个问题了。嗯,你的SESSION为攻击者敞开了一道大门。为什么呢?看了上文的你可能已经大致知道了,因为就像那个“红包拿来”的扬声器一样,很多语言或者框架中的SESSION是能够伪造的。以PHP为例,你可以在浏览器中的cookie看到PHPSESSIONID,这个ID不同的话,SESSION也就不同了,然后如果你杜撰一个PHPSESSIONID过去的话,你会发现,服务器也认可了这个ID,为这个ID初始化了一个会话。那么,攻击者只需要每次发完包就构造一个新的SESSIONID就可以很轻松地躲过这种在SESSION上的请求次数限制。
    <span]首先,我们先要一个攻击者无法杜撰的sessionID,一种方式是用个池子记录下每次给出的ID,然后在请求来的时候进行查询,如果没有的话,就拒绝请求。这种方式我们不推荐,首先一个网站已经有了session池,这样再做个无疑有些浪费,而且还需要进行池中的遍历比较查询,太消耗性能。我们希望的是一种可以无状态性的sessionID,可以吗?可以的。
    • rewrite_by_lua '
    •      local random = ngx.var.cookie_random
    •      if(random == nil) then
    •           random = math.random(999999)
    •      end
    •      local token = ngx.md5("helloboniu" .. ngx.var.remote_addr .. random)
    •      if (ngx.var.cookie_token ~= token) then
    •          ngx.header["Set-Cookie"] = {"token=" .. token, "random=" .. random}
    •          return ngx.redirect(ngx.var.scheme .. "://" .. ngx.var.host .. ngx.var.uri)
    •      end
    • ';


    复制代码
    <span]然后我们只需要在上面的token配置后面中加入
    •     limit_req zone=session_limit burst=5;


    复制代码
    <span]看个完整一点的吧:
    • location /{
    •     limit_req zone=session_limit burst=5;
    •     rewrite_by_lua '
    •     local random = ngx.var.cookie_random
    •     if (random == nil) then
    •         return ngx.redirect("/auth?url=" .. ngx.var.request_uri)
    •     end
    •     local token = ngx.md5("helloboniu" .. ngx.var.remote_addr .. random)
    •     if (ngx.var.cookie_token ~= token) then
    •         return ngx.redirect("/auth?url=".. ngx.var.request_uri)
    •     end
    •     ';
    • }
    • location /auth {
    •     limit_req zone=auth_limit burst=1;
    •     if ($arg_url = "") {
    •         return403;
    •     }
    •     access_by_lua '
    •     local random = math.random(9999)
    •     local token = ngx.md5("helloboniu" .. ngx.var.remote_addr .. random)
    •     if (ngx.var.cookie_token ~= token) then
    •         ngx.header["Set-Cookie"] = {"token=" .. token, "random=" .. random}
    •         return ngx.redirect(ngx.var.arg_url)
    •     end
    •     ';
    • }


    复制代码
    <span]
    <span]
    <span]于是,通过这些配置我们便实现了一个网站访问频率限制。不过,这样的配置也不是说可以完全防止了攻击,只能说让攻击者的成本变高,让网站的扛攻击能力变强,当然,前提是nginx能够扛得住这些流量,然后带宽不被堵死。如果你家门被堵了,你还想开门营业,那真心没有办法了。
    <span]
    1.3. 防扫描
    ngx_lua_waf模块
    <span]我能做的就只有这些了,剩下的就靠伯乐的大神运维啦。最后,其实我不希望大家照搬上面的配置,需要自己去研究,比如配置参数,还有nginx各个模块的安装等,都需要自己亲自实践的。
    最后写了这么多,望伯乐大神们打赏一点博币,也不枉我写了这么多。。。


  • TA的每日心情
    开心
    2024-9-10 09:22
  • 签到天数: 179 天

    271

    主题

    273

    伯币

    1万

    积分

    版主

    积分
    13170
    发表于 2023-9-7 21:44:35 | 显示全部楼层
    楼主只讲了在WEB层面上的防御
    有些环节天生有缺陷  防御要花成本的
    上CDN 大流量来了 挨个打死
    有防御   拿个上层G口带宽照样堵死你
    :lol

    该用户从未签到

    0

    主题

    19

    伯币

    126

    积分

    Zzy新手村

    积分
    126
    发表于 2023-9-8 14:03:15 | 显示全部楼层
    :funk::funk::funk::funk::funk::funk:
  • TA的每日心情
    开心
    3 小时前
  • 签到天数: 204 天

    394

    主题

    4471

    伯币

    9478

    积分

    八打雁行者

    积分
    9478
    发表于 2023-9-8 14:36:23 | 显示全部楼层
    大神666,没有什么能形容我此刻的心情,犹如滔滔江水,连绵不绝,一发不可收拾也

    发表回复

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    快速回复 返回顶部 返回列表