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-helmet
:npm i koa-helmet --save
-
修改
app.js
,配置中间件
const helmet = require('koa-helmet')
app.use(helmet())
在许多的架构中,这些头会在Web
服务器(Apache
,nginx
)的配置中设置,而不是在应用的代码中。
如果是通过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攻击:在应用存储未经过滤的用户输入时发生。用户输入的代码会在你的应用环境下执行。
为了防御这类攻击,需要确保总是检查并过滤了用户的输入内容。
-
下载
xss
:npm 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 forgery
,CSRF
)是指攻击者欺骗用户浏览器,让其以用户的名义运行操作。
这种跨站请求依赖于浏览器同源策略中允许跨域写操作和跨域资源嵌入的开放规则,如链接、表单提交、css
的 url
和<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-csrf
:npm 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-ratelimit
:npm 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] || ''
}
发表评论