如果测试网络应用程序的安全问题就像写文章那样简单,那么世界会变得多么美好。最近,有人要求我给出一个网络应用程序常见安全错误的清单。这项工作很简单,下面是我常见到的“陷阱(gotchas)”:
下面是前五个常见错误的简要介绍:
“信任,但也要验证(Trust but verify)”是我最喜欢的座右铭之一。网络应用程序设计师和程序员应该很好的实践这句座右铭。尽管cookie和URL参数大大简化了开发者的工作,但我们不应该忘记验证它们所传递数据的有效性。
许多网络商务平台从臭名昭著的“购物车漏洞(shopping cart vulnerability)”学会了这个,网上小偷可以通过这个漏洞来修改购物车中的商品价格。而购物车本身不过是一个基于文本的cookie而已。服务器在检验之后,会合计保存在cookie中的条目价格。设想一下:客户完全控制了价格,这种情况会有多可怕。更糟糕的是,服务器没有验证数据的手段。我敢肯定,许多网络商务经历了更严重的冲击。
检查这个问题的最好方法就是清除所有的cookie,运行应用程序,并看看写到磁盘中的cookie。我总是看看cookie的内容,这样可以避免敏感的信息(例如任务(role)甚至用户id和口令)没有保存到cookie中。
我曾经看到过这样一个系统,它通过URL传递的参数来进行程序控制。当我查看它的源代码后,我注意到了一个普通线程,系统级的命令用如下形式嵌入到URL中:“action=’do something’”。
在测试过程中,我编写了一对自定义URL来看看系统是如何处理它们的。不出所料,通过我在URL中嵌入的命令(“action=’cat xxx>>/etc/passwd’”)我获得了系统的控制权。
概括的说:如果你通过URL栏来传递参数,那么你至少应当解析它的无效内容和恶意内容。你最好对URL参数设置约束,这样当传递来的参数值在意料之外时,你的程序依然可以处理它。测试你的程序是否存在这个问题也很容易——修改URL栏中的地址,然后看看你的应用程序是如何处理这个数据的。
在测试网络应用程序的过程中,我经常会发现不验证输入数据有效性的字段,它们简直就是缓冲区溢出和SQL injection攻击者的金矿。测试时,我会打开记事本并创建一个长度超过500的字符串,然后把它剪切拷贝到口令输入框中。如果系统没有限制输入字符串的长度,那么它往往会挂起或者崩溃。
然后我将测试验证规则,我会把一个总是等于“真”(例如“OR ‘x’=’x’”)的条件语句附加到口令输入框中。由于通过这种方法,SQL语句已经建立,因此许多系统都会被操控,从而允许未授权的访问——许多系统都会被这种“OR TRUE”语句所欺骗。下面是可以用来控制系统的SQL语句的例子:
Select userid, passwd from USERS where userid = :uid_entered and passwd = pwd_entered
假设用户在useid字段中键入“admin”,在口令栏中键入“OR ‘x’=’x’”,那么这个SQL语句就会解释为“select userid,
passwd from USERS where userid=admin
and passwd=password OR 'x'='x'”,设计者可能会没有预料到这种情况的出现。
另一个常见的错误就是把系统帐号作为应用程序数据库的预验证帐号,我常常对这中错误出现的频率之高感到吃惊。许多网络应用程序把用户凭证(也就是用户名和口令)保存到自己的数据库中。在验证用户凭证的有效性之前,你必须登录到数据库,因此,系统一般用一种我称之为“预验证登录帐号”的方法来处理验证;例如,当以“admin/admin”登录系统时,就会验证屏幕输入与数据库中保存的用户名和口令是否相匹配。
值得注意的是,我发现每个预验证登录帐号总是管理员类型的帐号,这些帐号具有最大权限。使得情况更具有风险性的是:为了让网络应用程序可以访问帐号和口令,数据库一般保存到Webroot目录中或者起始页(start page)下的目录中。无论是上述两种情况下的哪一种,恶意用户都能很容易获得口令。这种情况非常像把房门钥匙藏在欢迎毯下,或者把备用的车钥匙放在汽车的遮阳板上。这个错误很严重,它的存在有利于恶意用户闯入网络程序。