Koa框架前端安全

koa-helmet

以下是一些安全相关的HTTP头,站点应该设置它们:

  • Strict-Transport-Security:强制使用安全连接(SSL/TLS之上的HTTPS)来连接到服务器
  • X-Frame-Options:提供对于点击劫持的保护
  • X-XSS-Protection:开启大多数现代浏览器内建的对于跨站脚本攻击(XSS)的过来功能
  • X-Content-Type-Options:防止浏览器使用MIME-sniffing来确定响应的类型,转而使用明确的content-type来确定
  • Content-Security-Policy:防止受到跨站脚本攻击以及其他跨站注入攻击
  • 下载koa-helmetnpm i koa-helmet --save

  • 修改app.js,配置中间件

const helmet = require('koa-helmet') app.use(helmet())

在许多的架构中,这些头会在Web服务器(Apachenginx)的配置中设置,而不是在应用的代码中。
如果是通过nginx配置,配置文件会类似于如下例子:

# nginx.conf add_header X-Frame-Options SAMEORIGIN; add_header X-Content-Type-Options nosniff; add_header X-XSS-Protection "1; mode=block"; add_header Content-Security-Policy "default-src 'self'";

xss

  • 非持久化的XSS攻击:在攻击者向指定的URL的响应HTML中注入可执行的JavaScript代码时发生。
  • 持久化的XSS攻击:在应用存储未经过滤的用户输入时发生。用户输入的代码会在你的应用环境下执行。

为了防御这类攻击,需要确保总是检查并过滤了用户的输入内容。

  • 下载xssnpm i xss --save

  • 在代码中使用

const xss = require('xss') router.get('/test/xss', async ctx => { // http://192.168.97.78:3000/test/xss?str=<script>alert("xss");</script> console.log(ctx.query.str) const str = xss(ctx.query.str) ctx.body = str })

koa-csrf

跨站请求伪造(cross-site request forgeryCSRF)是指攻击者欺骗用户浏览器,让其以用户的名义运行操作。
这种跨站请求依赖于浏览器同源策略中允许跨域写操作和跨域资源嵌入的开放规则,如链接、表单提交、cssurl<img>嵌入等方式。

攻击示例的大致过程:

  • 用户使用同一浏览器访问两个站点。
  • 用户先在A站点登录,并获得会话凭据。
  • 然后访问B站点,其中B站点中预设了一个提交给A站点的包含恶意操作的<form>表单,并通过脚本的 submit 方法自动提交。
  • 当用户访问B站点时,将会使用此时用户在A站点的会话凭据来请求A站点,于是通过了身份验证并执行恶意操作。

通过检查 Referer 请求头来判断请求来源地址的方法并不是那么可靠,所以通常会使用添加校验 token 的方式来防范 CSRF

koa-csrf参数介绍

  • invalidTokenMessage:使 koa 抛出的错误信息内容,默认值为:'Invalid CSRF token'。它可以是一个接收 ctx 作为参数的函数,函数最后返回错误信息内容。
  • invalidTokenStatusCode:验证失败时的响应状态码,默认值为:403(Forbidden)。跟 invalidTokenMessage 参数一样,它也会被传递给 ctx.throw,用于抛出错误和拒绝请求。
  • excludedMethods:排除的请求方法,默认值为:['GET', 'HEAD', 'OPTIONS']
  • disableQuery:是否禁止通过查询字符串传递 _csrf 校验 token,默认值为 false。如果校验 token 出现在 URL 中,则可能会通过 Referer 泄露,应尽量把 Token 放在表单中,把敏感操作由 GET 改为 POST
  • 下载koa-csrfnpm i koa-csrf --save

  • 修改app.js文件,配置中间件

const CSRF = require('koa-csrf') // add the CSRF middleware app.use(new CSRF({ invalidTokenMessage: 'Invalid CSRF token', invalidTokenStatusCode: 403, excludedMethods: [ 'GET','HEAD', 'OPTIONS' ], disableQuery: false })) // your middleware here (e.g. parse a form submit) app.use((ctx, next) => { if (![ 'GET', 'POST' ].includes(ctx.method)) { return next(); } if (ctx.method === 'GET') { ctx.state.csrf = ctx.csrf; } return next() });
  • 模板中form表单添加<input type="hidden" name="_csrf" value="<%= csrf %>" />

暴力破解

暴力破解即系统地列举所有可能的结果,并逐一尝试,来找到正确答案。在web应用中,用户登陆就特别适合它发挥。

可以使用koa-limit或者koa-ratelimit限制用户的链接频率来防止这类的攻击

  • 下载koa-ratelimitnpm i koa-ratelimit --save

  • 修改app.js文件,配置中间件

const ratelimit = require('koa-ratelimit') const Redis = require('ioredis') // apply rate limit app.use(ratelimit({ driver: 'redis', db: new Redis(), duration: 60000, errorMessage: 'Sometimes You Just Have to Slow Down.', // 根据ip id: (ctx) => ctx.ip, headers: { remaining: 'Rate-Limit-Remaining', reset: 'Rate-Limit-Reset', total: 'Rate-Limit-Total' }, max: 100, disableHeader: false, whitelist: (ctx) => { // some logic that returns a boolean }, blacklist: (ctx) => { // some logic that returns a boolean } }))

SQL注入

所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。

-- // 正常 select * from users WHERE username="zhangsan" and password="524ab85686df0e52ada43b11b53cce35" -- // sql注入 用户名写入:zhangsan'-- select * from users WHERE username='zhangsan'-- ' and password='524ab85686df0e52ada43b11b53cce35'

mysql中,可以使用mysql.escape来防止注入编码特殊字符

const login = async (username, password) => { // 格式化 预防sql注入 username = escape(username) // 生成加密密码 password = genPassword(password) // 格式化 预防sql注入 password = escape(password) const sql = `select id, username, realname from users where username=${username} and password=${password}` const rows = await exec(sql) return rows[0] || '' }

创作不易,若本文对你有帮助,欢迎打赏支持作者!

 分享给好友: