Web应用漏洞攻击分析与防范

编程语言 来源:FengCheMoMo 312℃ 0评论

最近在研究网络安全问题,涉及到sql注入,xss,csrf等常见攻击,写了如下的一个文档,也参考很多大神的见解,在此也表示感谢,此文章以后会有所更新。
1.Web攻击常见方法简介
网站攻击主要分为以下几类:
(1) sql注入攻击
SQL Injection:就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。它是利用现有应用程序,将(恶意)的SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。
(2) xml注入攻击
XML是存储数据的一种方式,如果在修改或者查询时,没有做转义,直接输入或输出数据,都将导致XML注入漏洞。攻击者可以修改XML数据格式,增加新的XML节点,对数据处理流程产生影响。
(3) CSRF 攻击
CSRF(Cross-site request forgery),中文名称:跨站请求伪造,
攻击者盗用了你的身份,以你的名义发送恶意请求。CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账……造成的问题包括:个人隐私泄露以及财产安全。
(4) XSS攻击
XSS又称CSS,全称Cross SiteScript,跨站脚本攻击,是Web程序中常见的漏洞,XSS属于被动式且用于客户端的攻击方式,所以容易被忽略其危害性。其原理是攻击者向有XSS漏洞的网站中输入(传入)恶意的HTML代码,当其它用户浏览该网站时,这段HTML代码会自动执行,从而达到攻击的目的。如,盗取用户Cookie、破坏页面结构、重定向到其它网站等。
2.sql注入攻击
2.1 sql注入攻击造成的影响
绕过登录验证,非法登录系统;非法读取、篡改、添加、删除数据库中的数据;盗取用户的各类敏感信息,获取利益;通过修改数据库来修改网页上的内容;私自添加或删除账号;注入木马等等。
只要系统有一处存在sql注入漏洞,被利用到,对系统将是致命的伤害。最糟糕的是攻击者拿到了数据库服务器最高级的权限,可以对整个数据库服务器的数据做任何操作。
2.2 sql注入攻击原理分析
下面通过一个例子来了解sql注入的过程:
假如有个登录页面,页面需要输入登录名和密码才能登录系统,
正常sql语句应该是:
SELECT COUNT(*) FROM Login WHERE UserName=’admin’ AND Password=’123456’
以用户名和密码来查询用户信息来判断是否存在该用户,但如果我更改输入内容,将userName改为:admin’—,则sql语句将变为:
SELECT COUNT(*) FROM Login WHERE UserName=’admin’– Password=’123’
因为UserName值中输入了“–”注释符,后面语句被省略而登录成功。
以这样方式执行后的sql,已经违背原程序所执行的意图,用户输入数据,意外变成了代码被执行,针对于SQL注入,则是用户提交的数据,被数据库系统编译而产生了开发者预期之外的动作。也就是,SQL注入是用户输入的数据,在拼接SQL语句的过程中,超越了数据本身,成为了SQL语句查询逻辑的一部分,然后这样被拼接出来的SQL语句被数据库执行,产生了开发者预期之外的动作。
2.3 sql注入攻击的防范措施
Sql注入问题已经由来已久,但现在仍会发现大量sql注入攻击的发生,这是因为框架不完善,程序员没有意识拼接sql所造成安全性问题,遗留老系统的更改的难度等等问题。
以下就是几种防范sql注入发生的方法:
2.3.1 对用户输入数据进行检查和过滤
永远也不要相信用户输入,输入验证假定所有输入都是恶意的,用户的输入是未知的,但我们可以引导我们的用户,按照系统要求去输入合法的数据。
程序所需要做的,前端后端双重验证,由于前端验证很容易绕过,所以后端验证也是必须要的。
2.3.1.1 SpringMVC拦截器防止SQL注入
在用户输入的数据传输到后台逻辑代码之前,拦截到该请求,并对该请求中的用户输入进行转义处理。可参考:http://www.imooc.com/article/6137
http://www.cnblogs.com/Mainz/archive/2012/11/01/2749874.html
http://blog.csdn.net/niuch1029291561/article/details/17377857
也可以在BaseController中,定义共通方法中加一层过滤,
比如:

public String getParameter(String key) {
        try {
            String value = request.getParameter(key);

            String str = clearXss(value);
            if(null != value){
                Encoding encoding = StringUtils.getEncoding(value);
                if (encoding==Encoding.ISO88591) {
                    str = new String(value.getBytes(
                            "iso-8859-1"), "utf-8");                    
                }
            }
            return str;
        } catch (UnsupportedEncodingException e) {
            logger.warn("",e);
        } catch (NullPointerException e) {
            logger.warn("",e);
        }
        return "";
}
private String clearXss(String value) {
        if (value == null || "".equals(value)) {
            return value;
        }
        //You'll need to remove the spaces from the html entities below
        value = value.replaceAll("<", "& lt;").replaceAll(">", "& gt;");
        value = value.replaceAll("\\(", "& #40;").replaceAll("\\)", "& #41;");
        value = value.replaceAll("'", "& #39;");
        value = value.replaceAll("eval\\((.*)\\)", "");
        value = value.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\"");
        value = value.replaceAll("script", "");
        return value;
    }

以上的过滤方法也可以采用StringEscapeUtils类escapeSql方法,但此方法在最新版本中已经去掉(解释原文:This was a misleading method, only handling the simplest of possible SQL cases. As SQL is not Lang’s focus, it didn’t make sense to maintain this method.)可以看出使用参数化查询,就没有使用此方法必要了。参数化查询见下文。
http://stackoverflow.com/questions/32096614/migrating-stringescapeutils-escapesql-from-commons-lang
2.3.1.2 javascript 前端验证特殊字符
一般情况下,没有特殊要求,不允许用户输入特殊字符,利用特殊字符的正则表达式,可以很容易判断用户是否输入特殊字符,如果输入,则告知用户重新输入。
参考:
http://www.cnblogs.com/walkingp/archive/2009/08/31/1557456.html
2.3.2 处理所有的错误提示

当出现以上情况时,说明系统没有对错误进行拦截,这样就会给黑客分析我们系统机会。
黑客往往在第一次sql注入时,并不能造成什么实质性影响,但如果后台程序没有对错误进行相关处理,错误将直接返回给页面,那么黑客就可以根据返回错误内容不断调整sql语句,以达到他们的目的。所以后台拦截所有的错误提示,并返回我们想给用户展示的内容。数据验证可保护应用程序免遭恶意数据篡改,而有效的错误处理策略则是防止应用程序意外泄露内部错误消息(如异常堆栈跟踪)所不可或缺的。
(1)现在的框架基本都有对错误的拦截的设置,最简单的就是在web.xml 中配置错误页面,当发生某些错误时,跳转到我们自己设置好的页面:

    <error-page>
        <error-code>404</error-code>
        <location>/404.jsp</location>
    </error-page>
    <error-page>
        <error-code>500</error-code>
        <location>/500.jsp</location>
    </error-page>

(2)在controller中针对所有容易出错的处理,用try-catch包裹起来,捕捉错误,并进行相应处理。
2.3.3 参数化查询
一提到sql注入的防范,最佳的方式是参数化查询,他从根本上防止sql注入攻击。
关于参数化查询,首先要清楚一个概念,没有(运行时)编译,就没有注入。现在很多系统,在进行数据库操作的时候,往往会把参数直接拼接到sql中,然后在拿到数据库中编译运行,如果用户输入的数据包含某些sql语句,就很容易篡改我们的数据库。所以我们要做的就是使用预编译(Prepared statement),也就是将我们所要表达的sql语句预先编译,再讲用户数据以参数的形式传入到sql语句中,
这样sql语句就不会改变原有的意思,无论用户输入的什么数据,都会认为是参数,而不是sql语句的一部分。
2.3.1.1 mybatis针对sql注入攻击的解决方案
mybatis有两种参数的书写形式:
(1)#{xxxxxx} (2){xxxxxx}  
第一种就是参数化查询方式,很好的避免了sql注入漏洞,#将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。如:order by #{user_id},如果传入的值是111,那么解析成sql时的值为order by “111”, 如果传入的值是id,则解析成的sql为order by “id”。第二种需要注意,
将传入的数据直接显示生成在sql中。如:order by {user_id},如果传入的值是111,那么解析成sql时的值为order by user_id,  如果传入的值是id,则解析成的sql为order by id。  
一般情况下,能用#就别用

$方式一般用于传入数据库对象,例如传入表名,传入参数为int类型等,可以说应用的场景很少。

结论:参数化查询+错误提示拦截,可以避免绝大多数sql注入问题
如果需求需要用到sql的拼接语句,就对此特殊地方进行过滤及转义的处理。
3.xml注入攻击
XML是存储数据的一种方式,如果在修改或者查询时,没有做转义,直接输入或输出数据,都将导致XML注入漏洞。
3.1 xml注入攻击造成的影响
可以导致信息泄露、任意文件读取、DOS攻击和代码执行等问题。
3.2 xml注入攻击原理分析
Xml注入与sql注入类似,当用户数据是以xml的形式存储或传输的,那么就可以输入xml中的标签来篡改xml的内容。
3.3 xml注入攻击的防范措施
与防范sql注入类似,xml注入的防范措施主要集中于两方面:
(1) 用户输入检查(2)用户输入的过滤转义
参考:http://blog.csdn.net/mevicky/article/details/48239481
http://zhouhaitao.iteye.com/blog/1484930

4.CSRF 攻击
4.1 CSRF攻击造成的影响
你这可以这么理解CSRF攻击:攻击者盗用了你的身份,以你的名义发送恶意请求。CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账……造成的问题包括:个人隐私泄露以及财产安全。
CSRF 攻击的对象
在讨论如何抵御 CSRF 之前,先要明确 CSRF 攻击的对象,也就是要保护的对象。从以上的例子可知,CSRF 攻击是黑客借助受害者的 cookie 骗取服务器的信任,但是黑客并不能拿到 cookie,也看不到 cookie 的内容。另外,对于服务器返回的结果,由于浏览器同源策略的限制,黑客也无法进行解析。因此,黑客无法从返回的结果中得到任何东西,他所能做的就是给服务器发送请求,以执行请求中所描述的命令,在服务器端直接改变数据的值,而非窃取服务器中的数据。所以,我们要保护的对象是那些可以直接产生数据改变的服务,而对于读取数据的服务,则不需要进行 CSRF 的保护。比如银行系统中转账的请求会直接改变账户的金额,会遭到 CSRF 攻击,需要保护。而查询余额是对金额的读取操作,不会改变数据,CSRF 攻击无法解析服务器返回的结果,无需保护。
4.2 CSRF攻击原理分析

4.3 CSRF攻击的防范措施
(1).验证码
  这个方案的思路是:每次的用户提交都需要用户在表单中填写一个图片上的随机字符串,这个方案可以完全解决CSRF,但此方案只能针对系统特定功能上,比如注册,登记,查询等,不可能每个请求的地方都用验证码。
(2). 在请求地址中添加 token 并验证
CSRF 攻击之所以能够成功,是因为黑客可以完全伪造用户的请求,该请求中所有的用户验证信息都是存在于 cookie 中,因此黑客可以在不知道这些验证信息的情况下直接利用用户自己的 cookie 来通过安全验证。要抵御 CSRF,关键在于在请求中放入黑客所不能伪造的信息,并且该信息不存在于 cookie 之中。可以在 HTTP 请求中以参数的形式加入一个随机产生的 token,并在服务器端建立一个拦截器来验证这个 token,如果请求中没有 token 或者 token 内容不正确,则认为可能是 CSRF 攻击而拒绝该请求。
(3) 尽量使用POST,限制GET
(4) 验证 HTTP Referer 字段
根据 HTTP 协议,在 HTTP 头中有一个字段叫 Referer,它记录了该 HTTP 请求的来源地址。在通常情况下,访问一个安全受限页面的请求来自于同一个网站,比如需要访问 http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory,用户必须先登陆 bank.example,然后通过点击页面上的按钮来触发转账事件。这时,该转帐请求的 Referer 值就会是转账按钮所在的页面的 URL,通常是以 bank.example 域名开头的地址。而如果黑客要对银行网站实施 CSRF 攻击,他只能在他自己的网站构造请求,当用户通过黑客的网站发送请求到银行时,该请求的 Referer 是指向黑客自己的网站。因此,要防御 CSRF 攻击,银行网站只需要对于每一个转账请求验证其 Referer 值,如果是以 bank.example 开头的域名,则说明该请求是来自银行网站自己的请求,是合法的。如果 Referer 是其他网站的话,则有可能是黑客的 CSRF 攻击,拒绝该请求。
结论:使用token验证,请求尽量使用post请求。
5.XSS攻击
XSS又称CSS,全称Cross SiteScript,跨站脚本攻击,是Web程序中常见的漏洞,XSS属于被动式且用于客户端的攻击方式,所以容易被忽略其危害性。其原理是攻击者向有XSS漏洞的网站中输入(传入)恶意的HTML代码,当其它用户浏览该网站时,这段HTML代码会自动执行,从而达到攻击的目的。如,盗取用户Cookie、破坏页面结构、重定向到其它网站等。
5.1 XSS 攻击造成的影响
盗取用户Cookie、破坏页面结构、重定向到其它网站等。
5.2 XSS 攻击原理分析
XSS攻击类似于SQL注入攻击,攻击之前,我们先找到一个存在XSS漏洞的网站,XSS漏洞分为两种,一种是DOM Based XSS漏洞,另一种是Stored XSS漏洞。理论上,所有可输入的地方没有对输入数据进行处理的话,都会存在XSS漏洞,漏洞的危害取决于攻击代码的威力。
5.2.1 DOM Based XSS漏洞
用户登录A网站,然后用户在某种情况下,点击了恶意网站B网站,B网站可能只有一个图片,图片属性访问了一个A网站的URL,这样恶意带着用户登录A网站后的cookie访问了A网站,而A网站无法知道此访问的是否是用户本人,从而造成了攻击。
5.2.2 Stored XSS
恶意用户登录A网站,并在A网站需要输入的地方,输入了恶意代码,当其他用户查询到恶意用户输入的信息后,代码便会执行,从而达到攻击很多人的目的。
5.3 XSS 攻击的防范措施
(1)针对DOM Based XSS的攻击,现在的主流浏览器都设置一个属性来防止js盗用cookie信息,此属性为HttpOnly,设置方法见:
http://zhenghaoju700.blog.163.com/blog/static/13585951820138267195385/
(2)对输入项进行转义显示。将数据原封不动存入数据库,在取数据时,将数据进行转义显示。这样攻击代码不会被解释成代码标签执行。
(3)对输入项信息进行过滤。此方法可能会被绕过。
(4)对输入检查,严格限制输入项格式,输入项长度;对输出转义,对数据项有特殊符号,可能会发生xss攻击的,页面显示时进行转义处理。
转义方法可以使用:
1.Apache的commons-lang.jar的StringEscapeUtils.escapeHtml(str);
2. ESAPI的encodeForHTML方法。
针对用户输入的不可信数据插入页面位置进行分类
① 数据在html标签内用:encodeForHTML
② 数据在标签属性内时用:encodeForHTMLAttribute
③ 数据在JavaScript中时用:encodeForJavaScript
④ 数据在css中时用:encodeForCSS
⑤ 数据在url中时用:encodeForURL
3.jstl c:out标签也可做转义操作,但是此方法需要在每个页面变量的地方加入,增加了编码复杂性。
4. Jsoup是一款 Java 的HTML 解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API,可通过DOM,CSS以及类似于JQuery的操作方法来取出和操作数据。
5. XSS HTMLFilter 这是一个采用Java实现的开源类库。用于分析用户提交的输入,消除潜在的跨站点脚本攻击(XSS),恶意的HTML,或简单的HTML格式错误。
结论:针对登记系统特点,对一些需要输入很长文本的输入框要进行数据的转义操作,建议采用对输入项信息转义保存方法。在取数据时采用encodeForHTML方法。
5.漏洞扫描工具和sql注入工具
(1)sqlmap sql 注入测试工具
(2)pangolin sql注入测试工具
(3) IBM Security AppScan Standard web应用漏洞扫描工具
6.参考资料
Web安全之XML注入:http://blog.csdn.net/mevicky/article/details/48239481
浅谈CSRF攻击方式:
http://www.cnblogs.com/hyddd/archive/2009/04/09/1432744.html
SQL注入原理讲解,很不错!:
http://blog.csdn.net/stilling2006/article/details/8526458/
如何从根本上防止 SQL 注入?:
https://www.zhihu.com/question/22953267
mybatis中的#和$的区别:
http://blog.csdn.net/kobi521/article/details/16941403
SpringMVC利用拦截器防止SQL注入:
http://www.imooc.com/article/6137
XML注入:
http://www.51testing.com/html/47/352747-814931.html
Web安全之XML注入
http://blog.csdn.net/mevicky/article/details/48239481
浅谈CSRF攻击方式:
http://www.cnblogs.com/hyddd/archive/2009/04/09/1432744.html
XSS攻击及防御:
http://blog.csdn.net/ghsau/article/details/17027893
XSS注入方式和逃避XSS过滤的常用方法:
http://blog.csdn.net/yinqiaohua/article/details/52087208
java 防止xss攻击:
http://breezylee.iteye.com/blog/2063615
防御 XSS 的七条原则:
http://www.oschina.net/news/43919/7-principles-of-defense-xss
ESAPI解决CSRF:
http://book.2cto.com/201212/12162.html
web安全之token和CSRF攻击:
http://blog.csdn.net/qq_15096707/article/details/51307024
总结 XSS 与 CSRF 两种跨站攻击:
http://www.cnblogs.com/wangyuyu/p/3388180.html
CSRF 攻击的应对之道:
http://www.ibm.com/developerworks/cn/web/1102_niugang_csrf/
使用Jsoup消除不受信任的HTML (来防止XSS攻击):
http://elf8848.iteye.com/blog/1872433
跨站点脚本攻击(XSS)防护 XSS HTMLFilter:
http://blog.csdn.net/jasontome/article/details/7215468