egg學習筆記第七天:eggjs post提交數據,egg安全機制CSRF防範、以及配置模板全局變量

1、eggjs post提交數據

在eggjs如何接受用戶提交的post數據呢?javascript

①:在routerjs中新建兩個路由規則:html

router.get("/doLogin", controller.login.doLogin);

  router.post("/userLogin", controller.login.getUserData);

第一個訪問/doLogin,執行login controller下的doLogin方法,渲染login頁面。java

第二個訪問/userLogin,執行login controller下的getUserData方法,打印接收的post數據。git

②緊着着編寫login controller,注意:在eggjs中可使用ctx.request.body來獲取用戶post的數據。github

 

"use strict";

const Controller = require("egg").Controller;

class LoginController extends Controller {
  async doLogin() {
    const { ctx } = this;

    await ctx.render("login");
  }
  async getUserData() {
    const { ctx } = this;
    console.log(ctx.request.body);
  }
}

module.exports = LoginController;

③view下新建login頁面,寫一個簡單登陸表單,咱們的想法是點擊登陸匹配userLogin路由,執行login controller下的getUserData方法,打印接收的post數據。瀏覽器

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>登陸頁面</title>
  </head>
  <body>
    <form action="/userLogin" method="POST">
      用戶名:<input type="text" name="username"><br/>
        密碼:<input type="password" name="password"><br/>
          <button type="submit">登陸</button>
        </form>
      </body>

④訪問/userLogin,看到登陸頁面,點擊登陸按鈕。安全

而後呢,咱們會看到以下界面:報了個403的錯誤  什麼invalid csrf token,這是個什麼鬼東西哦?????服務器

 

按照官方介紹說的 eggjs內置了 csrf安全機制,下面是copy了官網上的描述:csrf攻擊:僞造用戶請求向網站發起惡意請求。app

Web 安全概念

Web 應用中存在不少安全風險,這些風險會被黑客利用,輕則篡改網頁內容,重則竊取網站內部數據,更爲嚴重的則是在網頁中植入惡意代碼,使得用戶受到侵害。常見的安全漏洞以下:框架

  • XSS 攻擊:對 Web 頁面注入腳本,使用 JavaScript 竊取用戶信息,誘導用戶操做。
  • CSRF 攻擊:僞造用戶請求向網站發起惡意請求。
  • 釣魚攻擊:利用網站的跳轉連接或者圖片製造釣魚陷阱。
  • HTTP參數污染:利用對參數格式驗證的不完善,對服務器進行參數注入攻擊。
  • 遠程代碼執行:用戶經過瀏覽器提交執行命令,因爲服務器端沒有針對執行函數作過濾,致使在沒有指定絕對路徑的狀況下就執行命令。

而框架自己針對 Web 端常見的安全風險內置了豐富的解決方案:

  • 利用 extend 機制擴展了 Helper API, 提供了各類模板過濾函數,防止釣魚或 XSS 攻擊。
  • 常見 Web 安全頭的支持。
  • CSRF 的防護方案。
  • 靈活的安全配置,能夠匹配不一樣的請求 url 。
  • 可定製的白名單,用於安全跳轉和 url 過濾。
  • 各類模板相關的工具函數作預處理。

在框架中內置了安全插件 egg-security, 提供了默認的安全實踐。

⑤在渲染頁面的時候傳入生成的csrf給頁面

async doLogin() {
    const { ctx } = this;
    // this.ctx.csrf 當用戶訪問頁面,會生成一個簡單地祕鑰,用戶調用接口需將這個祕鑰傳回去,防止他人屢次惡意不停的掉接口
    await ctx.render("login", {
      csrf: this.ctx.csrf
    });
  }

⑥在頁面上拿到csrf作以下改動:

⑦可觀察到dom面板中csrf渲染的值,這個值,每次刷新頁面的時候都會變,點擊登陸按鈕,發現控制檯打印出post的數據

點了兩下,因此打印出了兩下。

 

到此,咱們就獲取到了用戶簡單post提交的數據。

有個小問題就是,當咱們想在不少controller裏面的不少post請求都要傳遞這個csrf每次都要寫這個csrf:this.ctx.csrf,太麻煩了,eggjs爲咱們提供了定義模板全局變量的途徑:在中間件中設置全局變量

①:middleware下新建auth.js,鍵入以下內容:

module.exports = (option, app) => {
  return async function auth(ctx, next) {
    // 設置模板全局變量

    ctx.state.csrf = ctx.csrf;
    await next();
  };
};

②在config>config.default.js中進行中間件配置掛載

    

③全局變量配置好了以後,將剛纔在controller中傳入的csrf值刪掉,看模板的csrf有沒有做用或者報錯,會發現,csrf驗證依舊可用。則模板全局變量配置完成。

 

④模板添加csrf還有一種寫法是隱藏表單域傳值:點擊登陸發現csrf驗證依舊生效。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>登陸頁面</title>
  </head>
  <body>
    <form action="/userLogin" method="POST">
      <input type="hidden" name="_csrf" value="<%=csrf%>">
      用戶名:<input type="text" name="username"><br/>
        密碼:<input type="password" name="password"><br/>
          <button type="submit">登陸</button>
        </form>
      </body>

打完收工。。。

相關文章
相關標籤/搜索