开店乐

开店乐电子商务研究 KaiDianLe.Com

网站地图 :

  搜索:

学习ASP之编写安全的ASP代码

    ASP中数据库的安全是一个很严肃的问题。很多代码的编写者意识到了这类问题,并且小心翼翼地对他们认为有问题的地方做了补救,但常见的情况是要么没有穷尽所有的可疑地点,要么这种补救逻辑上有误。对于一个耐心且嗅觉灵敏的攻击者来说,这种意义上的补救措施和没有任何补救措施没有本质上区别。

下面罗列的是一些可能出现的问题:有些是常见易犯的错误,有些根本就是逻辑上有问题。看看你是不是也这样写过?对于攻击者而言,倒着看这些东西,应该对寻找漏洞有点帮助,更为完整一点的检测方法,请等我的关于黑/白盒分析和自动化测试文章。

一、令人疑惑的过滤方式

典型例子是不管不顾地对所有的输入变量都去掉单引号,或者是把单引号替换成合法的两个单引号,例如:

id = replace(request.querystring("id"), "'", "")

str = replace(request("someinput"), "'", "'")

现在很明了的是,第一个做法很有可能是错误的。因为引起SQL Injection的不总是单引号,再扩大一点,引起问题的不是任何单独的符号,这样子的过滤,有些冤枉单引号了。正确的利用注入,重要的一点是闭合前面的一句SQL查询语句——往往是得先正确地闭合前面一个条件,因为我们可能会在同一句里面引入新的条件,补救措施只要破坏注入条件应该就可以了,但是考虑到其复杂性(下面会说),最好还是较为完整的限制一下输入的字符种类。

第二个看起来是没有什么问题的,但潜在的会带来一些隐患。这很容易给人造成的一个错觉是,我对输入的字符串已经很有效的做过处理了,以后使用没有什么问题。这句话没有错,对字符串来说这样做也是很正确的,但是他扮演了一个不光彩的角色,试想一下,如果过滤后的字符串放进了数据库,而后续的语句有直接拿出来使用的,这种对前面过滤的依赖性,是不是正确的呢?

也许较好的做法应该是,针对具体的情况来确定过滤的准则。

常见的输入变量有三种:数字,字符串还有集合。对于数字型的输入变量,简单调用一下判断函数即可,见得到的代码中,凡是检查了这类变量的,几乎都正确。对于字符串型的来说,基本上在插入到生成的SQL语句时,前后都有单引号,如果仅从破坏注入条件来看,把单引号替换成两个单引号应该问题不大。同理的,如果是一个字符串的集合,也可以简单的用这种方法。而如果是数字的集合,情况可能稍微麻烦一点,至少你得允许数字、逗号或许还有空格之类的符号在输入中正常出现,这样子的过滤规则可能显得复杂,不过你可以借鉴一下dvBBS6.1打过补丁后的版本,总的来说,对于已经发现的过滤漏洞而言,他们还是补得比较好的。

对于第二句话,至少现在不能说它说错的,我们留待后面解决。

二、获取的数据值得信赖吗?

其实这样子说范围显得有点大,一下子涉及到很多方面,一个例子一个例子地举来看好了。

首先是关于选择过滤数据的问题。一直以来,我们认为凡是用户输入的东西,都要经过适当的处理。没错,但真正的是否都做到呢?随便找个抓包的工具,比如 Ethereal,看看在你用IE提交表单或者是打开连接的时候,都提交了什么。或者,简单一些,打开NetAnt编辑一个任务,在协议标签中,看看那个 “自定义提交者”和“用户代理”的选项。

我想你已经明白了,对方可以自己定制的东西不仅仅是GET或POST过来的数据!如果所有的用户都规规矩矩地用浏览器,确实不用防备这么严,如果对方不这么老实,在取服务端变量或Cookie的时候可要小心了,没有任何人能够保证你获得的数据是合法的。对于Cookie而言,很多程序都出过问题,所以以前强调得比较多,至于另外的,关注的人可能比较少一点,但你是否看过或者写过这样的代码:

sql="ShowHOT_COM_inst_online_char 2,"&statuserid&",'"&membername&"','"&memberclass&"','"&Request.ServerVariables("REMOTE_HOST")&"',"&boardid&",'"&Request.ServerVariables("HTTP_USER_AGENT")&"','"&replace(stats,"'","")&"','"&Request.ServerVariables("HTTP_X_FORWARDED_FOR")&"',"&UserGroupID&",'"&actCome&"',"&userhidden&","&userid&""

Request.ServerVariables ("HTTP_USER_AGENT")就是你在NetAnt中看到的用户代理选项,也就是说你可以伪造,同样可以伪造的还有 Request.ServerVariables("HTTP_REFERER"),也就是你在NetAnt中看到的提交者选项等等。在做一些项目的时候,很有可能要将这一类的变量添加入数据库,这时候要千万小心,这个地方的忽略,引起的后果和其他类型变量未过滤导致的后果是一样的。

在Google上搜索Referer和Request.ServerVariables两个关键字,还可以看到很多有问题的写法,或者去看看五月份左右的关于动网论坛入侵的文章,也许你的理解会更加深刻一点。

然后是一个隐藏得稍微深一点的问题,不是用户的直接输入要不要过滤?

这就回到了我们前面留下的那个问题,单引号换成两个单引号的潜在威胁。在第二次构造SQL语句的时候,倘若数据是从数据库里面直接去取出来用的,多数情况下人们会认为前面已经处理过的东西看起来似乎并没有必要再处理,或者干脆就是没有意识到应该处理。这是极其错误的!从两个方面来看,首先你入库的时候对提交数据中的单引号处理,仅仅是保证了单次SQL语句构造的正确性,并没有一劳永逸地解决问题;再说了,后面取出数据用的时候,对数据安全性检查的依赖并没有得到保证,因为这种依赖关系没有传递下来,而且依赖关系本身还不是可传的。

就replace(request("someinput"), "'", "'")而言,它的不安定性在于这种过滤方式只是一种妥协,换句话说只是在有限的范围内掩盖了可能出现的问题,而没有永久性的处理掉。它还有一个讨厌的地方在于给人一种错觉,似乎是处理过的数据已经安全了,容易让后继的代码编写者产生虚幻的安全感。对这两个弱点,不是靠换一个写法就能解决的,因为如果你把单引号干脆去掉,又会引来另外一个问题,输入数据中确实有需要而且正确的单引号怎么办?从一开始我就说,单引号本身是无罪的,过滤它只是一种解决手段而已,所以我们还是就这样写吧,不过要在后继的部分加强一下检查。

这一类的问题,如果依然用动网论坛做例子,我建议看一下六月八号的漏洞文章。

还有就是过滤器的位置,这个掺杂了逻辑问题在内的复杂问题。

我曾经非常惊奇地发现乔客论坛对外散布的版本中一段让人觉得不可思议的问题代码,如果你比较感兴趣的话,翻翻gallery.asp就能看到一个特定的动作序列(action=flash_view),绕过了所有对id的检查。

其实说起来,这一类代码不太可能有太复杂的逻辑结构,对代码进行审查的时候,进行所有的分支覆盖是可以手工完成的,只要稍微想想就会发现对变量的检查是否能够有效地到达你的目的地——生成SQL语句的地方。

关于过滤器的位置,如果要深入下去,马上就会出来一些让人眼花缭乱的东西,中间的分析很麻烦而且很形式化,虽然确实有算法可以保证位置选取的正确性,但是我想这里还是给出一些结论性的东西吧。倘若你很有兴趣,我想你可以来信和我交流。

过滤的位置,取决于两个方面:你获得变量的来源,以及你需要保证到的生成SQL语句的位置。前面一个,不论是来自于直接还是间接输入,先想想可能的输入字符;对于后面一个,你要保证无论程序运行情况怎样,经过了过滤语句的流程一定会经过你需要保证到的生成SQL语句的位置(保证其是有效过滤语句的后向必经节点)。如果你不很清楚流程的判断,我的建议是if中仅仅判断,if嵌套间不要有多余的东西,过滤语句后紧接生成SQL语句。

再回到前面提到的潜在问题,我们终于可以在这里解决了:在取出数据后依然首先进行判断。因为根据前面说的,这一种间接输入依然有可能出现危险。

说到这里,插一句另类的过滤位置问题:不要把对输入的过滤放到客户端解决,那是可以绕过的!谁能保证你的VBScript/javascript能起作用,如果别人直接用NC或者一个不支持脚本的浏览器呢?

上述两个大的方面,以软件测试的目光来认识,显然是没有穷尽所有的分支所导致。在使用对方提交的数据之前,先做一个对方所有可能进入字符的分析列表,然后就每一种输入分支情况进行类型的审核,这是每个代码编写者都应该做的事情。这是一件很简单的事情,因为只是类型上的审核还好,碰上语义的问题就麻烦了……

三、类型正确意味着放行?

涉及到语义的问题,要是可能的话,我选择最好还是避开。

譬如对于一个整型数字,你输入的确实是一个整型,通过了过滤器,潜在的问题是你的输入内容上合法吗,或者根本就不应该从你这里获得信息?很多年前就有人提出来,有些注册的模块存在问题:它里面的id是通过一个type=hidden掩盖后隐式提交的,但是我在第一步建立了用户,第二步仍就有可能通过提交内容不合法的id来修改他人的信息。这种异类的问题都是非常难发现,而且几乎都只有靠经验而不是某一个具体的算法来处理。我们在联系一下前面的,连起来想想或许能够更加清楚,对于输入的字符串,感觉上没有过滤也不会有错,因为比较数字之类集合来说,字符串所能容纳的几乎是全部可能输入的集合。事实上,常见的是没有过滤造成单引号的错误匹配,进而导致了SQL Injection。严格说起来,这也是一个语义上的问题,不过对于这样子的特殊情况而言,可以通过处理输入中的单引号来保证语义的某种程度上的正确。所以我也一再强调,单引号本身是无罪的,不过是背了语义的黑锅而已。

令人遗憾的是,如果是整型数据出了语义上的问题,没有什么东西可以替语义背黑锅了,所以没有了一个一定程度上通用的解决方案。不过也不要悲观,前面就已经说过,能避开就避开,釜底抽薪不要让可能有语义问题的变量作为输入好了。

仅仅考虑数据库安全的话,所有有威胁的语义问题都几乎出在对数据库的操作上,那么,我们只要注意update/insert等语句就可以了,如果考虑数据内容的安全性的话,select也得算上。一般来说,特别关注的是生成的where后面的条件语句,总觉得条件的语义应该是由服务器端决定的,而不是说用户的输入是什么就是什么。我的建议是对于所有的可能出现语义问题的整型变量,最好都是Session,当然,没有进行非常深入的研究,或许有人能够提出像对付字符串的语义问题一样的有效方法也说不一定。不过话又说回来,在语义层面上看对字符串的过滤,不能证明它不安全,但是更重要的没有人能够证明它安全,只是大家现在用着没有问题,也就默认了罢了。

若要深入的分析语义,也会突然冒出一大堆奇怪的东西,所以还是就此打住吧,真切的希望同行之间能够多一些这方面的交流!

前面说的也许更多地会用在一些对既有代码的补救上,如果是从头开始构架一个软件的话,上面的仅仅是设计上一些参考。所有的漏洞都是源于设计上的缺陷,一个好的软件应该被证明其模型是正确的,这很难但是可以做到。如果你一开始就证明了软件的正确性,我想也不会有漏子可以给别人钻了。

【日期:2006-8-7】【作者:不祥】【转载自:开店乐】

相关文章:
 最好的网上开店系统:凡人网络购物系统免费下载
 Rs.open sql,conn,A,B 的A、B各代表什么?
 ASP开发中存储过程应用全接触
 Oracle大文本在ASP中存取问题的解决
 数据分页方法新思路,速度非常快!
 ASP+vbscript写的万能查询表达式生成器
 常用网站数据库SQL操作语句
 ASP程序与SQL存储过程详解
 ASP脚本一空间绑定多个域名代码
 WEB编程开发常用的代码大全
 解决大字段在Form中Post出错的方法
 学习ASP之编写安全的ASP代码
 ASP程序应用之模板采用
 防止别人批量采集功能的ASP代码
 网页图片下拉选择控件使用实例
 平时写程序的时候出错时的解决方法
 “在线访客”的制作方法
 ASP中数据库调用时常见错误的现象和解决
 ASP 编程中20个非常有用的例子
 经典实用的基础asp程序整理
 ASP中从数据库读取二进制文件数据代码
 ASP动态生成的javascript表单验证代码
 在电子商务中实现购物车的方法
 ASP利用Google实现在线翻译功能
 实现千万级数据分页的存储过程
 详细说明用ASP和WML来实现数据库查询
 ASP访问INTERBASE数据库
 ASP安全配置不完全手册
 在ASP中如何访问Novell下的数据库
 ASP进阶学习必经之认识数学函数11种
 初学者必读 ASP运行环境的搭建
 解析asp的脚本语言
 学习使用ASP对象和组件
 让ASP程序运行于非Windows平台
 通过启动脚本来感受ASP的力量
 一些不长见的ASP调用存储过程的技巧
 使用ASP脚本技术
 优化Web数据库页面
 Asp限制IP访问代码
 ACCESS数据库防下载另类方法
 ASP浏览器性能组件
 细说ASP中Counters 组件
 全面解析Server对象
 ASP 内建对象Request和Respones
 深入研究Application和Session对象
 使用ASP、VB和XML建立运行于互联网上的应用程序
 在客户端执行数据库记录的分页显示
 对ASP脚本源代码进行加密
 用代码打开Access文件的两种方法
 使用Visual InterDev进行小组开发
 用JScript脚本实现分页的另类办法
 ASP中Cookie读写的实现方法
 如何使用ASP建立虚拟的FTP服务器
 在ASP中自动创建多级文件夹的函数
 一个硬盘文件搜索的Asp源码
 ASP使用MYSQL数据库全攻略
 ASP上传数据流格式分析详解
 ASP汉字转换UTF-8及UTF-8转换GB2312
 ASP常用数据库连接及操作的方法
 ASP编程中常用SQL命令使用方法
 ASP查询记录时RecordCount=-1问题
 让你的WAP网站有更好的兼容性
 如何注册服务器端组件
 轻松实现任何程序和动易整合
 在服务器端调用winzip命令行对上传的多个文件打包压缩
 用ASP制作强大的搜索引擎
 ASP彩色校验码的制作
 ASP 系列函数大全
 ASP程序处理进程进度条
 Asp无组件生成缩略图
 用ASP实现自动建站.实现虚拟二级目录
 删除Access数词库中的空记录
 ASP身份证验证代码函数
 ASP写的自动生成SELECT表单的函数
 几种打开记录集方式的比较
 用ASP实现汉字转拼音的功能
 ASP分页代码,已经写成类了,值得参考
 ASP下载系统防盗链方法
 Global.asa文件用法大全
 如何防止页面中的敏感信息被提取
 Delphi编写组件封装asp代码的基本步骤
 制做行背景颜色交替变换的表格
 如何用foreach遍历页面上所有的TextBox
 将数据库中的信息存储至XML文件中
 用Asp写个加密和解密的类
 如何固定表格的标题行和标题列
 ASP小偷(远程数据获取)程序入门教程
 Asp编写不再让人讨厌的自动弹出窗口
 用ASP实现在线压缩与解压缩
 使用组件封装ASP的数据库操作
 ASP中读写注册表
 ASP判断函数一览及网页制作常用技术
 ASP中Cookie使用指南
 随机产生用户密码(good)
 ASP:如何对身份证的籍贯进行验证
 ASP产生随机密码的函数
 ASP+ADO实现数据读写简单示例
 一个简单的用户登录接口ASP实现
 ASP+SQL Server构建网页防火墙
 一个通用的保护ASP系统的方法
 利用ASP发送和接收XML数据的处理方法

版权所有:Kaidianle.Com  联系方式:Shnxn@Yhaoo.Com.Cn 京ICP备06028743号 在线留言