xss跨站脚本攻击

xss跨站脚本攻击

1、介绍

XSS攻击,其实就是黑客将恶意的脚本,注入到浏览的网页中从而改变网页的dom结构,当受害者访问这些页面时,浏览器会解析并执行这些恶意代码,从而达到窃取用户身份/钓鱼/传播恶意代码等行为。

类型:反射性,存储型,dom型

场景:搜索框,留言板

环境:windows-s-2008,phpstudy2016,攻击机。

成因:对用户提交的数据没有做很好的过滤所导致

1、 反射型xss

特点:非持久化,每次必须注入才能触发。

由于dom型也算是反射型的一种,所以就拿到一块来分析。

说直白点就是你在网站输入文字后,你的文字会在网站上显示,说明你的文字暂时存放在了html中

举个栗子,我在下载小说的时候在书城搜索1,他会在页面留下如下图。

说明他也存在前端代码中

好!那我们就开始仿造!

<meta charset="UTF-8">
<form action="XSS.php" method="post">
	<h1>反射型XSS</h1>
	<input type="text" name="keyword" value="<?php echo @$_POST["keyword"]; ?>">
	<input type='submit' value="搜索" name="submit">
	<p>find:<?php echo @$_POST["keyword"]; ?></p>
</form>

来测试一下

因为有的网站你搜索的文字也会遗留在搜索框中,所以我们也这么处理了,这样来说,可以注入的点就有两个了。再直白点来说你改变了该网站两处地方

好到这了大家就可以理解反射性xss为什么是短暂的,因为你改变的是前端,而所有数据是服务器提供的,所以当你刷新的时候数据就会重置到一开始的样子。

2、存储型XSS

特点:持久化,一但成立不管谁访问都会受到影响

其实如果理解了上述所说的,你改变了网页的html,但是提供数据的是服务器所以刷新或者从新访问就会消失,但是存储型xss是改变了服务器的数据,然后影响了前端页面。所以只要服务器不改变,你注入的代码不被删除,影响就会一直存在。

我们也来模拟

首先我们在数据库中建立一个名为xss的数据库

然后在xss的数据库中创建一个名为message的表

有id,message字段,id为主键

CREATE TABLE `message` (
  `id` int(50) NOT NULL AUTO_INCREMENT,
  `message` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

模拟代码如下

####  XXS.php
<h1>存储型XSS</h1>
<?php
$host = "127.0.0.1";
$user = "root";
$pass = "root";
$db = "xss"; 
$link = @mysqli_connect($host,"root",$pass,$db);

if(!$link){
	die(mysqli_connect_error());
}
?>
<?php
$sql = "select message,id from message;";

$results = mysqli_query($link,$sql);


if($results === false){
    die("[".mysqli_errno($link)."]".mysqli_error($link));
}
?>
<table border="1" width="80%">
<?php
while($result = mysqli_fetch_assoc($results)){
	$html = <<<HTML
	<tr>
		<td>{$result['id']}</td>
        <td>{$result['message']}</td>
        
        <td>
            <a href="./xssform.php?id={$result['id']}">修改</a>|<a href="delect.php">删除</a>
    </tr>	

HTML;
echo $html;
}
?>
</table>

#### xssfrom
<?php
$host = "127.0.0.1";
$user = "root";
$pass = "root";
$db = "xss"; 
$link = @mysqli_connect($host,"root",$pass,$db);

if(!$link){
	die(mysqli_connect_error());
}
?>


<?php
	
    @$message = $_POST['message'];
	//echo $message;
	//echo "<br />";
	$id = $_GET['id'];
	//echo $id;
    $sql = "update message set message='{$message}' where id='{$id}';";
	//echo $sql;
    $results = mysqli_query($link,$sql);
	
  
?>
<meta charset="UTF-8">
<form action="" method="post">
	<h1>存储型XSS</h1>
	<input type="text" name="message">
	<input type='submit' value="确认修改" name="submit1">
	<br/>
	<a href="./XSS.php">返回上一级</a>
</form>

说明后台读取的数据在前段展现了,可以控制。

2、xss的攻防

攻击语句的构造

思路:既然就是注入一个可运行的html代码,那就可以利用<>.’’.” ”去闭合原来的html标签,再构造新的标签就好。

1、利用JavaScript伪协议

<a href=javascript:alert(/xss/)>click me!</a>
<img src="javascript:alert(/xss/)">

2、利用html中触发事件来攻击

<img onmouseover='alert(/dont touch me!/)' src=""> //鼠标悬在该图片上
<input type="text" onkeydown="alert(/xss/)">       //在该输入框按下键盘任意键
<input type="text" onkeyup="alert(/xss/)">         //在该输入框按下键盘任意键并抬起

这种事件还有很多大家可以去html学习的网站上去查看

代码测试实验

然后实验一下

输入框输入

<scrript>alert(/xss/)</script>

JS语句执行了,说明注入成功了。那我们来看一下现在网站的前端代码

执行的是下面的语句,因为上面的语句作为属性的值被“”引用了,所以我们只需利用 “>去闭合就好

代码就变成了


JS所以逃逸出来了,就执行了。

所以我们要怎么防御呢?

思路:既然是他们是利用“”,<>,script,javascript,img,a等去绕过的,那把这些关键字符过滤掉怎么样

在文件任意读取与下载中我们讲到了可以用str_replace()函数去过滤,但是他的缺点是可以双写或者大小写过滤。所以今天我们换一种函数preg_replace

preg_replace

是正则法则过滤,

preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $_GET[ 'keyword' ] ); 
完美的过滤了<script /<SCRIPT

由于条件原因(token,我们会在csrf中详细讲述)我们借鉴一下DVWA中的xss的无懈可击版本

<?php

// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {//基本输入都会做空判断
    // Check Anti-CSRF token
    checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); //检查token值

    // Get input
    $name = htmlspecialchars( $_GET[ 'name' ] );//把预定义的字符 "<" (小于)和 ">" (大于)转换为 HTML 实体

    // Feedback for end user
    echo "<pre>Hello ${name}</pre>";
}

// Generate Anti-CSRF token
generateSessionToken();

?> 

htmlspecialchars

不会让<>下的标签解析

<?php
$str = "This is some <b>bold</b> text.";
echo htmlspecialchars($str);
?>

>>>This is some <b>bold</b> text.

在我们的模拟上实验一哈,


被打印了出来没有被解析,说明成功。

反射型的说完了我们来看看存储型的。

让我们许修改1111<script>alert(/xss/)</script>,然后返回发现

出现了弹窗,然后我们关闭了弹窗,再刷新一下页面发现还是会有弹窗

!
说明该语句只要存在数据库中就会永远生效。

因为大部分存储型xss在留言或者博客发表文章这一场景中,所以让我们的过滤就有了很多限制,不可能说用户想说的话十个字符,过滤了一半,这样就会极大降低了用户的使用体验。

我们还是先看一下DVWA中 存储型xss的完全防御代码

<?php

if( isset( $_POST[ 'btnSign' ] ) ) {
    // Check Anti-CSRF token
    checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );

    // Get input
    $message = trim( $_POST[ 'mtxMessage' ] );//过滤掉特殊字符
    $name    = trim( $_POST[ 'txtName' ] );

    // Sanitize message input
    $message = stripslashes( $message );
    $message = ((isset($GLOBALS["___mysqli_ston"]) &&          is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
    
    $message = htmlspecialchars( $message );

    // Sanitize name input
    $name = stripslashes( $name );
    $name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
    $name = htmlspecialchars( $name );

    // Update database
    $data = $db->prepare( 'INSERT INTO guestbook ( comment, name ) VALUES ( :message, :name );' );
    $data->bindParam( ':message', $message, PDO::PARAM_STR );
    $data->bindParam( ':name', $name, PDO::PARAM_STR );
    $data->execute();
}

// Generate Anti-CSRF token
generateSessionToken();

?> 

让我们来审计一下

先看一下各个函数的用法

trim

语法:trim(string,charlist)
string:	必需。规定要检查的字符串。
charlist:可选。规定从字符串中删除哪些字符。如果被省略,
则移除以下所有字符:   "\0" - NULL
                    "\t" - 制表符
                    "\n" - 换行
                    "\x0B" - 垂直制表符
                    "\r" - 回车
                    " " - 空格

stripslashes:删除字符串中的\

bindParam:绑定参数

如果有'',会变成\'\'

3、总结

xss的防御

输入过滤

输入验证:

仅接受指定长度、
仅包含合法字符
仅接收指定范围
特殊的格式严格控制:邮箱、IP

输入过滤:

str_replace
trim
stripslashes
htmlspecialchars

输出编码

黑白名单策略

防御DOM型xss

避免客户端文档重写,重定向或者其他敏感操作!

posted @ 2021-09-12 20:05  shy_dow  阅读(300)  评论(0)    收藏  举报