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>

打完收工。。。

相关文章
相关标签/搜索