事件模型
1. 原始事件模型(DOM0级)
- 这是一种被所有浏览器都支持的事件模型,对于原始事件而言,没有事件流,事件一旦发生马上处理。有两种方式可以实现原始事件:
- html代码中直接指定属性值:
<button id="demo" type="button" onclick="doSomeTing()" />
- 在js中获取代码元素指定:
document.getElementsById("demo").onclick = doSomeTing()
- html代码中直接指定属性值:
- 优点:所有浏览器都兼容。
- 缺点:
- 只能绑定一个事件,后面的会覆盖前面的事件
- 逻辑与显示没有分离;
- 没有事件流。无法捕获事件的冒泡、委托等机制。
2. DOM2级事件模型
- 此模型是W3C指定的标准模型。除IE6~8外都遵循这个规范。一次事件的发生包含三个过程:
- 事件捕获阶段:当某个元素触发事件时,最外层的document会发出一个事件流,随着DOM树的节点向目标元素流去,直到到达事件真正发生的目标元素,在该过程中,事件的监听函数默认是不会触发的。
- 位于目标阶段:到达目标元素后,执行目标元素响应的处理函数。
- 事件冒泡阶段:处理完函数后,会从目标元素开始,往顶层元素传播,途中如果有节点绑定了响应的事件处理函数,会依次触发。
- 如图所示:
- 所有的事件类型都会经历事件捕获。但有小部分元素不会经历事件冒泡,比如submit事件就不会被冒泡。
- 事件传播是可以阻止的:
- 在W3C中,使用stopPropagation() 方法。
- 在IE中设置cancelBubble = true。
- 在捕获过程中会执行该方法,后面的冒泡过程就不会发生了。
- 绑定方式为
addEventListener("eventType", "handler", "true | false")
通过修改第三个参数的true(捕获) 或 false(冒泡) 来指定该函数在哪个阶段执行。 接触监听器:removeEventListner("eventType", "handler", "true!false");
3. IE事件模型(低版本浏览器)
- IE的事件模型只有两步,先执行元素的监听函数,然后事件沿着父节点一直冒泡到document。而且IE是将event对象在处理函数中设为window的属性,一旦函数执行结束,便被置为null了。
window.onload = function (){alert(window.event);}
// 【object event】
setTimeout(function(){alert(window.event);},2000);
// null
- IE绑定事件监听的方式为
attachEvent( "eventType", "handler")
,第一个参数需要加 on,解除的方法为detachEvent("eventType", "handler" )
event对象的常用属性和方法
- 属性:
1. event.target:发生事件的节点;
2. event.currentTarget:当前正在处理事件的节点,在事件捕获或冒泡阶段;
3. event.timeStamp:事件发生的时间,时间戳;
4. event.bubbles:事件是否冒泡。
5. event.cancelable:事件是否可以用preventDefault()方法来取消默认的动作;
6. event.keyCode:按下的键的值; - 方法:
1.e.preventDefault()
可以阻止事件的默认行为发生。默认行为是指:点击a标签就转跳到其他页面、拖拽一个图片到浏览器会自动打开、点击表单的提交按钮会提交表单等等。
2.event. stopPropagation()
阻止事件冒泡。 - event.target与event.currentTarget有什么不同?
target在事件流的目标阶段;currentTarget在事件流的捕获,目标及冒泡阶段。只有当事件流处在目标阶段的时候,两个的指向才是一样的, 而当处于捕获和冒泡阶段的时候,target指向被单击的对象而currentTarget指向当前事件活动的对象(一般为父级)。
自定义事件
- 想要实现自定义事件,需要经过下面几步:
createEvent(eventType)
:创造一个事件,其中eventType有五种类型:Events(包括所有的事件)、HTMLEvents(‘abort’, ‘blur’, ‘change’, ‘error’, ‘focus’, ‘load’, ‘reset’, ‘resize’, ‘scroll’, ‘select’,‘submit’, ‘unload’)、UIEevents(‘DOMActivate’, ‘DOMFocusIn’, ‘DOMFocusOut’, ‘keydown’, ‘keypress’, ‘keyup’)、MouseEvents(‘click’, ‘mousedown’, ‘mousemove’, ‘mouseout’, ‘mouseover’, ‘mouseup’)、MutationEvents(‘DOMAttrModified’, ‘DOMNodeInserted’, ‘DOMNodeRemoved’,‘DOMCharacterDataModified’,DOMNodeInsertedIntoDocument’,‘DOMNodeRemovedFromDocument’, ‘DOMSubtreeModified’)initEvent( 'type', bubbles, cancelable )
:在创造完后必须初始化事件。targetObj.dispatchEvent(event)
: 初始化完成后便可随时触发需要的事件了。- 例子:
var fireOnThis = document.getElementById('demo'); var evObj = document.createEvent('MouseEvents'); evObj.initMouseEvent('click',true,true, window, 1, 12, 345, 7, 220,false,false,true,false, 0,null ); fireOnThis.dispatchEvent(evObj)
事件代理
- 为父级元素绑定事件,通过
e.target
判断点击的子级元素进行相应的事件处理程序。 - 并非所有的事件都能冒泡的blur、focus、load、unload并不能像其他事件一样冒泡。
跨域
什么是跨域
- 浏览器有同源策略:
协议、域名、端口均一样的情况下,才允许访问相同的cookie、localStorage或是发送Ajax请求等,若三者有一不同, 则视为跨域。 - 一个URL由以下几个部分组成:
- 协议名:https,http,ftp(文件传输协议)
- 域名:一级域名(www.baidu.com)、二级域名(abc.baidu.com)、三级域名(abc.baidu.com.cn)
- 端口名:http默认80,https默认443,ftp默认21
- 请求路径名称:path、pathname
- 问号传参及哈希值。
如何跨域
- jsonp(只能实现get一种请求)
src属性的标签不受同源策略影响,拥有该属性的标签都可以跨域,所以我们可以通过动态创建script,再请求一个带参网址实现跨域通信。<script> var script = document.createElement('script'); script.type = 'text/javascript'; // 传参一个回调函数名给后端,方便后端返回时执行这个在前端定义的回调函数 script.src = 'http://baidu.com?user=admin&callback=handleCallback'; document.head.appendChild(script); // 回调执行函数 function handleCallback(res) { alert(JSON.stringify(res)); } </script>
- iframe跨域
通过iframe的src属性由外域转向本地域,跨域数据即由iframe的window.name从外域传递到本地域。这个就巧妙地绕过了浏览器的跨域访问限制,但同时它又是安全操作。- document.domain + iframe 跨域 (此方案仅限主域相同,子域不同的跨域应用场景)
两个页面都通过js强制设置document.domain为基础主域,强制实现了同域。
父窗口:
子窗口:<iframe id="iframe" src="http://child.domain.com/b.html"></iframe> <script> document.domain = 'domain.com'; var user = 'admin'; </script>
<script> document.domain = 'domain.com'; // 获取父窗口中变量 alert('get js data from parent ---> ' + window.parent.user); </script>
- location.has + iframe跨域
A域:a.html -> B域:b.html -> A域:c.html,a与b不同域只能通过hash值单向通信,b与c也不同域也只能单向通信,但c与a同域,所以c可通过parent.parent访问a页面所有对象。 - window.name + iframe跨域
window.name属性的独特之处:name值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值
- document.domain + iframe 跨域 (此方案仅限主域相同,子域不同的跨域应用场景)
- postMessage跨域
- postMessage是HTML5 XMLHttpRequest Level 2中的API,且是为数不多可以跨域操作的window属性之一,它可用于解决以下方面的问题:
- 页面和其打开的新窗口的数据传递
- 多窗口之间消息传递
- 页面与嵌套的iframe消息传递
- 上面三个场景的跨域数据传递
- postMessage(data, origin)。
data:html5规范支持任意基本类型或可复制的对象,但部分浏览器只支持字符串,所以格式应JSON.stringify()序列化。
origin:协议+主机+端口号,也可设置为 * ,表示可传递给任意窗口。
- 跨域资源共享(cors)
- 普通跨域请求:只服务端设置Access-Control-Allow-Origin即可,前端无须设置,若要带cookie请求:前后端都需要设置。
- 需注意的是:由于同源策略的限制,所读取的cookie为跨域请求接口所在域的cookie,而非当前页。
- 目前,所有浏览器都支持该功能(IE8+:IE8/9需要使用XDomainRequest对象来支持CORS)),CORS也已经成为主流的跨域解决方案。
- nginx代理跨域
- 跨域原理: 同源策略是浏览器的安全策略,不是HTTP协议的一部分。服务器端调用HTTP接口只是使用HTTP协议,不会执行JS脚本,不需要同源策略,也就不存在跨越问题。
- 实现思路:通过nginx配置一个代理服务器(域名与domain1相同,端口不同)做跳板机,反向代理访问domain2接口,并且可以顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域登录。
- Nodejs中间件代理跨域(约等于nginx代理)
- 通过设置cookieDomainRewrite参数修改响应头中cookie中域名,实现当前域的cookie写入,方便接口登录认证。
- WebSocket协议跨域
- WebSocket protocol是HTML5一种新的协议。它实现了浏览器与服务器全双工通信,同时允许跨域通讯,是server push技术的一种很好的实现。
- 原生WebSocket API使用起来不太方便,我们使用Socket.io,它很好地封装了webSocket接口,提供了更简单、灵活的接口,也对不支持webSocket的浏览器提供了向下兼容。
模块化
原始写法
- 模块就是实现特定功能的一组方法。只要把不同的函数(以及记录状态的变量)简单地放在一起,就算是一个模块。直接的一个函数,也可算作一个模块,但是会污染全局变量,无法保证不与其他模块发生变量名冲突,模块成员之间看不出直接关联关系。
对象写法
- 为了解决上面的问题,可以把模块写成一个对象,所有的成员都放在这个对象里
var module1 = new Object({
_count : 0,
m1 : function (){
//...
},
m2 : function (){
//...
}
});
上面的m1()和m2(),都封装在module1中,使用时直接调用就行。
- 但是这样的写法会暴露所有的模块成员,而且内部状态也可以被外部改写。
立即执行函数写法
- 使用立即执行函数,可以达到不暴露私有成员的目的
var module1 = (function(){
var _count = 0;
var m1 = function(){
//...
};
var m2 = function(){
//...
};
return {
m1 : m1,
m2 : m2
};
})();
- module1就是JS模块的基本写法。
放大模式
- 如果一个模块很大,必须分成几个部分,或者一个模块需要继承另一个模块,这时就有必要采用"放大模式"(augmentation)
var module1 = (function (mod){
mod.m3 = function () {
//...
};
return mod;
})(module1);
- 上面的代码为module1模块添加了一个新方法m3(),然后返回新的module1模块。
宽放大模式
- 在浏览器环境中,模块的各个部分通常都是从网上获取的,有时无法知道哪个部分会先加载。如果采用上一节的写法,第一个执行的部分有可能加载一个不存在空对象,这时就要采用"宽放大模式"。
var module1 = ( function (mod){
//...
return mod;
})(window.module1 || {});
- 与放大模式相比,宽放大就是立即执行函数的参数可以是空对象。
输入全局变量
- 独立性是模块的重要特点,模块内部最好不与程序的其他部分直接交互。为了在模块内部调用全局变量,必须显式地将其他变量输入模块。
var module1 = (function ($, YAHOO) {
//...
})(jQuery, YAHOO);
- 上面的module1模块需要使用jQuery库和YUI库,就把这两个库(其实是两个模块)当作参数输入module1。这样做除了保证模块的独立性,还使得模块之间的依赖关系变得明显。
模块化规范
- CommonJS
- CommonJS主要用在Node开发上,每个文件就是一个模块,没个文件都有自己的一个作用域。通过module.exports暴露public成员。
- Module模式是模块化规范的基石,CommonJS也是对Module模式的一种封装。
- AMD和CMD
- AMD:区别于CommonJS,AMD规范的被依赖模块是异步加载的,而定义的模块是被当作回调函数来执行的。同时,AMD规范不是采用匿名函数自调用的方式来封装,我们依然可以利用闭包的原理来实现模块的私有成员和公有成员。
- CMD:CMD是SeaJS在推广过程中对模块定义的规范化产出。AMD推崇依赖前置,CMD推崇依赖就近。CMD集成了CommonJS和AMD的特点,支持同步和异步加载模块。CMD加载完模块后并不执行,只是下载而已,遇到require语句的时候才会执行对应的模块,模块的执行顺序是从上至下的。因此,CMD中require函数同步加载模块时没有HTTP请求过程。
ES6module
- ES6的模块化已经不是规范了,而是JS语言的特性。随着ES6的推出,AMD和CMD也随之成为了历史。ES6模块与模块化规范相比,有两大特点:
- 模块化规范输出的是一个值的拷贝,ES6 模块输出的是值的引用。
- 模块化规范是运行时加载,ES6 模块是编译时输出接口。
- 模块化规范输出的是一个对象,该对象只有在脚本运行完才会生成。而 ES6 模块不是对象,ES6 module 是一个多对象输出,多对象加载的模型。
- 从原理上来说,模块化规范是匿名函数自调用的封装,而ES6 module则是用匿名函数自调用去调用输出的成员。
异步加载js、defer、saync动态创建dom插入
Script Dom Element
- 也就是将script标签的saync设置为true。
- 属性是HTML5中新增的异步支持。此方法被称为Script DOM Element方法
- 问题在于这种加载方式执行完之前会阻止onload事件的触发,而现在很多页面都在onload时执行额外的渲染工作,所以还是会阻塞写在onload后的渲染。
onload时的异步加载
- 这种方法只是把插入script的方法放在一个函数里面,然后放在window的onload方法里面执行,这样就解决了阻塞onload事件触发的问题。
script标签的async属性
- async属性是HTML5新增属性,需要Chrome、FireFox、IE9+浏览器支持
- async属性规定一旦脚本可用,则会异步执行
- async属性仅适用于外部脚本
- 此方法不能保证脚本按顺序执行
- 他们将在onload事件之前完成
script标签的defer属性
- defer属性规定是否对脚本执行进行延迟,直到页面加载为止
- 如果脚本不会改变文档的内容,可将defer属性加入到
es6模块type="module"属性
- 浏览器对于带有type=”module”的
<script type="module">
import utils from "./utils.js";
// other code
</script>
web安全
1. XSS攻击
- Cross Site Script,跨站脚本攻击,因为缩写和CSS重叠,所以称为XSS(哈哈哈哈哈)
- XSS的原理是恶意攻击者往Web页面里插入恶意可执行网页脚本代码,当用户浏览该页之时,嵌入其中的脚本代码会被执行,从而可以达到攻击者盗取用户信息或其他侵犯用户安全隐私的目的。大致可分为
非持久型 XSS
也叫反射型XSS漏洞,一般是通过给别人发送带有恶意脚本代码参数的URL,当该地址被打开时,恶意的参数将
被HTML解析、执行。
![相当于中间商赚差价](https://imgconvert.csdnimg.cn/aHR0cHM6Ly91cGxvYWQtaW1hZ2VzLmppYW5zaHUuaW8vdXBsb2FkX2ltYWdlcy85MjEwMjcyLTM5YmM3MTdkYTM4ZTlhYzYuanBn?x-oss-process=image/format,png#pic_center)
当你的Web页面中包含以下代码时:
<select>
<script>
document.write(''
+ '<option value=1>'
+ location.href.substring(location.href.indexOf('default=') + 8)
+ '</option>'
);
document.write('<option value=2>English</option>');
</script>
</select>
攻击者便可直接通过URL(类似:https://xx.com/xx?default=)注入可执行的脚本代码。
非持久型XSS漏洞攻击有以下几点特征:
-
- 及时性,不经过服务器存储,直接通过HTTP的GET和POST请求就能完成一次攻击,拿到用户隐私数据。
-
- 攻击者需要诱导用户点击或执行对应的操作。
-
- 反馈率低,所以比较难发现和响应修复。
-
- 盗取用户敏感和保密信息。
为了防止出现非持久型 XSS 漏洞,需要确保这么几件事情:
-
- Web 页面渲染的所有内容或者渲染的数据都必须来自于服务端。
-
- 尽量不要从 URL,document.referrer,document.forms 等这种 DOM API 中获取数据直接渲染。
-
- 尽量不要使用 eval, new Function(),document.write(),document.writeln(),window.setInterval(),window.setTimeout(), innerHTML,document.createElement() 等可执行字符串的方法。
-
- 如果做不到以上几点,也必须对涉及 DOM 渲染的方法传入的字符串参数做 escape 转义。
-
- 前端渲染的时候对任何的字段都需要做 escape 转义编码。
持久型 XSS (存储型 XSS)
- 持久型 XSS 漏洞,一般存在于 Form 表单提交等交互功能,如文章留言,提交文本信息等,黑客利用的 XSS 漏洞,将内容经正常功能提交进入数据库持久保存,当前端页面获得后端从数据库中读出的注入代码时,恰好将其渲染执行。
- 主要注入页面方式和非持久型 XSS 漏洞类似,只不过持久型的不是来源于 URL,referer,forms 等,而是来源于后端从数据库中读出来的数据 。持久型 XSS 攻击不需要诱骗点击,黑客只需要在提交表单的地方完成注入即可,但是这种 XSS 攻击的成本相对还是很高。
攻击成功需要同时满足以下几个条件:
- POST 请求提交表单后端没做转义直接入库。
- 后端从数据库中取出数据没做转义直接输出给前端。
- 前端拿到后端数据没做转义直接渲染成 DOM。
持久型 XSS 有以下几个特点:
- 持久性,植入在数据库中
- 盗取用户敏感私密信息
- 危害面广
防御 XSS 攻击
- 对于 XSS 攻击来说,通常有两种方式可以用来防御。
- CSP
CSP 本质上就是建立白名单,开发者明确告诉浏览器哪些外部资源可以加载和执行。我们只需要配置规则,如何拦截是由浏览器自己实现的。我们可以通过这种方式来尽量减少 XSS 攻击。
通常可以通过两种方式来开启 CSP:- 设置 HTTP Header 中的 Content-Security-Policy
- 设置 meta 标签的方式
- 这里以设置 HTTP Header 来举例:
- 只允许加载本站资源
Content-Security-Policy: default-src 'self'
- 只允许加载 HTTPS 协议图片
Content-Security-Policy: img-src https://*
- 允许加载任何来源框架
Content-Security-Policy: child-src 'none'
- 如需了解更多属性,请查看Content-Security-Policy文档
对于这种方式来说,只要开发者配置了正确的规则,那么即使网站存在漏洞,攻击者也不能执行它的攻击代码,并且 CSP 的兼容性也不 错。
- 只允许加载本站资源
- 转义字符
- 用户的输入永远不可信任的,最普遍的做法就是转义输入输出的内容,对于引号、尖括号、斜杠进行转义
但是对于显示富文本来说,显然不能通过上面的办法来转义所有字符,因为这样会把需要的格式也过滤掉。对于这种情况,通常采用白名单过滤的办法,当然也可以通过黑名单过滤,但是考虑到需要过滤的标签和标签属性实在太多,更加推荐使用白名单的方式。function escape(str) { str = str.replace(/&/g, '&') str = str.replace(/</g, '<') str = str.replace(/>/g, '>') str = str.replace(/"/g, '&quto;') str = str.replace(/'/g, ''') str = str.replace(/`/g, '`') str = str.replace(/\//g, '/') return str }
以上示例使用了 js-xss 来实现,可以看到在输出中保留了 h1 标签且过滤了 script 标签。const xss = require('xss') let html = xss('<h1 id="title">XSS Demo</h1><script>alert("xss");</script>') // -> <h1>XSS Demo</h1><script>alert("xss");</script> console.log(html)
- HttpOnly Cookie
- 这是预防XSS攻击窃取用户cookie最有效的防御手段。Web应用程序在设置cookie时,将其属性设为HttpOnly,就可以避免该网页的cookie被客户端恶意JavaScript窃取,保护用户cookie信息。
2. CSRF
- CSRF(Cross Site Request Forgery),即跨站请求伪造,是一种常见的Web攻击,它利用用户已登录的身份,在用户毫不知情的情况下,以用户的名义完成非法操作。
CSRF攻击的原理:
- CSRF 攻击必须要有三个条件:
- 用户已经登录了站点 A,并在本地记录了 cookie
- 在用户没有登出站点 A 的情况下(也就是 cookie 生效的情况下),访问了恶意攻击者提供的引诱危险站点 B (B 站点要求访问站点A)。
- 站点 A 没有做任何 CSRF 防御
如何防御 CSRF
- 防范 CSRF 攻击可以遵循以下几种规则:
Get 请求不对数据进行修改
不让第三方网站访问到用户 Cookie
阻止第三方网站请求接口
请求时附带验证信息,比如验证码或者 Token - SameSite:可以对 Cookie 设置 SameSite 属性。该属性表示 Cookie 不随着跨域请求发送,可以很大程度减少 CSRF 的攻击,但是该属性目前并不是所有浏览器都兼容。
- Referer Check:HTTP Referer是header的一部分,当浏览器向web服务器发送请求时,一般会带上Referer信息告诉服务器是从哪个页面链接过来的,服务器籍此可以获得一些信息用于处理。可以通过检查请求的来源来防御CSRF攻击。正常请求的referer具有一定规律,如在提交表单的referer必定是在该页面发起的请求。所以通过检查http包头referer的值是不是这个页面,来判断是不是CSRF攻击。
但在某些情况下如从https跳转到http,浏览器处于安全考虑,不会发送referer,服务器就无法进行check了。若与该网站同域的其他网站有XSS漏洞,那么攻击者可以在其他网站注入恶意脚本,受害者进入了此类同域的网址,也会遭受攻击。出于以上原因,无法完全依赖Referer Check作为防御CSRF的主要手段。但是可以通过Referer Check来监控CSRF攻击的发生。 - Anti CSRF Token:目前比较完善的解决方案是加入Anti-CSRF-Token。即发送请求时在HTTP 请求中以参数的形式加入一个随机产生的token,并在服务器建立一个拦截器来验证这个token。服务器读取浏览器当前域cookie中这个token值,会进行校验该请求当中的token和cookie当中的token值是否都存在且相等,才认为这是合法的请求。否则认为这次请求是违法的,拒绝该次服务。
这种方法相比Referer检查要安全很多,token可以在用户登陆后产生并放于session或cookie中,然后在每次请求时服务器把token从session或cookie中拿出,与本次请求中的token 进行比对。由于token的存在,攻击者无法再构造出一个完整的URL实施CSRF攻击。但在处理多个页面共存问题时,当某个页面消耗掉token后,其他页面的表单保存的还是被消耗掉的那个token,其他页面的表单提交时会出现token错误。 - 验证码:应用程序和用户进行交互过程中,特别是账户交易这种核心步骤,强制用户输入验证码,才能完成最终请求。在通常情况下,验证码够很好地遏制CSRF攻击。但增加验证码降低了用户的体验,网站不能给所有的操作都加上验证码。所以只能将验证码作为一种辅助手段,在关键业务点设置验证码。
3. 点击劫持
- 点击劫持是一种视觉欺骗的攻击手段。攻击者将需要攻击的网站通过 iframe 嵌套的方式嵌入自己的网页中,并将 iframe 设置为透明,在页面中透出一个按钮诱导用户点击。
- 特点:
1. 隐蔽性较高,骗取用户操作
2. “UI-覆盖攻击”
3. 利用iframe或者其它标签的属性 - 点击劫持的原理:用户在登陆 A 网站的系统后,被攻击者诱惑打开第三方网站,而第三方网站通过 iframe 引入了 A 网站的页面内容,用户在第三方网站中点击某个按钮(被装饰的按钮),实际上是点击了 A 网站的按钮。
- 防御点击劫持:
- X-FRAME-OPTIONS:X-FRAME-OPTIONS是一个 HTTP 响应头,在现代浏览器有一个很好的支持。这个 HTTP 响应头 就是为了防御用 iframe 嵌套的点击劫持攻击。
该响应头有三个值可选,分别是:- DENY,表示页面不允许通过 iframe 的方式展示
- SAMEORIGIN,表示页面可以在相同域名下通过 iframe 的方式展示
- ALLOW-FROM,表示页面可以在指定来源的 iframe 中展示
- JavaScript 防御:当通过 iframe 的方式加载页面时,攻击者的网页直接不显示所有内容。
<head> <style id="click-jack"> html { display: none !important; } </style> </head> <body> <script> if (self == top) { var style = document.getElementById('click-jack') document.body.removeChild(style) } else { top.location = self.location } </script> </body>
- X-FRAME-OPTIONS:X-FRAME-OPTIONS是一个 HTTP 响应头,在现代浏览器有一个很好的支持。这个 HTTP 响应头 就是为了防御用 iframe 嵌套的点击劫持攻击。
4. URL 跳转漏洞
- 借助未验证的 URL 跳转,将应用程序引导至不安全的第三方区域,从而导致的安全问题。
URL跳转漏洞原理
- 黑客利用URL跳转漏洞来诱导安全意识低的用户点击,导致用户信息泄露或者资金的流失。其原理是黑客构建恶意链接(链接需要进行伪装,尽可能迷惑),发在QQ群或者是浏览量多的贴吧/论坛中。安全意识低的用户点击后,经过服务器或者浏览器解析后,跳到恶意的网站中。
- 恶意链接需要进行伪装,经常的做法是熟悉的链接后面加上一个恶意的网址,这样才迷惑用户。
http://gate.baidu.com/index?act=go&url=http://t.cn/RVTatrd
http://qt.qq.com/safecheck.html?flag=1&url=http://t.cn/RVTatrd
http://tieba.baidu.com/f/user/passport?jumpUrl=http://t.cn/RVTatrd
URL跳转漏洞实现方式
- Header 头跳转
- Javascript 跳转
- META 标签跳转
举例:
<?php
$url=$_GET['jumpto'];
header("Location: $url");
?>
http://www.wooyun.org/login.php?jumpto=http://www.evil.com
如何防御URL 漏洞跳转
- referer的限制:如果确定传递URL参数进入的来源,我们可以通过该方式实现安全限制,保证该URL的有效性,避免恶意用户自己生成跳转链接。
- 加入有效性验证Token:我们保证所有生成的链接都是来自于我们可信域的,通过在生成的链接里加入用户不可控的Token对生成的链接进行校验,可以避免用户生成自己的恶意链接从而被利用,但是如果功能本身要求比较开放,可能导致有一定的限制。
5. SQL注入
- SQL注入是比较常见的网络攻击方式之一,它不是利用操作系统的BUG来实现攻击,二十针对程序员编写时的疏忽,通过SQL语句,实现无账号登录,甚至篡改数据库。
- SQL主如攻击的总体思路
- 寻找到SQL注入的位置。
- 判断服务器类型和后台数据库类型。
- 针对不同的服务器和数据库特点进行SQL注入攻击。
6. OS命令注入攻击
原理
- OS命令注入攻击(OS Command Injection)是指通过Web应用,执行非法的操作系统命令达到攻击的目的。只要在能调用Shell函数的地方就有存在被攻击的风险。
- 可以从Web应用中通过Shell来调用操作系统命令。倘若调用Shell时存在漏洞,就可以 执行插入的非法OS命令。
- OS命令注入攻击可以向Shell发送命令,让Windows或Linux操作系统的命令行启动程序。也就是说,通过OS注入攻击可执行OS上安装者的各种程序。
漏洞利用
-
- 查询系统文件:提交参数查看相关文件(?cmd=type c:\windows\system32\drivers\etc\hosts)
-
- 显示当前路径:提交参数cmd = cd
-
- 写文件:提交参数 ?cmd=echo “<?php phpinfo();?>” > D:\xampp\htdocs\Commandi\shell.php。页面没有报错,说明文件写入成功,访问shell.php文件
防御方法
- 尽量减少命令执行函数的使用,并在disable_functions 中禁用
- 在进入命令执行函数的方法之前,对参数进行过滤
- 参数的值尽量使用引号包裹,并在调用之前进行转义。
设计模式
- 假设有一个空房间,我们要日复一日地往里面放一些东西。最简单的办法当然是把这些东西直接扔进去,但是时间久了,就会发现很难从这个房子里找到自己想要的东西,或者调整位置也很难。所以如果我们有一些柜子用来分类,也许是个好的选择,而这些柜子就是一种设计模式。
单例模式
- 确保只有一个实例,并且可以被全局访问到。
工厂模式
- 工厂模式是由一个方法来决定到底要创建哪个类的实例,而这些实例经常都拥有相同的接口。这种模式主要用在所实例化的类型在编译期并不能确定, 而是在执行期决定的情况。
适配模式
- 该模式主要是为了解决一些接口不兼容产生的问题,适配器可以在不修改这些不兼容接口的情况下给使用者提供统一包装过的适配接口。是对其他对象或者接口进行包装再呈现,适配模式偏向的是解决兼容性问题。
发布订阅模式
- 发布——订阅模式又叫观察者模式,它定义了对象间的一种一对多的关系,让多个观察者对象同时监听某一个主题对象,当一个对象发生改变时,所有依赖于它的对象都将得到通知。
策略模式
- 定义一些列的算法,把他们一个个封装起来,并且使它们可以相互替换
代理模式
- 为一个对象提供一个代用品或占位符,以便控制对它的访问。js里虚拟代理(网络请求相关)、缓存代理(数据相关)最常用。