一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

通過nginx配置文件抵御攻擊,防御CC攻擊的經(jīng)典思路! | moon's blog

 命運之輪 2016-02-24

0x00 前言

大家好,我們是OpenCDN團隊的Twwy。這次我們來講講如何通過簡單的配置文件來實現(xiàn)nginx防御攻擊的效果。

其實很多時候,各種防攻擊的思路我們都明白,比如限制IP啊,過濾攻擊字符串啊,識別攻擊指紋啦??墒且绾稳崿F(xiàn)它呢?用守護腳本嗎?用PHP在外面包 一層過濾?還是直接加防火墻嗎?這些都是防御手段。不過本文將要介紹的是直接通過nginx的普通模塊和配置文件的組合來達到一定的防御效果。

0x01 驗證瀏覽器行為

簡易版

我們先來做個比喻。

社區(qū)在搞福利,在廣場上給大家派發(fā)紅包。而壞人派了一批人形的機器人(沒有語言模塊)來冒領(lǐng)紅包,聰明工作人員需要想出辦法來防止紅包被冒領(lǐng)。

于是工作人員在發(fā)紅包之前,會給領(lǐng)取者一張紙,上面寫著“紅包拿來”,如果那人能念出紙上的字,那么就是人,給紅包,如果你不能念出來,那么請自覺。于是機器人便被識破,灰溜溜地回來了。

是的,在這個比喻中,人就是瀏覽器,機器人就是攻擊器,我們可以通過鑒別cookie功能(念紙上的字)的方式來鑒別他們。下面就是nginx的配置文件寫法。

  1. if ($cookie_say != "hbnl"){
  2.      add_header Set-Cookie "say=hbnl";
  3.      rewrite .* "$scheme://$host$uri" redirect;
  4. }

讓我們看下這幾行的意思,當cookie中say為空時,給一個設(shè)置cookie say為hbnl的302重定向包,如果訪問者能夠在第二個包中攜帶上cookie值,那么就能正常訪問網(wǎng)站了,如果不能的話,那他永遠活在了302中。你也可以測試一下,用CC攻擊器或者webbench或者直接curl發(fā)包做測試,他們都活在了302世界中。

當然,這么簡單就能防住了?當然沒有那么簡單。

增強版

仔細的你一定會發(fā)現(xiàn)配置文件這樣寫還是有缺陷。如果攻擊者設(shè)置cookie為say=hbnl(CC攻擊器上就可以這么設(shè)置),那么這個防御就形同虛設(shè)了。我們繼續(xù)拿剛剛那個比喻來說明問題。

壞人發(fā)現(xiàn)這個規(guī)律后,給每個機器人安上了揚聲器,一直重復著“紅包拿來,紅包拿來”,浩浩蕩蕩地又來領(lǐng)紅包了。

這時,工作人員的對策是這樣做的,要求領(lǐng)取者出示有自己名字的戶口本,并且念出自己的名字,“我是xxx,紅包拿來”。于是一群只會嗡嗡叫著“紅包拿來”的機器人又被攆回去了。

當然,為了配合說明問題,每個機器人是有戶口本的,被趕回去的原因是不會念自己的名字,雖然這個有點荒誕,唉。

然后,我們來看下這種方式的配置文件寫法

  1. if ($cookie_say != "hbnl$remote_addr"){
  2.      add_header Set-Cookie "say=hbnl$remote_addr";
  3.      rewrite .* "$scheme://$host$uri" redirect;
  4. }

這樣的寫法和前面的區(qū)別是,不同IP的請求cookie值是不一樣的,比如IP是1.2.3.4,那么需要設(shè)置的cookie是say=hbnl1.2.3.4。于是攻擊者便無法通過設(shè)置一樣的cookie(比如CC攻擊器)來繞過這種限制。你可以繼續(xù)用CC攻擊器來測試下,你會發(fā)現(xiàn)CC攻擊器打出的流量已經(jīng)全部進入302世界中。

不過大家也能感覺到,這似乎也不是一個萬全之計,因為攻擊者如果研究了網(wǎng)站的機制之后,總有辦法測出并預(yù)先偽造cookie值的設(shè)置方法。因為我們做差異化的數(shù)據(jù)源正是他們本身的一些信息(IP、user agent等)。攻擊者花點時間也是可以做出專門針對網(wǎng)站的攻擊腳本的。

完美版

那么要如何根據(jù)他們自身的信息得出他們又得出他們算不出的數(shù)值?

我想,聰明的你一定已經(jīng)猜到了,用salt加散列。比如md5("opencdn$remote_addr"),雖然攻擊者知道可以自己IP,但是他無法得知如何用他的IP來計算出這個散列,因為他是逆不出這個散列的。當然,如果你不放心的話,怕cmd5.com萬一能查出來的話,可以加一些特殊字符,然后多散幾次。

很可惜,nginx默認是無法進行字符串散列的,于是我們借助nginx_lua模塊來進行實現(xiàn)。

  1. rewrite_by_lua '
  2.      local say = ngx.md5("opencdn" .. ngx.var.remote_addr)
  3.      if (ngx.var.cookie_say ~= say) then
  4.          ngx.header["Set-Cookie"] = "say=" .. say
  5.          return ngx.redirect(ngx.var.scheme .. "://" .. ngx.var.host .. ngx.var.uri)
  6.      end
  7. ';

通過這樣的配置,攻擊者便無法事先計算這個cookie中的say值,于是攻擊流量(代理型CC和低級發(fā)包型CC)便在302地獄無法自拔了。

大家可以看到,除了借用了md5這個函數(shù)外,其他的邏輯和上面的寫法是一模一樣的。因此如果可以的話,你完全可以安裝一個nginx的計算散列的第三方模塊來完成,可能效率會更高一些。

這段配置是可以被放在任意的location里面,如果你的網(wǎng)站有對外提供API功能的話,建議API一定不能加入這段,因為API的調(diào)用也是沒有瀏覽器行為的,會被當做攻擊流量處理。并且,有些弱一點爬蟲也會陷在302之中,這個需要注意。

同時,如果你覺得set-cookie這個動作似乎攻擊者也有可能通過解析字符串模擬出來的話,你可以把上述的通過header來設(shè)置cookie的操作,變成通過高端大氣的js完成,發(fā)回一個含有doument.cookie=...的文本即可。

那么,攻擊是不是完全被擋住了呢?只能說那些低級的攻擊已經(jīng)被擋住而來,如果攻擊者必須花很大代價給每個攻擊器加上webkit模塊來解析js和執(zhí)行set-cookie才行,那么他也是可以逃脫302地獄的,在nginx看來,確實攻擊流量和普通瀏覽流量是一樣的。那么如何防御呢?下節(jié)會告訴你答案。

0x02 請求頻率限制

不得不說,很多防CC的措施是直接在請求頻率上做限制來實現(xiàn)的,但是,很多都存在著一定的問題。

那么是哪些問題呢?

首先,如果通過IP來限制請求頻率,容易導致一些誤殺,比如我一個地方出口IP就那么幾個,而訪問者一多的話,請求頻率很容易到上限,那么那個地方的用戶就都訪問不了你的網(wǎng)站了。

于是你會說,我用SESSION來限制就有這個問題了。嗯,你的SESSION為攻擊者敞開了一道大門。為什么呢?看了上文的你可能已經(jīng)大致知道了,因為就像那個“紅包拿來”的揚聲器一樣,很多語言或者框架中的SESSION是能夠偽造的。以PHP為例,你可以在瀏覽器中的cookie看到PHPSESSIONID,這個ID不同的話,session也就不同了,然后如果你杜撰一個PHPSESSIONID過去的話,你會發(fā)現(xiàn),服務(wù)器也認可了這個ID,為這個ID初始化了一個會話。那么,攻擊者只需要每次發(fā)完包就構(gòu)造一個新的SESSIONID就可以很輕松地躲過這種在session上的請求次數(shù)限制。

那么我們要如何來做這個請求頻率的限制呢?

首先,我們先要一個攻擊者無法杜撰的sessionID,一種方式是用個池子記錄下每次給出的ID,然后在請求來的時候進行查詢,如果沒有的話,就拒絕請求。這種方式我們不推薦,首先一個網(wǎng)站已經(jīng)有了session池,這樣再做個無疑有些浪費,而且還需要進行池中的遍歷比較查詢,太消耗性能。我們希望的是一種可以無狀態(tài)性的sessionID,可以嗎?可以的。

  1. rewrite_by_lua '
  2.      local random = ngx.var.cookie_random
  3.      if(random == nil) then
  4.          random = math.random(999999)
  5.      end
  6.      local token = ngx.md5("opencdn" .. ngx.var.remote_addr .. random)
  7.      if (ngx.var.cookie_token ~= token) then
  8.          ngx.header["Set-Cookie"] = {"token=" .. token, "random=" .. random}
  9.          return ngx.redirect(ngx.var.scheme .. "://" .. ngx.var.host .. ngx.var.uri)
  10.      end
  11. ';

大家是不是覺得好像有些眼熟?是的,這個就是上節(jié)的完美版的配置再加個隨機數(shù),為的是讓同一個IP的用戶也能有不同的token。同樣的,只要有nginx的第三方模塊提供散列和隨機數(shù)功能,這個配置也可以不用lua直接用純配置文件完成。

有了這個token之后,相當于每個訪客有一個無法偽造的并且獨一無二的token,這種情況下,進行請求限制才有意義。

由于有了token做鋪墊,我們可以不做什么白名單、黑名單,直接通過limit模塊來完成。

  1. http{
  2.      ...
  3.      limit_req_zone $cookie_token zone=session_limit:3m rate=1r/s;
  4. }

然后我們只需要在上面的token配置后面中加入

  1. limit_req zone=session_limit burst=5;

于是,又是兩行配置便讓nginx在session層解決了請求頻率的限制。不過似乎還是有缺陷,因為攻擊者可以通過一直獲取token來突破請求頻率限制,如果能限制一個IP獲取token的頻率就更完美了??梢宰龅絾??可以。

  1. http{
  2.      ...
  3.      limit_req_zone $cookie_token zone=session_limit:3m rate=1r/s;
  4.      limit_req_zone $binary_remote_addr $uri zone=auth_limit:3m rate=1r/m;
  5. }
  1. location /{
  2.      limit_req zone=session_limit burst=5;
  3.      rewrite_by_lua '
  4.      local random = ngx.var.cookie_random
  5.      if (random == nil) then
  6.          return ngx.redirect("/auth?url=" .. ngx.var.request_uri)
  7.      end
  8.      local token = ngx.md5("opencdn" .. ngx.var.remote_addr .. random)
  9.      if (ngx.var.cookie_token ~= token) then
  10.          return ngx.redirect("/auth?url=".. ngx.var.request_uri)
  11.      end
  12. ';
  13. }
  14. location /auth {
  15.      limit_req zone=auth_limit burst=1;
  16.      if ($arg_url = "") {
  17.          return403;
  18.      }
  19.      access_by_lua '
  20.          local random = math.random(9999)
  21.          local token = ngx.md5("opencdn" .. ngx.var.remote_addr .. random)
  22.          if (ngx.var.cookie_token ~= token) then
  23.              ngx.header["Set-Cookie"] = {"token=" .. token, "random=" .. random}
  24.              return ngx.redirect(ngx.var.arg_url)
  25.          end
  26.      ';
  27. }

我想大家也應(yīng)該已經(jīng)猜到,這段配置文件的原理就是:把本來的發(fā)token的功能分離到一個auth頁面,然后用limit對這個auth頁面進行頻率限制即可。這邊的頻率是1個IP每分鐘授權(quán)1個token。當然,這個數(shù)量可以根據(jù)業(yè)務(wù)需要進行調(diào)整。

需要注意的是,這個auth部分我lua采用的是access_by_lua,原因在于limit模塊是在rewrite階段后執(zhí)行的,如果在rewrite階段302的話,limit將會失效。因此,這段lua配置我不能保證可以用原生的配置文件實現(xiàn),因為不知道如何用配置文件在rewrite階段后進行302跳轉(zhuǎn),也求大牛能夠指點一下啊。

當然,你如果還不滿足于這種限制的話,想要做到某個IP如果一天到達上限超過幾次之后就直接封IP的話,也是可以的,你可以用類似的思路再做個錯誤頁面,然后到達上限之后不返回503而是跳轉(zhuǎn)到那個錯誤頁面,然后錯誤頁面也做個請求次數(shù)限制,比如每天只能訪問100次,那么當超過報錯超過100次(請求錯誤頁面100次)之后,那天這個IP就不能再訪問這個網(wǎng)站了。

于是,通過這些配置我們便實現(xiàn)了一個網(wǎng)站訪問頻率限制。不過,這樣的配置也不是說可以完全防止了攻擊,只能說讓攻擊者的成本變高,讓網(wǎng)站的扛攻擊能力變強,當然,前提是nginx能夠扛得住這些流量,然后帶寬不被堵死。如果你家門被堵了,你還想開門營業(yè),那真心沒有辦法了。

然后,做完流量上的防護,讓我們來看看對于掃描器之類的攻擊的防御。

0x03 防掃描

ngx_lua_waf模塊

這個是一個不錯的waf模塊,這塊我們也就不再重復造輪子了??梢灾苯佑眠@個模塊來做防護,當然也完全可以再配合limit模塊,用上文的思路來做到一個封IP或者封session的效果。

0x04 總結(jié)

本文旨在達到拋磚引玉的作用,我們并不希望你直接單純的復制我們的這些例子中的配置,而是希望根據(jù)你的自身業(yè)務(wù)需要,寫出適合自身站點的配置文件。

源文地址

本文地址:http://www./30/1255.html
如非注明則為本站原創(chuàng)文章,歡迎轉(zhuǎn)載。轉(zhuǎn)載請注明轉(zhuǎn)載自:moon's blog
                 

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    日本99精品在线观看| 男人的天堂的视频东京热| 国产老女人性生活视频| 好骚国产99在线中文| 亚洲中文字幕三区四区| 日本午夜福利视频免费观看| 五月婷婷六月丁香亚洲| 久久精品免费视看国产成人| 日韩三极片在线免费播放| 粉嫩一区二区三区粉嫩视频| 亚洲中文字幕高清乱码毛片| 日本不卡在线一区二区三区| 国产国产精品精品在线| 九九热在线视频观看最新| 亚洲国产成人一区二区在线观看| 亚洲视频一区自拍偷拍另类| 好吊视频一区二区在线| 天堂av一区一区一区| 亚洲精品福利视频在线观看| 免费久久一级欧美特大黄孕妇| 免费观看潮喷到高潮大叫| 亚洲国产黄色精品在线观看| 亚洲国产黄色精品在线观看| 日韩欧美三级视频在线| 国产一区二区精品高清免费| 99香蕉精品视频国产版| 国产肥女老熟女激情视频一区| 国产精品亚洲二区三区| 国产高清在线不卡一区| 久久国产青偷人人妻潘金莲| 国产精品亚洲综合天堂夜夜| 日韩人妻一区二区欧美| 一区二区三区日韩中文| 日韩中文无线码在线视频| 欧美又大又黄刺激视频| 欧美美女视频在线免费看| 色涩一区二区三区四区| 国产精品午夜福利免费在线| 欧美多人疯狂性战派对| 欧美做爰猛烈叫床大尺度| 日韩欧美国产高清在线|