Egg中的安全防範

之前獲取前端安全方面的知識很是零碎且大多停留在看,又或者本身在實際項目中用到了其實也不太清楚。經過此次egg項目實踐能更加深入的理解。egg在框架中內置了安全插件 egg-security, 提供了默認的安全實踐。html

HSTS

HSTS 指的是Http Strict Transport Security,是響應頭的信息,它告訴瀏覽器只能經過HTTPS訪問當前資源,而不是HTTP。前端

Http的請求明文傳輸過程當中,信息均可以被中間人(通訊運營商,代理,路由器廠商等)獲取,可能形成數據泄漏,請求劫持,內容篡改等,web

場景:用戶直接輸入域名www.baidu.com,不輸入http或者https,默認是http訪問,http的訪問會給用戶返回一個302重定向到https的地址,後續的訪問都是https傳輸。那麼在這個http到302重定向的過程可能會被劫持篡改。chrome

開啓hsts 在站點的響應頭中設置Strict-Transport-Security,瀏覽器會將這個域名加入Hsts列表,下次用戶早使用http訪問這個網站,瀏覽器會自動發送https請求(但第一次訪問仍是http),而不是先發送http再重定向到https,避免302重定向url被篡改,進一步提升通訊的安全性。json

以訪問www.baidu.com爲例子測試分析segmentfault

  • 打開chrome://net-internals/#hsts,如今delete domain中輸入www.baidu.com刪除,而後在query hsts中輸入www.baidu.com出現not found證實緩存已經清除。

  • 在瀏覽器直接輸入www.baidu.com,會看到先發送http請求而後302的https重定向

  • 打開https的詳情信息,能夠看到Strict Transport Security響應頭,max-age表示hsts有效期

  • 再次在瀏覽器中輸入www.baidu.com會看到與第一次請求不一樣,此次是307重定向,表示瀏覽器作內部轉換,將http轉換爲https。

  • 回到chrome://net-internals/#hsts,query www.baidu.com能夠看到瀏覽器已經緩存了百度的hsts。

egg-security的防範 文檔上說的是默認開啓,可是看了下源碼默認是false,須要手動開啓。瀏覽器

// default
hsts: {
  enable: false,
  maxAge: 365 * 24 * 3600,
  includeSubdomains: false, //能夠添加子域名,保證全部子域名都使用 HTTPS 訪問。
}
複製代碼

CSRF

Cross Site Request Forgery,跨站域請求僞造,重點在僞造的請求,CSRF 攻擊能夠在受害者絕不知情的狀況下以受害者名義僞造請求發送給受攻擊站點。緩存

最經典的例子安全

受害者 Bob 在銀行有一筆存款,經過對銀行的網站發送請求 http://bank.example/withdraw?account=bob&amount=1000000&for=bob2 可使 Bob 把 1000000 的存款轉到 bob2 的帳號下。一般狀況下,該請求發送到網站後,服務器會先驗證該請求是否來自一個合法的 session,而且該 session 的用戶 Bob 已經成功登錄。黑客想到使用 CSRF 的攻擊方式,他先本身作一個網站,在網站中放入以下代碼: src=」http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory 」,而且經過廣告等誘使 Bob 來訪問他的網站。當 Bob 訪問該網站時,上述 url 就會從 Bob 的瀏覽器發向銀行,而這個請求會附帶 Bob 瀏覽器中的 cookie 一塊兒發向銀行服務器。大多數狀況下,該請求會失敗,由於他要求 Bob 的認證信息。可是,若是 Bob 當時恰巧剛訪問他的銀行後不久,他的瀏覽器與銀行網站之間的 session 還沒有過時,瀏覽器的 cookie 之中含有 Bob 的認證信息,操做成功。bash

這個操做看起來很玄乎,其實咱們常常點擊一些外部信息的時候也會有這個過程,好比說我在juejin中點擊一個原文連接跳轉到sf:

點擊訪問時就會帶上sf站點的cookie,假如攻擊者將這個連接改成對用戶有安全隱患的操做,sf又沒有作防範的話,csrf攻擊就成功了。(另外從圖中的referer能夠看到請求的來源。)

攻擊原理 黑客經過藉助受害者的cookie騙取服務器的信任,可是自己是沒有辦法獲取cookie值的。

防範方法:

  1. 驗證referer字段。
  • 從上述圖中能夠看到服務器中是能獲取到referer的,將全部有安全敏感的請求都加一個referer的過濾攔截。
  • 問題:referer是由瀏覽器提供的,雖然http有協議規定,但各個瀏覽器對referer的實現可能會有誤差,不能保證瀏覽器自己沒有安全漏洞。把安全性依賴於第三方瀏覽器來保障,理論上並不可靠。舊的瀏覽器有些能夠被篡改referer,即便沒法被篡改,用戶若是擔憂referer留下用戶的訪問來源也能夠在瀏覽器設置不記錄referer信息。
  1. 經過token值校驗
  • token的校驗有不少方式,實際上就是拿到服務端給的一個特定值,在發送請求時把這個值帶上,服務端確認是本身簽發的token。

egg-security 中csrf的防範:

  • 在默認配置下,egg-security會在cookie中設置token值,由於csrf攻擊這是僞造請求,並不能實際獲取cookie值,所以經過校驗的請求才能實際發生。

  • egg-security只用csrf策略不保護get, head, options and trace四個方法,由於這四個方法被認爲是安全的方法,不須要受到 CSRF 的保護,由於它們不會對應用程序進行更改,即便它們返回敏感信息,也會受到瀏覽器中的同源策略的保護。

  • 在發送請求時egg-security會經過headerName/queryName/bodyName的字段去獲取token值作校驗,在 AJAX 請求的時候,能夠從 Cookie 中取到 csrfToken(插件會把httponly設置爲false讓Js能夠操做),放置到 query、body 或者 header 中發送給服務端。如:xhr.setRequestHeader('x-csrf-token', csrftoken);

// config/config.default.js
module.exports = {
  security: {
    csrf: {
      headerName: 'x-csrf-token', // 經過 header 傳遞 CSRF token 的默認字段爲 x-csrf-token
      queryName: '_csrf', // 經過 query 傳遞 CSRF token 的默認字段爲 _csrf
      bodyName: '_csrf', // 經過 body 傳遞 CSRF token 的默認字段爲 _csrf
    },
  },
};
複製代碼
// egg-security csrf.js
 module.exports = options => {
  return function csrf(ctx, next) {
    if (utils.checkIfIgnore(options, ctx)) {
      return next();
    }

    // 在cookie中設置token值
    ctx.ensureCsrfSecret();

    // ignore requests: get, head, options and trace
    const method = ctx.method;
    if (method === 'GET' ||
      method === 'HEAD' ||
      method === 'OPTIONS' ||
      method === 'TRACE') {
      return next();
    }

    if (options.ignoreJSON && typeis.is(ctx.get('content-type'), 'json')) {
      return next();
    }

    const body = ctx.request.body || {};
    debug('%s %s, got %j', ctx.method, ctx.url, body);
    // 判斷token是否爲預期
    ctx.assertCsrf();
    return next();
  };
};
複製代碼

刷新token cookie在設置時若是沒有明確expires默認是session,這個session的意思跟sessionStorage的做用時間不同,sessionStorage只要關閉tab就不會保留數據,但cookie默認expires值session只有關閉瀏覽器token纔會失效從新賦值。因此在用戶登陸的時候須要刷新token,egg提供了ctx.rotateCsrfSecret();從新設置csrfToken。

CSP

CSP(Content Security Policy)指定資源可信任來源(腳本、圖片、iframe、fton、style等等可能的遠程的資源),減小(注意這裏是減小而不是消滅)跨站腳本攻擊。 egg-security 中csp默認是不開啓的,須要熟悉csp的policy配置Content Security Policy (CSP) 是什麼?爲何它能抵禦 XSS 攻擊

// 只容許本站資源
    csp: {
      enable: true,
      policy: {
          'default-src''self'
      },
    }
複製代碼

XST

Cross-Site Tracing客戶端經過http trace請求到服務器,服務器若是按照處理了trace請求會在response body中返回全部的請求頭信息,包括httponly的cookie。

好比說這裏的cookie test是httponly,正常來講js是不能操做的,可是經過trace請求可以直接將這些信息返回。

Trace請求: 客戶端發起一個請求可能要通過多個代理,網關等,每一個節點均可能修改原始的http請求,trace方法能夠看到發到服務端是請求頭最終的樣子,TRACE 方法主要用於診斷。

TRACE 請求會在目的服務器端發起一個 環回 診斷。行程最後一站的服務器會彈回一條 TRACE 響應,並在響應主體中攜帶它收到的原始請求報文。這樣客戶端就能夠查看在全部中間 HTTP 應用程序組成的請求 / 響應鏈上,原始報文是否,以及如何被毀壞或修改過。

egg-security的防範:判斷方法爲trace或者track時會返回405(Method Not Allowed)錯誤

// default
methodnoallow: {
  enable: true
}
複製代碼

釣魚攻擊

URL釣魚 網站中可能須要經過參數拼接成一個新的url讓用戶點擊訪問,若是參數是由用戶輸入的,可能會致使構形成一個惡意的網站連接,誘導用戶跳轉欺騙用戶輸入用戶名密碼,由於是信任的網站跳轉的,用戶比較信任。

防範 egg中由兩種服務端跳轉的方法,ctx.redirect(url)會通過配置白名單的校驗後再進行跳轉,若是domainWhiteList 爲空則與ctx.unsafeRedirect(url)跳轉同樣不進行校驗。 // default exports.security = { domainWhiteList: [] }

iframe釣魚 經過內嵌 iframe 到被攻擊的網頁中能夠誘導用戶點擊危險網站,遮蓋影響網站的正常功能。

防範 X-Frame-Options HTTP 響應頭是用來給瀏覽器 指示容許一個頁面 能否在 , , 或者 中展示的標記。 egg-security提供了xframe的選項,默認是SAMEORIGIN,只容許同域把本頁面看成 iframe 嵌入。

// default
xframe: {
  enable: true,
  // 'SAMEORIGIN', 'DENY' or 'ALLOW-FROM http://example.jp'
  value: 'SAMEORIGIN',
}
複製代碼

參考連接

相關文章
相關標籤/搜索