前端安全问题及解决策略
随着现代化进程的加速,代码安全问题显得越来越重要。其实大部分的程序员在开发过程当中并不会主动去关注代码的安全性问题。但是如果你所开发的是金融行业的应用,那么就对安全有着很高的要求。今天就来看一下前端领域我们所要关注的代码安全性问题。
跨站脚本攻击
XSS: cross site scripting,跨站脚本攻击,是一种代码注入攻击方式。常用的攻击分类有:
- 反射型: url参数直接注入, 短网址
- 存储型: 存储到DB后读取时注入
- 基于DOM : 比如提交按钮上传图片,onerror
借助XSS攻击,能够偷取网站任意数据,获取Cookie, 劫持前端逻辑等。
网站中常见的用户输入框, url参数等都是XSS攻击可能存在的地方。 根据用户攻击输入位置的不同,还可以分为:
1.在标签之中的攻击
2.在标签属性中的攻击
3.在script脚本中的攻击
4.在特殊位置: 比如源码的注释,还有一些头部参数之类的
通过提前闭合标签,提前闭合语句: var data = “ddd”; alert(1);””;
等方式,攻击者对于那么安全性不高的站点,很容易就通过代码进行盗取数据。
防御机制
最常见的防御方式就是验证用户输入,对 & , <, >, /, “, ‘, \ 等特殊字符进行转义 。 对于富文本应用来说,可以加入DOM解析白名单的机制, 保留部分标签和属性。 cheerio就可以实现这样的功能:
npm install cheerio
针对tag和属性来过滤, 不在白名单中就移除。
还可以采用现成的xss过滤库 :
npm install xss
var xss = require("xss");
var html = xss('<script>alert("xss");</script>');
console.log(html);
第二种策略是使用浏览器自带策略CSP, 设置合适的头部信息
通常指定HTTP Header 中的 Content-Security-Policy 来开启 CSP。
还有其他跟安全有关系的HTTP 头部有:
头部字段 | 含义 | 使用 |
---|---|---|
Strict-Transport-Security | HTTP Strict Transport Security (通常简称为HSTS) 是一个安全功能,它告诉浏览器只能通过HTTPS访问当前资源, 禁止HTTP方式。 | ctx.set(‘Strict-Transport-Security’, 'max-age=63072000; includeSubdomains’) |
X-Frame-Options | 用来给浏览器 指示允许一个页面 可否在frame, iframe, embed或object中展现的标记 | ctx.set(‘X-Frame-Options: sameorigin’, ‘sameorigin’) |
X-XSS-Protection | 是Internet Explorer,Chrome和Safari的一个功能,当检测到跨站脚本攻击 (XSS)时,浏览器将停止加载页面 | ctx.set(‘X-XSS-Protection’, 1) |
X-Content-Type-Options | 相当于一个提示标志,被服务器用来提示客户端一定要遵循在 Content-Type 首部中对 MIME 类型 的设定,而不能对其进行修改。这就禁用了客户端的 MIME 类型嗅探行为,换句话说,也就是意味着网站管理员确定自己的设置没有问题。 |
ctx.set(‘X-Content-Type-Options’ ‘nosniff’) |
Content-Security-Policy | 开启CSP策略 | Ctx.set(Content-Security-Policy: default-src ‘self’ ) |
对于使用Express框架的node应用来说,可以借助helmet中间件来实现这些设置:
const express = require('express')
const helmet = require('helmet')
const app = express()
app.use(helmet())
而用户输入信息认证,则可以采用https://github.com/ctavan/express-validator,比如:
const { body } = require('express-validator');
app.post('/user', body('email').custom(value => {
return User.findUserByEmail(value).then(user => {
if (user) {
return Promise.reject('E-mail already in use');
}
});
}), (req, res) => {
// Handle the request
});
CSRF
跨站请求伪造(CSRF)是一种强制用户在当前已登录的外部应用程序上执行非本意操作的一种攻击方法。攻击者通常会在目标的站点上,利用用户对于站点的信任,并且借助用户的已登录状态发起恶意的请求。举例来说,加入一个攻击者在他的钓鱼网站上加入一张图片,图片的地址指向站点B的某个接口。而站点B正好你已经登录过了,保留了你的登录信息。
<img src="http://www.B.com/xxx?comment='attack'" />
那么我们要怎么防御这种攻击呢?只要遵守以下几个规则就可以了:首先,请求中需要附带验证信息,比如加入验证码或者token。然后阻止第三方网站请求接口。验证请求来源等等。
express框架集成了对应的中间件(https://github.com/expressjs/csurf),可以很容易实现CSRF攻击的防御:
var cookieParser = require('cookie-parser')
var csrf = require('csurf')
var bodyParser = require('body-parser')
var express = require('express')
// setup route middlewares
var csrfProtection = csrf({ cookie: true })
var parseForm = bodyParser.urlencoded({ extended: false })
// create express app
var app = express()
// parse cookies
// we need this because "cookie" is true in csrfProtection
app.use(cookieParser())
app.get('/form', csrfProtection, function (req, res) {
// pass the csrfToken to the view
res.render('send', { csrfToken: req.csrfToken() })
})
app.post('/process', parseForm, csrfProtection, function (req, res) {
res.send('data is being processed')
})
Cookie安全
Cookie是前端用来存储用户认证信息的一种常用方式,它有以下几个特点:
- 前端数据存储
- 后端通过http头设置
- 请求时通过http头传给后端
- 前端可读写
- 遵守同源策略
Cookies 一般是由以下这些信息所组成:
- 域名
- 有效期
- 路径
- http-only: cookie只能被http协议所使用
- secure: https中使用
那么为了保障cookie的安全,需要后端代码设置如下cookie策略:
Ctx.cookies.set(‘userId’, user.id, {
httpOnly: false,
sameSite: ‘strict’
});
Session管理
Session中附带了很多用户敏感信息,所以对于session的管理也是代码安全中不能忽视的部分。
在node中,可以借助ACL模块,实现对应的用户授权等操作。
var acl = require('acl');
// Using redis backend
acl = new acl(new acl.redisBackend(redisClient, prefix));
// Or Using the memory backend
acl = new acl(new acl.memoryBackend());
// Or Using the mongodb backend
acl = new acl(new acl.mongodbBackend(dbInstance, prefix));
// guest is allowed to view blogs
acl.allow('guest', 'blogs', 'view')
// allow function accepts arrays as any parameter
acl.allow('member', 'blogs', ['edit', 'view', 'delete'])
定制好acl对象后,只要使用该模块就可以了:
app.put('/blogs/:id/comments/:commentId', acl.middleware(), function(req, res, next){…}
另外,认证请求的处理,也可以参考该文档:
密码安全
密码安全是一件很重要的事情,大家一般都能对这个观点形成共识。但是在应用程序中,很多代码都没有对代码进行正确的处理,包括让用户密码以明文形式暴露在数据库中,没有使用合适的哈希算法等。
通常在密码加密算法上,MD5和bcrypt两种算法比较流行,而安全性方面,bcrypt则比MD5略胜一筹。
这里推荐使用bcrypt
算法对密码进行哈希:
https://github.com/kelektiv/node.bcrypt.js
bcrypt.genSalt(saltRounds, function(err, salt) {
bcrypt.hash(myPlaintextPassword, salt, function(err, hash) {
// Store hash in your password DB.
});
});
比对用户密码的时候使用如下代码:
bcrypt.compare(myPlaintextPassword, hash, function(err, result) {
if (result == true) {
// do something
}
});
除了采用合适的加密算法外,还有其他策略来保障密码安全:
-
强制用户使用强密码
-
启用两步验证
https://gtihub.com/speakeasyjs/speakeasy
Google Authenticator
Authy
Yubico keys
SMS
其它工具
扫描node/js 项目
https://github.com/retirejs/retire.js
使用retire.js
工具可以帮助你检测已知漏洞。
另外一种审查工具是nsp (node security platform)。安装完成后,使用命令:
nsp check
就能检测应用所具有的安全漏洞。
参考文档
共同学习,写下你的评论
评论加载中...
作者其他优质文章