
 
 | 
| 技术资料  > ASP技术 > 数据库相关 : 安全脚本程序的编写 V1.0 |  
安全脚本程序的编写 V1.0 March 25,2004 |  
by Casper--------安全焦点 
[email protected] 
http://www.xfocus.org 
 
基本思路: 
    为没一个功能写一个独立的程序,程序页 
    尽可能少的让客户了解你的服务器端信息 
    不要用"客户应该这么写"这个思路想问题 
    尽可能多的想到不可能发生的事情 
     
1.关于交互式动态网页可能存在的问题 
1.1    form类型的交互 
1.1.1 概念介绍 
在我们和浏览者进行交互时,最常用到的就是form(post/get/put方法),虽然非常方便,但是很多问题也是因他而起。form表单中input标志 
用来接受用户输入的信息,例如:用户名、密码、email等。如果你没有对用户输入进行很好的检查的话,一个恶意的用户会屏蔽掉一些安全机 
制,绕过安全认证。例如,输入标准的HTML语句或者javascript语句会改变输出结果 ,在输入框中打入标准的HTML语句会得到什么样的结果呢?比如一个留言本,我们留言内容中打入:<font size=10>你好!</font>  如果你的程序中没有屏蔽html语句,那么就会改变"你好"字体的 
大小。在留言本中改变字体大小和贴图有时并不是什么坏事,反而可以使留言本生动。但是如果在输入框中写个 javascript 的死循环,比如: 
<a herf="http://someurl" onMouseover="while(1) {window.close('/')}">第一万个惊心动魄</a> 那么其他查看该留言的客人只要移 
动鼠标到"第一万个惊心动魄",上就会使用户的浏览器因死循环而死掉。 
1.1.2 防范要点 
(1)对特殊字符进行过滤 
([&;`'\|"*?~<>^()[]{}$nr])/\$1/g;),这个是最基本的,在很多地方也已经不只一次提到过 
<script language="vbscript"> 
sub uBotton_onclick 
if form1.uUserName.value=""then 
msgbox"您的姓名不能为空!",0+32,"哦!还不行" 
form1.uUserName.focus 
exit sub 
end if 
 
if form1.uPassword.value=""then 
msgbox"您的密码不能为空!",0+32,"哦!还不行" 
form1.uPassword.focus 
exit sub 
end if 
 
if form1.uUserName.value=""then 
msgbox"您的姓名不能为空!",0+32,"哦!还不行" 
form1.uUserName.focus 
exit sub 
end if 
form1.submit 
end sub 
</script> 
 
 
function isEmpty(objname) 
{ 
    var str = document.inputform[objname].value 
    var tmpstr = str.replace([&;`'\|"*?~<>^()[]{}$nr])/\$1/g;,"") 
    var tmpstr = tmpstr.replace([&;`'\|"*?~<>^()[]{}$nr])/\$1/g;,"") 
    return (tmpstr.length==0) 
} 
 
function check() 
{ 
    tf=document.inputform 
    errors="" 
    if (isEmpty("username")) errors += "用户名不能为空。n"; 
    if (isEmpty("password")) errors += "密码不能为空!n" 
    if (errors!="") 
        alert(errors); 
    return (errors=="") 
}     
(2) 对输入的字符长度进行限制 
(3) 进行尽可能多的错误出理和错误陷阱 
(4) 尽可能多的使用以下这些标志,减少用户输入的机会 
  <input type="checkbox" name="checkbox" value="checkbox"> 
  <select name="select">  </select> 
  <input type="radio" name="radiobutton" value="radiobutton"> 
 
   
1.2    post/get类型的交互 
 
1.2.1 概念介绍 
这种类型的问题主要是浏览者可以通过浏览器的地址栏对脚本页通过添加参数来和服务器进行交互,这些参数已经绕过放在客户端提交页的输入检 
查了,还有就是可以通过地址栏输入较长的参数或恶意编造的代码造成服务器异常运算错误,导致服务器宕机或缓冲区溢出。 
 
1.2.2 防范要点 
(1) 尽量不要让浏览者了解到你的运算提交页 
(2) 不允许地址栏提交参数 
例如ASP程序中的request.serverVariables(QUERY_STRING)检测是否有参数,如果有则使用response.redirect()强制返回指定页,可以 
是首页,或者你自己做的警告页。 
(3) 脚本页间传递参数不要再浏览器栏显示,尽可能少的让浏览者了解你的程序规则、参数等 
例如ASP中的Request.form和Request.QueryString这两个数据集合分别使用的是post和get方法,我们尽量不要是用Request.QueryString这个数据集合,尽可能少的让浏览者有和你交互的机会, 
 
2.     安全认证的问题 
2.1    需要安全认证密码认证的可能存在的问题 
2.1.1 概念介绍 
现在流行的CGI应用程序倾向于收集信用卡信息。数据收集是CGI 应用程序的一个简单的任务,但是敏感信息的 
收集需要一个将信息从浏览器传送给服务器和CGI程序的安全途径。 
 
  举个例子,假设我要通过Internet来销售书。我可能在浏览器上建立一个表单,允许要购书的顾客通过表单提交它的个人信息和信用卡号码。受 
  到这些信息后,我会将它们存储到我的计算机作为商业记录。 
 
  如果有人侵入我的商业计算机,那么他可能会访问存放顾客信息和信用卡号码的机密数据。为了避免这种情况,我会审查我的计算机配置安全了 
  ,并确定用来接受表单的CGI脚本不会被恶意的操纵。换句话说,我,作为计算机的系统管理员和CGI程序员,要尽力控制住第一个问题:防止 
  信息直接从我的计算机中被窃取。 
 
  然而,怎样防止当信息由客户端发往服务器过程中有人中途窃取呢?记住信息怎样由Web服务器传送到CGI程序了吗?信息通过网络由浏览器先 
  传送到服务器,然后服务器将信息传送给CGI程序。这些信息可能在由客户机传送到服务器时被中途窃取(如图2)。注意,为了保护信息使其不会 
  被中途窃取,必须在客户和服务器之间进行加密。当然,如果你的客户机不能识别的话,你不能执行特定CGI的加密。 
 
  由于Web处理的特点,使用你独有的单独通过CGI程序实现的安全处理协议的唯一途径是:在表单信息通过浏览器传送到服务器之前将其加密。 
  这个方案如。 
 
  之前,发展你自己的安全处理协议几乎是不可能的。感谢Java这样的语言,最近在客户端处理所作的创新,使得这个发展变成可能。  方法是产生 
  一个标准HTML格式扩展的Java接口。当Java的提交按钮被选择时,Java Applet会在利用标准的POST HTTP请求将它发送到Web服务器前先 
  将值加密。 
 
  使用Java作为客户机来发送和接收加密的数据将允许你使用自己定制的加密方案,而不需要一个昂贵的商业服务器。 
   
 
  因此,在网络上安全保密地传送数据信息需要调整浏览器和服务器之间的通信路径,有一些是不能仅仅靠CGI就能够控制的。目前有两种加密客 
  户机/服务器信息处理的建议:SSL(Secure Sockets Layer)和SHTTP(Secure HTTP),分别由Netscape和EIT(Enterprise Integrations  
  Technology)提议。关于这点,目前还不清楚哪一个将成为标准;很多公司在他们的服务器中两种都采用了。因此,知道如何在这两者中编写 
  CGI程序是很有用的。 
 
SSL是一个协议独立的加密方案,在网络信息包的应用层和传输层之间提供了安全的通道(参照图5)。简单说来,就是HTML或CGI经过了幕后的 
服务器进行了加密处理,然而对HTML和CGI的作者来说是透明的。 
 
因为客户端和服务器端网络程序处理加密过程,几乎你的所有的CGI脚本不需要进行安全事务的修正。有一个显著的例外。一个nph(no-parse- 
header)的CGI程序绕过服务器而直接与客户端进行通信。因此,nph的CGI脚本不会经过加密处理,因为信息未得到加密。受此影响的一个值得 
注意的CGI应用程序是Netscape服务器推动的动态实现(Netscape server-push animations)。我怀疑这是主要应该值得注意的,然而,更 
有可能因为要安全的传输敏感信息而牺牲页面中的动画。 
 
  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 
 
 
2.1.3 脚本解析 
 
下面是我以前写的一段asp脚本,做了一些修改,把他贴出来,让大家看看我加入了设置,那里做的不够好。我在这里就不多说了,有兴趣可以到 
我的论坛来大家讨论。 
 
<!--#include file="conn.asp"--> 
<% 
dim errmsg 
if request.form("username")="" then 
ErrMsg="用户名不能为空" 
foundError=True 
else 
UserName=request.form("UserName") 
end if 
 
if request.form("password")="" then 
    ErrMsg="密码不能为空" 
    foundError=True 
else 
    PassWord=request.form("PassWord") 
end if 
if FoundError=true then 
    showAnnounce(ErrMsg) 
else 
    set rstmp=server.createobject("adodb.recordset") 
    if Request.ServerVariables("REQUEST_METHOD") = "POST" then 
        rstmp.open "Select * from User Where userName='" & UserName & "'",conn,3,3 
        if rstmp.bof then 
            session.contents("UserName")=UserName 
            rstmp.addnew 
            rstmp("username")=username 
            rstmp("userpassword")=password 
            rstmp("logins")=1 
            rstmp("online")=1 
            rstmp.update 
            response.redirect("index.asp") 
        elseif PassWord<>rstmp("userpassword") then 
                ErrMsg="密码错啦" 
                foundError=True 
                showAnnounce(ErrMsg) 
            else 
                session.contents("UserName")=UserName 
                rstmp("logins")=rstmp("logins")+1 
                rstmp("online")=1 
                rstmp.update 
                rstmp.close 
                Set rstmp=nothing 
                response.redirect("index.asp") 
            end if 
 
    else 
        if session.contents("UserName")<>"" then 
            rstmp.open "Select * from User Where userName='"&session.contents("UserName")&"'",conn,3,3 
            rstmp("logins")=rstmp("logins")+1 
            rstmp("online")=1 
            rstmp.update 
            rstmp.close 
            Set rstmp=nothing 
            conn.close 
            set conn=nothing 
            response.redirect("index.asp") 
        end if 
    end if 
end if 
%> 
<html> 
 
<head> 
<title></title> 
<link rel="stylesheet" type="text/css" href="forum.css"> 
</head> 
 
<body> 
<% 
function showAnnounce(ErrMsg) 
on error resume next 
response.write "<p align=center><font color='red'><strong><Big>哈哈</big></strong></font><BR><font color='#0000FF'>"+ErrMsg+"</font><BR>"+chr(13)+chr(10) 
%> 
<tr>  
<td width="100%">  
<p align="center"><br>  
<form action="login.asp" method="post">  
输入<INPUT name=username size=8 class='smallInput'>  
<BR>哈哈<INPUT name=password size=8 class='smallInput' type=password> 
</td>  
</tr>  
<tr>  
<td width="100%">  
<p align="center"><br>  
<INPUT type="submit" name="B12" class='buttonface' value=μ???> 
<font color="#FF0000"><br> <br>  
*</font>错了 
</td> </form>  
</tr>  
<% 
end function 
%>  
 
###---checklogin.asp 
<% 
dim adname 
dim passwd 
 
adname=Request.Form("adname") 
passwd=Request.Form("passwd") 
 
if adname="" then 
  response.redirect "login.asp" 
end if 
if passwd="" then 
      response.redirect "login.asp" 
end if 
 
if adname="focus-admin"  and passwd="1" then  
    response.redirect "manage.asp" 
  else 
     response.redirect "login.asp" 
end if 
%> 
###---checklogin.asp----end 
###---manage.asp 
<% 
 
dim where 
dim where1 
dim refererURL 
dim refererURL2 
dim refererURL3 
refererURL=phyURL&"login.as" 
refererURL2=phyURL&"edit.asp" 
refererURL3=phyURL&"manage.a" 
refererURL4=phyURL&"savearti" 
where=Request.ServerVariables("HTTP_REFERER") 
where=left(where,(len(phyURL)+8))     
if where<>refererURL and where<> refererURL2 and where<>refererURL3 and where<>refererURL4 then 
            Response.Redirect "login.asp" 
    end if 
 
   const MaxPerPage=20  
   dim totalPut    
   dim CurrentPage 
   dim TotalPages 
   dim i,j 
 
   if not isempty(request("page")) then 
      currentPage=cint(request("page")) 
   else 
      currentPage=1 
   end if 
    
%> 
###---manage.asp-----end |  
 
 | 
  
Copyright © 2001-2008 Shenzhen Hiblue Software Team All rights reserved