網站最近攻擊防禦心得,個人網站搭建心得

ht_sauce發表於2019-12-11

序言

我也是很頭疼,我這個小破網站居然有人攻擊。還特麼的連續攻擊。本來吧小網站我覺得就是自己寫寫部落格,然後大家給我評論下。互幫互助,團結友愛。結果吧,我被教育了。挺慘痛的回憶。

然後就是個人站長的流量問題。

一、網際網路站點要點

1、搜尋引擎

這個很重要,就是,一定要服務端渲染。

沒有別的原因,你的網站如果是面向搜尋引擎的你必須是服務端渲染。不然是沒法被很好的搜尋,提升排名的。

我個人網站比較隱私,就沒搞那些東西了。不過我下一次必須要嘗試下服務端渲染,不然目前為止經驗尚淺啊。

2、流量問題

這裡說的流量問題和搜尋之類沒有什麼關係,就是單純的記住,別把圖片放上去。太吃流量了。你只是個小破站,就別搞那麼多了。

我為了圖片訪問速度和伺服器資源節省,把圖片放在了oss儲存上面,但是我想說。還是很貴的。

3、錢(圖片問題)

我給大家算一筆帳

目前伺服器(1核1G1M)是aliyun的,三年300,很便宜是吧,但是這是搞特價,正常一年需要一千。

如果你的網站開發的時候優化做的還可以,那麼首屏流量能控制在1M左右。這樣其實很快。

但是主要是圖片這塊。你如果把圖片放自己伺服器,那麼頻寬就不能很低,不然卡死。

如果放oss,那麼流量是按訪問量計算的。具體好像是1G2毛,總之挺貴的。你要是圖片很多,注意,隨便頁面切換,重新整理單人就能給你刷走上百流量。人數稍微多點……,之前知道一個公司。半年,流量費用20萬(主要用於視訊監控)。

所以個人博主們,自己的小破站圖片少放。

圖片最好是做好防盜鏈。不然流量也會很痛苦。

二、防禦機制舉例

這裡我先copy下阿里在eggjs方面的防禦,主要大家就是遇到這些了。

  • XSS 攻擊:對 Web 頁面注入指令碼,使用 JavaScript 竊取使用者資訊,誘導使用者操作。
  • CSRF 攻擊:偽造使用者請求向網站發起惡意請求。
  • 釣魚攻擊:利用網站的跳轉連結或者圖片製造釣魚陷阱。
  • HTTP引數汙染:利用對引數格式驗證的不完善,對伺服器進行引數注入攻擊。
  • 遠端程式碼執行:使用者通過瀏覽器提交執行命令,由於伺服器端沒有針對執行函式做過濾,導致在沒有指定絕對路徑的情況下就執行命令。

我這次遇到的攻擊是CSRF方面的攻擊。

三、網站防禦的過程

1、監控你的介面訪問

後端:記錄下每個介面每次呼叫的的記錄。

前端:記錄下每個路由的變化之後的訪問記錄

這兩個是很簡單的記錄方式,但是能讓你最直觀的感受到,網站訪問的量是多少。還有就是監控你的網站是否惡意呼叫介面,惡意訪問等等。很直觀,很用好。

本身我是沒有增加該項功能的。但是經過慘痛教訓之後,我痛定思痛。增加了對應的記錄。

通過介面呼叫的分析,得出對方是軟體重新整理頁面不斷惡意給我傳送評論

2、一輪交鋒,限制每個ip的傳送頻率(失敗)

這裡我貼下我中介軟體的程式碼,上面的說實在沒什麼意義,隨便寫一下中介軟體,資料庫記錄下資料即可。很簡單。

這裡我增加了redis,如果用資料庫效能不合適,並且不需要這麼笨重。快取比較不錯。至於為什麼不存在全域性變數。這個我得和大家科普下,不管是nodejs還是java等後端。是存在多執行緒或者多程式的。那麼一旦負載的時候,系統切換另一個程式,那麼就訪問不到資料了。

下面是限制訪問的中介軟體程式碼。

'use strict';

module.exports = (options, app) => {
  return async function(ctx, next) {
    try {
      const ip = ctx.request.header['x-forwarded-for'];
      const req_url = ctx.request.url;
      // 得到最終url地址
      const url = req_url.indexOf('?') === -1 ?
        req_url :
        req_url.substring(0, req_url.indexOf('?'));
      // 儲存當前介面訪問資訊,後續有統計
      ctx.service.interface.apiVisit.add({
        ip,
        url,
      });
      // 當前時間
      const time = new Date().getTime();
      // 獲取這個使用者該介面上次呼叫時間
      const usr_api = await app.redis.get(ip + url);
      // 攔截的介面
      const intercept_api = options.api[url];

      // 引數獲取完畢,設定最新引數
      // 設定介面最新呼叫時間
      await app.redis.set(ip + url, new Date().getTime());
      if (intercept_api) {
        if (time - usr_api > 5000) {
          await next();
        } else {
          ctx.body = ctx.helper.result('', -1, '限制訪問' + intercept_api / 1000 + '秒', 0);
        }
      } else {
        await next();
      }
    } catch (e) {
      ctx.logger.warn(e);
    }
  };
};複製程式碼

配置部分config.js

// 給'interfaceRestriction'傳入引數
config.interfaceRestriction = {
  // api封禁
  api: {
    '/dream-admin/noauth/blog/discuss/add': 1000 * 8,
  },
  // ip封禁,
  ip: [
    // '127.0.0.1',
  ],
};複製程式碼

上面的ip封禁沒有寫。暫時用不到

功能還可以擴充,比如限制ip,限制某個介面的訪問頻率等等。

3、第二輪(增加驗證碼)交鋒(勝利)

上面失敗的主要原因在於,ip實際上是可以偽造的。而且ip偽造成本很低。所以,你通過ip來限制對方這種爬蟲的惡意攻擊效果並不好,這隻能防止那些惡意灌水的人罷了。爬蟲分分鐘幾十上百萬給你攻擊過來,效果不好。

後來我在想怎麼才合適。

本身攻擊屬於csrf,但是通過csrf的方式來防禦對方沒有用。因為csrf本身是一種基於口令的方式。通過爬蟲工具,很容易可以竊取你的口令。

最後我就想著實在沒什麼好辦法就增加驗證碼了。

最後,用了 svg-captcha包。

下面是使用方式,比較簡單:

controller程式碼:

const { ctx, app } = this;
try {
  // 生成算數驗證碼
  const verify = svgCaptcha.createMathExpr({
    size: 4,
    ignoreChars: '0o1i',
    noise: 5,
    color: true,
    background: '#7E7D78',
  });
  // 以ip為單位儲存驗證碼
  const ip = ctx.request.header['x-forwarded-for'];
  await app.redis.set(ip, verify.text);
  ctx.response.type = 'image/svg+xml'; // 知道你個返回的型別
  ctx.body = verify.data;
} catch (e) {
  ctx.body = ctx.helper.result('', -1, e);
}複製程式碼

最後在建立評論的地方,增加驗證即可。

四、總結

1、所有的一切都是為了增加對方破譯的難度

2、不要對外開放建立資料的介面(萬惡之源)

3、做好資料監控,防範於未然。並且讓你能儘快的發現問題

4、如果你對外開放介面了,那麼請做好防小人的準備。(驗證碼真的是一個好東西)

5、所有驗證碼不如手機驗證碼來的可靠。


其實最後下來還是比較老套的一些東西。只是吧,好不容易勝利了。得發發動態。


相關文章