网安教育
培养网络安全人才
技术交流、学习咨询
1.1反射xss
1.1.1 输出在html 标签内或者普通属性(非href、非事件类)
调用如下的HtmlEncode 函数进行编码,php 示例代码,其他语言可以参照实现。
1function HtmlEncode($str)
2
3{
4
5 $str = str_replace("&","&", $str);
6
7 $str = str_replace(">",">", $str);
8
9 $str = str_replace("<","<", $str);
10
11 $str = str_replace(""",""", $str);
12
13 $str = str_replace("'","'", $str);
14
15 $str = preg_replace("/s+/"," ", $str);
16
17 return $str;
18
19}
注:为了预防业务将参数输出至属性值时未使用引号包裹的情况,这里自己实现的HtmlEncode 也将空格编码。
1.1.2 输出在html 标签的 href 属性内
一般来说,如果变量是完整的url,应该先检查下是否以^http开头,且目的域名是允许的域名列表内,以保证不会出现伪协议类的XSS攻击。接着使用 HtmlEncode编码下;或者因为此处是地址栏,可以用 php标准函数urlencode 编码变量。
1.1.3 输出在html 标签的事件属性内(如onXX 事件)
使用 jsencode(uUUUU) 编码,php 示例代码,其他语言可以参照实现。
1function jsencode($str)
2
3{
4
5 $arr = array();
6
7 $str_len = strlen($str);
8
9 $need_encode = "<>"&#`()[]';";
10
11 for($i = 0; $i < $str_len; $i++)
12
13 {
14
15 if (strpos($need_encode, $str[$i]))
16
17 {
18
19 $arr[$i] = "\u00" . bin2hex($str[$i]);
20
21 }
22
23 else
24
25 {
26
27 $arr[$i] = $str[$i];
28
29 }
30
31 }
32
33 return join("", $arr);
34
35 }
1.1.4 在富文本框内进行过滤
参考 这里 进行标签和属性的白名单过滤。
1.2 存储XSS
同反射XSS,在输出变量时参照如上情形描述。
1.3 DOMXSS
在"$var" 输出到<script> 时,应该执行一次 jsencode(uUUUU);其次,在document.write 输出到页面 html 页面时,要分具体情况对待:如果是输出到事件或者脚本,则要再做一次 jsEncode;如果是输出到 html 内容或者属性,则要再做一次 HtmlEncode。
如下情况属于后者,即 HtmlEncode (jsencode($var))
1<script>
2
3var x = "$var";
4
5document.write("<a href='"+x+"' >test</a>");
6
7</script>
Javascript 函数代码示例如下:
1function jsencode(str) {
2
3 var arr = [];
4
5 var need_encode = "<>"&#`()[]';";
6
7 for (var i = 0; i < str.length; i++) {
8
9
10
11 if (need_encode.indexOf(str[i]) != -1)
12
13 {
14
15 arr[i] = ("\u00" + str.charCodeAt(i).toString(16)).slice(-6);
16
17 }
18
19 else
20
21 {
22
23 arr[i] = str[i];
24
25 }
26
27 }
28
29 return arr.join("");
30}
31
32
33
34function HtmlEncode(sStr)
35
36{
37
38 sStr = sStr.replace(/&/g,"&");
39
40 sStr = sStr.replace(/>/g,">");
41
42 sStr = sStr.replace(/</g,"<");
43
44 sStr = sStr.replace(/"/g,""");
45
46 sStr = sStr.replace(/'/g,"'");
47
48 sStr = sStr.replace(/s+/g," ");
49
50 return sStr;
51
52}
在使用location.href / location.replace() / location.assign() 等函数实现前端跳转时不止要考虑url 任意跳转的问题,如1.1.2 所说也要避免伪协议引起的xss攻击。
1.4 flash xss
建议不再使用的swf请下线,其他有漏洞的swf请更新至官方最新版,或者用其他功能类似swf 替代实现。
2.1 校验refer
Refer 校验需要严格的正则,比如 /^http://www.qq.com/index.html$/,否则可能被绕过。但是某些情况下发出的情况Refer 为空甚至以前曾经出现过flash请求可以伪造Refer,故更敏感的一些操作建议使用验证token方式。
2.2 验证token
即在页面埋下隐藏的动态token值,后端逻辑对这个token 值进行验证,如果不正确则直接退出。php 代码示例如下:
1<?php
2
3
4
5session_start();
6
7if (isset($_SESSION['token']) && isset($_POST['username'])) {
8
9 if (empty($_POST['token']) || $_POST['token'] != $_SESSION['token']) {
10
11 header('Location: http://localhost/error.php?token=' . $_SESSION['token']);
12
13 exit(-1);
14
15 }
16
17}
18
19
20
21$token = md5(time());
22
23$_SESSION['token'] = $token;
24
25?>
26
27
28
29<html>
30
31<head>
32
33 <title>test with csrf token</title>
34
35</head>
36
37<body>
38
39<form method="post" action="/csrf.php" id="form">
40
41 <div>
42
43 <input name="username" type="text" id="username" style="width:270px;"/>
44
45 <input type="submit" name="btnSearch" value="Search" id="btnSearch" />
46
47 <input type="hidden" name="token" id="token" value="<?php echo $token;?>" />
48
49 </div>
50
51</form>
52
53
54
55<br/>
56
57</body>
58
59</html>
2.3 验证码
在特别关键的操作建议启用,其他操作建议预埋验证码,紧急时刻(如出现CSRF蠕虫)可以临时启用。
3.1 首选绑定参数的方式进行sql 操作
PHP5中,增加了MySQL支持,提供了mysqli扩展:
PHP手册地址:http://php.net/mysqli
1<?php
2
3// retrieve the user's input
4
5$animalName = $_POST['animalName'];
6
7// connect to the database
8
9$connect = mysqli_connect('localhost', 'username', 'password', 'database');
10
11if (!$connect)
12
13 exit('connection failed: ' . mysqli_connect_error());
14
15// create a query statement resource
16
17$stmt = mysqli_prepare($connect, "SELECT intelligence FROM animals WHERE name = ?");
18
19if ($stmt) {
20
21 // bind the substitution to the statement
22
23 mysqli_stmt_bind_param($stmt, "s", $animalName);
24
25 // execute the statement
26
27 mysqli_stmt_execute($stmt);
28
29 // retrieve the result...
30
31 mysqli_stmt_bind_result($stmt, $intelligence);
32
33 // ...and display it
34
35 if (mysqli_stmt_fetch($stmt)) {
36
37 print "A $animalName has $intelligence intelligence.n";
38
39 } else {
40
41 print 'Sorry, no records found.';
42
43 }
44
45 // clean up statement resource
46
47 mysqli_stmt_close($stmt);
48
49}
50
51mysqli_close($connect);
52
53?>
3.2 检测参数类型,添加转义
如果php版本太低,或者改造代码成本比较大,在使用参数拼接方式实现sql 操作时,务必做到以下两点:
3.2.1 检查参数类型
当用户输入的为数字时可以使用如下方式:
使用is_int()函数(或is_integer()或is_long()函数)
使用gettype()函数
使用intval()函数
使用settype()函数
检查用户输入字符串的长度使用strlen()函数。
检查日期或时间是否是有效的,可以使用strtotime()函数。
3.2.2 查询之前进行转义操作
对于一个已经存在的程序来说,可以写一个通用函数来过滤:
1function safe($string)
2
3{
4
5 return "'" . mysql_real_escape_string($string) . "'";
6
7}
调用方式:
1$variety = safe($_POST[' variety ']);
2
3$query = "SELECT * FROM wines WHERE variety=" . $variety;
注:mysql_real_escape_string 必须在(PHP 4 >= 4.3.0, PHP 5)的情况下才能使用,否则只能用 mysql_escape_string,转义字符有:x00 , n , r , , ' , " and x1a。
Safe 函数中需要将转义之后的字符串用引号包裹起来(对于int类型说查询结果一致),否则黑客本来就不用考虑去闭合引号,转义操作也等于没有效果。
如果数据库字符集是gbk,可能存在宽字节绕过问题,需要在查询之前设置一下character_set_client,如下所示:
1mysql_query("SET character_set_connection=gbk, character_set_results=gbk,character_set_client=binary", $conn);
4.1 本地文件包含
php中可以使用 open_basedir 将用户文件访问限制在指定的区域。如将文件访问限制在 /dir/user/ 中,在php.ini中设置 open_basedir = /dir/user/。
对包含文件的名称、路径进行严格限制和过滤(建议白名单方式),避免被篡改为恶意文件,单纯过滤 ”../” 等相对路径串很可能会被绕过。过滤以下字符(以逗号分隔):
1../, %2e%2e%2f, %2e%2e/, ..%2f, %2e%2e%5c, %2e%2e, ..%5c, %252e%252e%255c, ..%c0%af(仅windows需要), ..%c1%9c(仅windows需要)
4.2 远程文件包含
关闭allow_url_fopen、allow_url_include。
对于传入的变量做过滤,对于 n $ & ; | ' " ( ) `(反单引号) 过滤或转义这些特殊字符。
限制 C(libcurl)/php(cURL) 允许的协议
如设置CURLPROTO_HTTP选项,仅仅允许http和https请求,可以防止类似于file:///, gopher://, ftp:// 等引起的问题。
限制访问内网
从url 中提取出域名 www.test.com ,解析域名,获得域名指向的地址 X.X.X.X
检查地址是否为内网地址段:10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,127.0.0.0/8等,
如果是内网地址则屏蔽;
如果不是内网地址,设置 CURLOPT_RESOLVE(libcurl),使libcurl 将域名解析到我们刚才解析出的ip 地址进行访问,即真正发起请求时不再进行dns解析,避免被 dns rebinding 绕过。
避免30x 跳转绕过
设置不跟随跳转,即设置 CURLOPT_FOLLOWLOCATION 为false。如果一定要跟随跳转,这里因为使用了库函数,故不能自己在跟随跳转前判断下域名解析的目标ip 是否是内网(如2),但可以通过设置 CURLOPT_OPENSOCKETFUNCTION 回调函数,在socket 创建之前先校验目标地址。
1// curl_easy_setopt(curl, CURLOPT_OPENSOCKETFUNCTION, opensocket_callback);
1curl_socket_t opensocket_callback(void *clientp, curlsocktype purpose,
2 struct curl_sockaddr *addr)
3{
4 struct sockaddr_in *addr_in = (struct sockaddr_in *) &addr->addr;
5 unsigned int uip = ntohl(addr_in->sin_addr.s_addr);
6
7 char ipbuf[50];
8 inet_ntop(addr_in->sin_family, &addr_in->sin_addr, ipbuf, sizeof(ipbuf));
9 INF("Connect IP: %sn", ipbuf);
10
11 if ((uip >= 0x7F000000 && uip <= 0x7FFFFFFF) ||
12 (uip >= 0x0A000000 && uip <= 0x0AFFFFFF) ||
13 (uip >= 0xAC100000 && uip <= 0xAC1FFFFF) ||
14 (uip >= 0xC0A80000 && uip <= 0xC0A8FFFF) ||
15 (uip == 0x00000000 || uip == 0xFFFFFFFF))
16 {
17 //过滤来自内网的访问
18 WRN("target ip is illegal.n");
19 return CURL_SOCKET_BAD;
20 }
21
22 return socket(addr->family, addr->socktype, addr->protocol);
23}
这样,每当libcurl 试图创建socket 连接某个服务器时,都会先执行 opensocket_callback 回调函数。若目标地址不合法,则可以在这个回调函数中返回CURL_SOCKET_BAD,libcurl 也会因此无法建立连接返回失败。
7.1 目录安全配置
如果Apache以daemon普通用户启动,则黑客通过网站漏洞入侵服务器后,将获得Apache的daemon权限,因此需要确认网站web目录和文件的属主与Apache启动用户不同,防止网站被黑客恶意篡改和删除。
a) 网站web目录和文件的属主可以设置为root等(非Apache启动用户)。
b) Web目录权限统一设置为755,web文件权限统一设置为644(cgi文件若需执行权限可设置为755),只有上传目录等需要可读可写权限的目录可以设置为777(目录需要有执行权限才可进入)。
目录默认不可写,可写目录不解析,Web Server非root,管理页面不对外。
7.2判断文件类型
可以结合使用mime type、后缀方式、文件头部(getimagesize /exif_imagetype),强烈推荐白名单方式。
7.3 改写文件名和路径
使用随机数改写文件名和文件路径;或者把文件放在非web 目录下(或者统一的一个文件服务器),且设置open_basedir 以避免被文件包含。
7.4上传目录只允许访问特定类型的文件
配置文件如下:
1<Files ^(*.jpeg|*.jpg|*.png|*.gif)>
2
3order deny,allow
4
5deny from all
6
7</Files>
管理后台默认不对外开放,如果一定要对外开放,需要有安全配置。
对于管理目录,需要做到只允许合法ip(一般内网)可以访问,nginx限制白名单ip访问的配置如下:
1location ~ ^/private/ {
2
3allow 192.168.1.0/24;
4
5deny all;
6
7}
管理目录建议启用密码认证,密码认证依靠Web应用自身的认证机制。如果Web应用无认证机制,可启用nginx(apache同理)的密码认证机制,配置如下:
1location ^~ /soft/ {
2
3location ~ .*.(php|php5)?$ {
4
5fastcgi_pass unix:/tmp/php-cgi.sock;#这里按照你自己的设置
6
7fastcgi_index index.php;
8
9include fcgi.conf;
10
11}
12
13auth_basic "Authorized users only";
14
15auth_basic_user_file 这里写前面脚本返回的文件路径;
16}
战疫期间,开源聚合网络安全基础班、实战班线上全面开启,学网络安全技术、升职加薪……有兴趣的可以加入开源聚合网安大家庭,一起学习、一起成长,考证书求职加分、升级加薪,有兴趣的可以咨询客服小姐姐哦!
加QQ(1271375291)找小姐姐私聊哦
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论