【web安全】常见web安全问题及解决思路-爱代码爱编程
前言
web安全是我们面试中经常遇到的问题,而在实际项目开发中,尤其一些大型项目,web安全显得尤为重要。那么本文阿彬就给大家大概总结一下常见的一些web安全问题以及防御手段。
1.xss
XSS(Cross Site Scripting)跨站脚本攻击,因为缩写和css重叠,所以改叫XSS,跨脚本攻击是指通过存在安全漏洞的web网站注册用户的浏览器内非法的非本站点HTML标签或javascript进行一种攻击。
实现条件
1.利用虚假输入表单骗取用户个人信息
2.利用脚本窃取用户的cookie值,被害者在不知情况的下,帮助攻击者发送恶意请求
3.显示伪造的文章活图片
安全危害
1.获取页面数据
2.获取Cookies
3.劫持前端逻辑
4.发送请求
5.偷取网站的任意数据
6.偷取用户的资料
7.偷取用户的秘钥和登录状态
8.欺骗用户
XSS攻击分类:
1.1 反射型 -url参数直接注入
反射型XSS攻击一般是攻击者通过特定手法,诱使用户去访问一个包含恶意代码的URL,当受害者点击这些专门设计的链接的时候,恶意代码会直接在受害者主机上的浏览器执行。此类XSS攻击通常出现在网站的搜索栏、用户登录口等地方,常用来窃取客户端Cookies或进行钓鱼欺骗。
//比较常见的是alert弹窗盗取cookie,例如在输入框输入" <script>alert(document.cookie)<\script> "
1.2 DOM-based型XSS攻击
客户端的脚本程序可以动态地检查和修改页面内容,而不依赖于服务器端的数据。例如客户端如从URL中提取数据并在本地执行,如果用户在客户端输入的数据包含了恶意的JavaScript脚本,而这些脚本没有经过适当的过滤或者消毒,那么应用程序就可能受到DOM-based型XSS攻击。
需要特别注意以下的用户输入源document.URL、location.hash、location.search、document.referrer等。
1.3 存储型 存储到DB后读取注入
攻击者事先将恶意代码上传或者储存到漏洞服务器中,只要受害者浏览包含此恶意代码的页面就会执行恶意代码。这意味着只要访问了这个页面的访客,都有可能会执行这段恶意脚本,因此存储型XSS攻击的危害会更大。此类攻击一般出现在网站留言、评论、博客日志等交互处,恶意脚本存储到客户端或者服务端的数据库中。
与前者不同,存储型XSS是持久化的XSS攻击方式,通过用户输入个人信息或者发表文章的方式将恶意代码存储于服务器端,当其他用户再次访问页面时触发,造成XSS攻击。
防御手段
- 设置CSP安全策略
通过在页面中设置允许加载的资源的来源,来严格限制页面可加载的脚本以及图片等资源,防止外部的脚本攻击后注入其他脚本以及内容。
CSP,内容安全策略,是一种基于内容的声明式网络应用程序机制,对缓解内容注入漏洞的危害非常有效。通过一系列指令告诉客户端(如浏览器)被保护资源(如页面)内只允许加载和执行指令集中限定的内容,类似白名单机制,不满足限定条件的资源和内容将被客户端阻断或不被执行。可以通过两种方式设置CSP,一种是meta标签,一种是设置HTTP响应头Content-Security-Policy:1
Content-Security-Policy: default-src 'self' 只允许加载本站资源
Content-security-Policy: img-src https:// 只允许加载https协议图片
Content-security-Policy:child-src 'none' 不允许加载任何来源框架
例如 ctx.set('Content-security-Policy','default-src')
- Htmlencode转义特殊字符
大部分的论坛或者博客平台,注册账号都会允许用户填写个人信息,包括昵称、邮箱和个性签名等,此类文本信息属于非富文本类型,最常见的方法就是对尖括号标签转义成实体字符存储,由于是非富文本信息,并且以标签内容的形式展示,如果不使用框架渲染,直接原生JS通过docoment.getElementById(‘xxx’).innerText = 'your name’展示回页面中即可。
常见的处理方式如下:
const htmlEncode = function (handleString){
return handleString
.replace(/&/g,"&")
.replace(/</g,"<")
.replace(/>/g,">")
.replace(/ /g," ")
.replace(/\'/g,"'")
.replace(/\"/g,""");
}
- 白名单
大部分的富文本编辑器原理,都是提供一个具备contenteditable属性的dom元素,让用户对一段富文本进行编辑,其本质是对一段html进行处理,新增或删除样式等,最后通过回传富文本框中html的方式提供给开发者,意味着我们要允许用户填充一段html于我们的页面中。而获取到的html字符串我们不能直接进行简单的标签替换,否则会导致原有的样式丢失,最终展示在页面中的也不再是一篇排版精致的文章,因此我们要另寻他路。
首先需要明确的是,无论是这份来自于富文本编辑器的html,还是来自于最终用户发起请求所获取到的html,都是不可信的,意味着在前端进行过滤是没有任何实际意义和价值的,因为攻击者可以轻易的伪造请求绕过限制,所以我们需要在我们的服务器端针对这段html进行过滤处理。针对html的标签白名单过滤,不同的语言有不同的库实现,这里主要介绍nodejs中常用的标签过滤库,nodejs中常用的库主要是xss和xss-filter,下面以xss库的使用为例:
import * as xss from 'xss';
function handleXss(content: Content) {
// 设置HTML过滤器的白名单
const options = {
whiteList: {
p: ['class', 'style'],
em: ['class', 'style'],
strong: ['class', 'style'],
br: ['class', 'style'],
u: ['class', 'style'],
s: ['class', 'style'],
blockquote: ['class', 'style'],
li: ['class', 'style'],
ol: ['class', 'style'],
ul: ['class', 'style'],
h1: ['class', 'style'],
h2: ['class', 'style'],
h3: ['class', 'style'],
h4: ['class', 'style'],
h5: ['class', 'style'],
h6: ['class', 'style'],
span: ['class', 'style'],
div: ['class', 'style'],
img: ['src', 'class', 'style', 'width'],
},
};
// 自定义规则
const myxss = new xss.FilterXSS(options);
// 直接调用 myxss.process() 即可
content.content = myxss.process(content.content);
return content;
}
通过限定白名单,仅允许常见的文本展示标签以及图片img标签进入白名单,这部分会再过滤后被保留,并且标签内的class和style属性也会被保留;其他属性和诸如script、iframe等标签都会被直接过滤掉。
这里为何要严格限定标签的以及属性的原因,例如一个a标签可以通过href属性注入一段类似这样的js代码:
<a href\="javascript:alert('xss')"\>click me</a\>
- HttpOnly Cookie,配合token或验证码防范
这是防止XSS攻击窃取用户cookie最有效的防御手段,web应用程序设置cookie时,将其属性设置为HttpOnly 就可以防止网页的cookie客户端恶意JavaScript窃取,保护用户cookie信息。
设置方法:response.addHeader('Set-Cookie','uid=12;path=/; HttpOnly')
2.CSRF
CSRF(Cross Site Request Forgery),既跨站请求伪造,是一种常见的web攻击,他利用用户以登录的身份,在用户不知情的情况下,以用户的名字完成非法操作
实现条件
1.用户登录了站点A,并在本地记录了cookie
2.在用户没有登录除站点A的情况下(也就是cookie生效的情况下),访问了恶意攻击者提供引诱危险站点B(B站点需求访问站点A)。
3.站点A没有做任何CSRF防御
安全危害
1.利用用户登录状态
2.用户不知情
3.完成业务请求
4.盗取用户资金(转账,消费)
5.冒充用户发帖背锅
6.损害网站声誉
防御手段
- 验证 HTTP Referer 字段
- 在请求地址中添加 token 并验证
- 在 HTTP 头中自定义属性并验证
3.点击劫持–clickjacking
点击劫持是一种视觉欺骗的攻击手段,攻击者将需要攻击的网站通过iframe嵌套方式嵌入自己的网页中,并将iframe设置为透明的,在页面中透露出一个按钮诱导用户点击
通过用于各种网站,使用iframe技术,图片点几进入一个其他网址,导致用户信息泄密。
X-FRAME-OPTIONS 是一个HTTP响应头,在现代浏览器有一个很好的支持,这个HTTP响应头就是为了防御iframe嵌套的点击劫持攻击。
该响应头有三个值可选,分别是
DENY:表示页面不允许通过iframe的方式展示
SAMEORIGIN:表示页面可以在相同域名下通过iframe的方式展示
ALLOW-FRO:表示页面可以在指定来源的iframe中展示
<style id="click-jack">
html{
display: none;
}
</style>
<script>
if(self == top) {
var style = document.getElementById('click-jack')
document.body.removeChild(style)
} else {
top.location = self.location
}
</script>
现在实现方式: ctx.set('X-FRAME-OPTIONS','DENY')
以上代码的作用就是当通过iframe的方式加载页面时,攻击者的网页直接不显示所有内容了
4.SQL注入
攻击者成功的向服务器提交恶意的SQL查询代码,程序在接收后错误的将攻击者的输入作为查询语句的一部分执行,导致原始的查询逻辑被改变,额外的执行了攻击者精心构造的恶意代码。
例如: 'or’1 ‘=’ 1 填写特殊密码
拼接后的sql
SELECT *
FROM test.user
WHERE username = 'xiaozhou'
AND password= '1' or '1' = '1'
老的后台数据库登录,黑客尝试使用1' or '1' = '1相等于密码,去登录
防御手段
所有的查询语句建议使用数据库提供的参数查询接口**。参数化的语句使用参数而不是将用户输入变量嵌入到SQL语句中,既不要直接拼接SQL语句,例如node.js中的mysqlis库query方法中的?占位符参数
//错误的写法
cosnt sql = `
SELECT *
FROM test.user
WHERE username = '${ctx.reuqueset.body.username}'
AND password= '${ctx.reuqueset.body.password}' `
console.log('sql',sql)
res = await query(sql)
//正确的写法
const sql = `
SELECT *
FROM test.user
WHERE username = ?
AND password= ? `
console.log('sql',sql)
res = await query(sql.[ctx.request.body.username,ctx.reuqueset.body.password])
1.严格限制web应用的数据库的操作权限,给此用户提供仅仅能够满足其工作的最低权限,从而最大限度减少注入攻击对数据库的危害
2.后端代码检查输入的数据是否符合预期**,严格限制变量的类型,例如使用正则表达式进行一些匹配处理
3.对进行数据库的特殊字符串(’,",,>,<,&,%,等等)进行转义处理,后者编码转换。基本所有的后端语言都有对字符串进行转义处理的方法,比例,loads的lodaash_escapehtmlchar等
5.OS命令注入
os命令注入和sql注入差不多,只不过SQL注入是针对数据库的,而OS命令注入是针对操作系统的,OS命令注入攻击者指通过web应用,执行非法的操作系统命令达到攻击的目的,只要在你让那个调用Shell函数的地方就有存在被攻击的风险,倘若调用shell时存在疏漏,就可以执行插入非法命令。
//以node.js为例,假如在接口中需要从github下载用户指定的repo
const exec = require('mz/child_process').exec;
let params = {/*用户输入的参数*/}
exec(`git clone ${params.repo} /some/path`)
//如果传入参数会怎么样
https://github.com/xx/xx.git && rm -fr /* &&
6.请求劫持
DNS劫持
顾名思义,DNS服务器(DNS解析各个步骤)被篡改,修改了域名解析的结果,使得访问的不是预期的ip
HTTPS劫持
运营商劫持,此时大概就只能升级为HTTPS了
7.DDOS
DDOS不是一种攻击,而是一大类攻击的总称,它有几十张类型,新的攻击方法还不断发明出来,网站运行各个环节,都可以是攻击目标,只要把一个环节攻破,使得整个流程、跑不起来,就得到瘫痪服务的目的。
其中,比较常见的是一种攻击是cc攻击,他就是简单粗暴地送来大量的正常请求,超出服务器的最大承受量,导致死机。
比如遭遇cc攻击,最多的时候全世界大概20多个ip地址轮流发出请求,每个地址请求量在每秒200次-300次,我看访问日志的时候,就觉得请求像洪水一样涌来,一眨眼就是一大堆,几分钟的时候,日志文件的体积就大了100MB,
常见的攻击方式
SYN Flood
此攻击通过目标发送具有欺骗性源ip地址的大量TCP 初始链接请求SYN数据包来利用TCP握手,目标机器相应每个链请求,然后等待握手中的最后一步,这一步从未发生过,耗尽了过程中的目标资源
HTTP Flood
此攻击类似于同时在多个不同计算机上反复按web浏览器中的刷新,大量HTTP请求泛滥服务器,导致拒接服务
防御手段
- 备份网站
备份网站不一定是全功能的,如果能做到全静态浏览,就能满足需求,最低限度应该可以显示公告,告诉用户,网站出看问题,正在全力抢修
- HTTP请求拦截
硬件,服务器,防火墙 带宽扩容 + CDN 提高犯罪成本