1. 引言
1.1. 文档说明:
1.2. 文档组织方式:
2. 正文
2.1. SQL注入
2.1.1. 攻击模式:
2.1.2. 防御办法:
2.2. 脚本注入
2.2.1. 攻击模式
2.2.2. 防御方式
2.3. 跨站攻击
2.3.1. 攻击模式
2.3.2. 防御方式
2.4. shell 上传
2.4.1. 攻击模式
2.4.2. 防御方式
2.5. 爆破
2.5.1. 攻击模式
2.5.2. 防御方式
3. 结语
1. 引言
1.1. 文档说明:
该文档主要阐述在BS程序中,安全性方面的注意事项。常见的主要攻击模式,以及为了防御这些不同的攻击手段,作为技术人员建议注意的编码事项。
该文档包含的内容主要是个人对于Internet安全性问题的理解。以及对这些问题进行规避的方法整理,难免有误,也欢迎大家进行指正和补充。
另注:该文档出现的编码均为伪代码。
1.2. 文档组织方式:
该文档主要按照攻击模式进行分类整理,每个攻击模式的小专题分2部分内容:
(1) 攻击模式详述
(2) 防御方式与建议
对于攻击模式详述部分,尽可能多的举出案例来进行说明,已方便理解。而防御方式,实际上通常只有在对攻击模式理解的前提下,才可能真正确保防御的有效。
2. 正文
2.1. SQL注入
2.1.1. 攻击模式:
SQL 注入的成因主要是因为向DB提供的SQL是用字符串拼装的方式生成的。
最经常遭受SQL注入的页面通常是管理员/用户登陆点。不论是asp或是jsp,如果不正确的编码,都会出现这个漏洞。
下面以一个实例来阐述SQL注入的成因。
假设我们有一个JSP页面login.jsp,用于搜集管理员输入的用户名和密码。用户点击按钮,将会把收集到的用户名与密码提交到指定的控制组件(Struts:Action,或者Servlet).在该组件中调用chekLogin(String userName, String passWord) 进行登陆验证,以从页面收集到的用户名和密码信息拼装出SQL字符串,供DAO下层使用,以从数据库中的管理员记录表中读取数据,如果从表中找到匹配的记录,则表示验证成功,我们将返回相应得管理员实体类。否则返回Null表示登陆验证失败。
这个逻辑产生注入漏洞的关键在于checkAdminLogin方法。因为在该方法中,我们以这种方式进行编码:
public Admin checkAdminLogin(String userName, String password){
//拼装SQL字符串
String strSQL =”SELECT * FROM TD_ADMIN AS A WHERE A.USERNAME=’”+userName +”’ AND A.PASSWORD=’”+password+”’”;
//后续通过DAO提交该SQL到数据库获得查询结果,省略
这个生成SQL的方式,记得刚接触数据库编程的时候,有很多书籍的范例代码也是这样书写的,咋一看没有什么问题,但是由于没有对可能的输入作一个全面的考虑,所以便产生了注入漏洞。如果有人试图在这里进行恶意攻击,那么他可以在登陆名输入框中输入 123 (其实其他的任意值也可)而在密码输入框中输入 ‘ OR ‘1’=’1
那么由于我们的SQL是靠拼出来的,所以最终提交给数据库的将是:
SELECT * FROM TD_ADMIN AS A WHERE A.USERNAME=’123’ AND A.PASSWORD=’’ OR ‘1’=’1’
很显然,这句SQL由于后面被加上了永真条件,登陆是一定成功的。那么不论登陆者是否是管理员,输入 ‘ OR ‘1’=’1,他都将能够登陆系统。
更有甚者,我可以在输入框中输入数据库的SQL注释符,然后填写我想让数据库执行的操作例如DROP SOMETABLE一类的。所以注入漏洞的危害实际是非常大的。
SQL 注入漏洞的根本原因是,由于我们编码时的不小心,导致用户可以通过输入来改变要执行的逻辑,甚至输入新的逻辑。但是,越是严重和显而易见的代码安全问题,实际要修补却也是越容易的。
2.1.2. 防御办法:
A: 加上验证(或者字符过滤)
在网上搜索关于对SQL注入的防护问题,有很多答案提供的是对输入字符串进行验证/或者是过滤,甚至有人提供了字符串过滤代码。这种方案指出: SQL注入的成因是攻击者在输入框中输入了有特殊意义的字符,如单引号,或者是数据库特定的注释符号,或者是执行分隔符的分号。
那么我们在控制层进行验证,禁止用户输入这些符号,或者将这些符号进行转义是否可以杜绝SQL注入?
表面上看似乎是可以的,因为在控制层中,用户如果试图输入 ‘ OR ‘1’=’1将得到类似”不允许输入单引号”的提示从而系统拒绝了本次执行。
但是,这样的防御方案有非常大的缺陷:
第一:输入验证应该与具体的逻辑挂钩,而不应该与安全防护中的防注入产生过密的依赖。用户名和密码的输入验证和新闻内容的输入验证是不同的。例如,对于新闻的按内容搜索又应该允许输入单引号,因为新闻内容本身是允许包含单引号的。所以输入验证不能从根本上解决问题。一个疏忽带来的结果将是满盘皆输。
第二:提出这种解决方案实际上是没有真正的理解SQL注入,SQL注入的问题并不是出在不合法字符的问题上。这只是表象,SQL注入的真正原因是系统没有办法严格地控制程序逻辑与输入参数之间的分离,系统存在漏洞让系统是用者有地方可以把自己的输入(本应该是参数)变成了程序逻辑的一部分。
B: 控制与参数分离
试想我们给用户提供一个接口,这个接口带一个参数,用户填写这个的这个参数将决定下面的代码执行序列。那么用户可以通过这个接口来命令系统做任何事情。其实SQL注入就是这个原因。
产生这个问题的最根本的原因是,系统应该有能力明确的划分什么是逻辑,什么是参数。
所以解决SQL注入的最根本办法是使用Template模式。
那么用户的输入会作为Business Object的参数存在。但是不管用户输入什么。都无法脱离程序员设置的Templete (逻辑模板)。最后 Templete + Parameters 将决定程序具体的执行。
Java 中对该模式的实现有PreparedStatment或者NamingQuery一类的技术。详细内容可以参见相关文档。由于他们实现了参数与逻辑的分离,所以将从根本上杜绝SQL注入。
使用PreparedStatement还有其他好处,除了安全方面的考虑,由于数据库的编译特性,在性能上也有所提高。
2.2. 脚本注入
2.2.1. 攻击模式
这里所说的脚本,通常所指的是JavaScript脚本,虽然JavaScript运行于客户端,并且有安全沙箱的保护,但是放任恶意JavaScript脚本是十分危险的。
脚本注入也是一种技术含量低的攻击方式。需要攻击者熟悉JavaScript脚本和Dom模型,如果会运用Ajax技术,更是如虎添翼。如果你了解这两项技术,便可以在网上搜索你的目标。
一个网站,如果对输入未做合理的验证或过滤,在显示输出的时候又未做合适的格式化,那么便存在这种漏洞。下面举一个实例:
我们有一个新闻站点。每个新闻允许浏览者进行评论,浏览者提交的评论将被存储在数据据库专门的表中,并且将被显示在新闻的下边。
这个逻辑很正常,没有什么问题。但是很可惜的是开发者除了字符长度没有在后端做任何输入合法验证。那么这个站点的评论输入,必然给坏蛋们有机可乘。
假设我们在评论中输入如下内容:
那么,这句话将被存储在数据库评论表中。以后,每一个浏览者打开这个新闻页面是,都将会弹出这样一个消息框。攻击者很仁慈,没有做过多的破坏。
但是如果输入:
那么打开这个新闻页面,该页面将被从定向到baidu的页面上。
如果目标页面不是baidu.而是一个有恶意代码的页面。那么每个浏览者的机器都可能中毒。
注入上述脚本的攻击者不够聪明或者只是想好心的提示。因为他们注入的东西太容易被人发觉。
我们有别的方式把活干的隐蔽,毕竟开发者和维护人员都不可能对评论一条一条得进行检查。
我们注入:
好文!顶
那么在新闻页面上,将看不到任何异状。但是浏览器其实可能正在悄悄得下载病毒。
WEB2.0的流行使页面效果更加绚丽,同时也使脚本注入的攻击力提高不少。
攻击者在幕后准备了服务器去接受Ajax提交的请求。攻击者通常有自己的服务器(通常是肉鸡),在上面部署了合适的代码。
在目标站点,存在注入点的页面注入如下代码:
我也来顶!