反射型XSS(Reflected Cross Site Scripting)
反射型XSS,即非持久性XSS,这种攻击方式往往具有一次性的特点,仅通过'用户请求-服务器反射-浏览器执行'流程触发。
攻击者通过邮件等方式将含有XSS代码的恶意链接发给目标用户,当目标用户访问改链接时,服务器接收目标用户的请求进行处理,然后服务器把带有XSS代码的数据发送给目标用户的浏览器,在进行解析携带XSS代码的恶意脚本后就会触发XSS攻击,完成攻击者想要的效果,例如窃取敏感信息、伪造用户操作、劫持浏览器行为等。
Low
代码审计:
php
<?php
header ("X-XSS-Protection: 0");
// Is there any input?
//验证用户输入为空
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
// Feedback for end user
//查询返回
echo '<pre>Hello ' . $_GET[ 'name' ] . '</pre>';
}
?>
源代码只判断了name输入的存在(非空判断),

javascript
<script>alert('反射型xss注入')</script>
php
//代码执行效果如下:
<?php
header ("X-XSS-Protection: 0");
// Is there any input?
//验证用户输入
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
// Feedback for end user
//查询返回
echo '<pre>Hello ' . <script>alert('反射型xss注入')</script> . '</pre>';
}
?>

提取当前cookie,
javascript
<script>alert(document.cookie)</script>

Medium
代码审计:
php
<?php
header ("X-XSS-Protection: 0");
// Is there any input?
//验证输入
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
// Get input
//过滤<script>
$name = str_replace( '<script>', '', $_GET[ 'name' ] );
// Feedback for end user
//返回输出
echo "<pre>Hello {$name}</pre>";
}
?>
这次是把<script>做了置空替换。
大小写绕过:
<sCript>alert('medium反射型xss注入')</script>
*大写位置随意。

改写绕过:
<script<script>>alert('medium反射型xss注入改写绕过')</script>

High
代码审计
php
<?php
header ("X-XSS-Protection: 0");
// Is there any input?
//验证输入
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
// Get input
//正则输入过滤:匹配以<开头,中间包含s,c,r,i,p,t字母(任意顺序、任意间隔,以t结尾的字符串)置换为空
$name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $_GET[ 'name' ] );
// Feedback for end user
//返回查询
echo "<pre>Hello {$name}</pre>";
}
?>
preg_replace():执行一个正则表达式的搜索和替换,这次过滤了大小写和改写,以上方法无效。

<image src=0 οnerrοr=alert("high反射型xss")>

Impossible
代码审计:
php
<?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' );
// Get input
$name = htmlspecialchars( $_GET[ 'name' ] );
// Feedback for end user
echo "<pre>Hello {$name}</pre>";
}
// Generate Anti-CSRF token
generateSessionToken();
?>
仅作反射型XSS代码防护的学习。
存储型XSS
存储型XSS,即持久型XSS,攻击脚本会被永久的存放在目标服务器的数据库或文件中,且具有很高的隐蔽性,具有持久性和批量性。
多见于论坛,博客和留言板,攻击者在发帖的过程中,将恶意脚本连同正常信息一起注入至帖子内容中,随后被服务器存储下来。带该携带恶意脚本的帖子被浏览时,恶意脚本就会执行。常见于用户评论、内容发布功能、用户资料设置和私信等。
Low
代码审计:
php
<?php
if (isset($_POST['btnSign'])) {
// Get input
//输入传值
//对用户名和文本信息使用trim()移除字符串两侧的字符(例如,"Hello World!","Hello" 中的 "He"以及 "World" 中的 "d!")。
$message = trim($_POST['mtxMessage']);
$name = trim($_POST['txtName']);
// Sanitize message input
//stripslashes()返回抽离了反斜杠的字符串。
$message = stripslashes($message);
// 对message和name变量进行SQL转义处理,防止SQL注入攻击。
$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)) ? "" : ""));
// Sanitize name input
$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)) ? "" : ""));
// Update database
//插入name和message变量
$query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
//验证执行结果
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query) or die('<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>');
//mysql_close();
}
?>
$GLOBALS["__mysqli_ston"]:这是一个全局变量,存储mysqli数据库连接对象。
$query:这是要执行的SQL查询语句字符串。
mysqli_query():执行SQL查询的函数吗,成功时返回结果对象集。
<script>alert('存储型xss注入')</script>

点击sign guestbook存储,此后除非删除该留言,则每次访问此页面就是弹窗,干扰正常用户使用。
Medium
代码审计
php
<?php
if( isset( $_POST[ 'btnSign' ] ) ) {
// Get input
//trim()函数:移除字符串两侧空白字符。
$message = trim( $_POST[ 'mtxMessage' ] );
$name = trim( $_POST[ 'txtName' ] );
// Sanitize message input
//着重对message做了处理。
//addslashes()函数:对单引号、双引号、反斜杠等特殊字符添加反斜杠转义。
//strip_tags()函数:剥离字符串中的HTML标签。
$message = strip_tags( addslashes( $message ) );
//SQL转义,防止SQL注入语句。
//检查数据库连接,若不存在则出发错误。
$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)) ? "" : ""));
//把一些预定义的字符串做html实体转义,输出到页面时防止xss
$message = htmlspecialchars( $message );
// Sanitize name input
//str_replace()函数:将<script>标签替换为空。
$name = str_replace( '<script>', '', $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)) ? "" : ""));
// Update database
$query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
//mysql_close();
}
strip_tags() :删除所有HTML和PHP标签(如<script>、<style>),对xss跨站脚本攻击做了防御。
addslashes() :对单引号、双引号、反斜杠等特殊字符添加反斜杠转义。
htmlspecialchars() :将特殊字符(如<,>,&)转化为HTML实体(如<,>,&),确保数据在HTML中安全显示。
代码对于存储的message信息输入框做了多层过滤,第一层addslashes()函数过滤,第二层strip_tags()函数过滤,第三层htmlspecialchars()函数过滤。
name输入框只做了<script>标签的过滤。
在name输入框利用大小写尝试逃逸过滤,首先利用F12查询input修改输入限制,



嵌套写法尝试逃逸过滤:


High
代码审计
php
<?php
if( isset( $_POST[ 'btnSign' ] ) ) {
// Get input
$message = trim( $_POST[ 'mtxMessage' ] );
$name = trim( $_POST[ 'txtName' ] );
// Sanitize message input
$message = strip_tags( addslashes( $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
//preg_replace()函数:利用正则表达式对<script>标签过滤。
$name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $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)) ? "" : ""));
// Update database
//防止sql注入
$query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
//mysql_close();
}
?>
message和name都做了<script>标签的详细过滤,使用<img>:
php
<img src=0 onerror=alert("存储型xss注入high")>
和medium一一样的步骤,增加前端对name的输入字符:


Impossible
代码审计
php
<?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();
?>
这段代码处理了POST提交的留言和用户名,首先使用checkToken()验证user_token和会话中的session_token是否一致,防止攻击者伪造用户请求提交数据。
sql注入防护。
利用htmlspecialchars()处理输入,确保用户提交的内容中包含的HTML/JS代码不会被浏览器执行,例如<script>会被转化为<script&t,避免了存储型xss的注入攻击(当留言内容被展示时,恶意脚本不会生效。)。
XSS注入防御的简单方法:
- 验证数据类型和格式:
例如在注册表单中,邮箱字段应验证是否符合邮箱合适,手机号字段应验证是否位正确的手机号码格式等。PHP中可考虑例如filter_var()函数等验证邮箱,
过滤特殊字符:
例如htmlspecialchars()函数将HTML特殊字符转换为HTML实体,防止恶意脚本被浏览器解析执行。
- 输出编码的转义:
在将数据输出到HTML页面、Javascript代码中时,进行响应的编码处理。例如在输出HTML标签内容中时,使用htmlspecialchars()函数。
在将数据输出到Javascript代码中时,对字符串进行转义,防止恶意代码破坏Javascript语法结构。可以使用PHP中的json_encode()将数据转换为JSON格式,它可以自动对特殊字符进行转义。
- 避免使用eval函数:
eval函数会将传入的字符串作为Javascript代码执行,如果传入的字符串来自用户输入,就可能导致XSS攻击。
- 及时更新和维护web应用程序及依赖库。