安全脚本程序的编写 V1.0
类别: ASP教程
基本思路:
为没一个功能写一个独立的程序,程序页
尽可能少的让客户了解你的服务器端信息
不要用"客户应该这么写"这个思路想问题
尽可能多的想到不可能发生的事情
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
2.2 cookie的问题
2.2.1 概念介绍
按照Netscape官方文档中的定义,Cookie是在HTTP协议下,服务器或脚本可以维护客户工作站上信息的一种方式。Cookie是由Web服务器保存在用户浏览器上的小广西文件,它可以包含有关用户的信息(如身份识别号码、密码、用户在Web站点购物的方式或用户访问该站点的次数)。无论何时用户链接到服务器,Web站点都可以访问Cookie信息。
通俗地讲,浏览器用一个或多个限定的文件来支持Cookie。这些文件在使用Windows操作系统的机器上叫做Cookie文件,在Macintosh机器上叫做magic Cookie 文件,这些文件被网站用来在上面存储Cookie数据。网站可以在这些Cookie文件中插入信息,这样对有些网络用户就有些副作用。有些用户认为这造成了对个人隐私的侵犯,更糟的是,有些人认为Cookie是对个人空间的侵占,而且会对用户的计算机带来安全性的危害。
目前有些Cookie是临时的,另一些则是持续的。临时的Cookie只在浏览器上保存一段规定的时间,一旦超过规定的时间该Cookie就会被系统清除。例如在PHP中Cookie被用来跟踪用户进程直到用户离开网站。持续的Cookie则保存在用户的Cookie文件中,下一次用户返回时,仍然可以对它进行调用。
要了解Cookie,必不可少地要知道它的工作原理。一般来说,Cookie通过HTTP Headers从服务器端返回到浏览器上。首先,服务器端在响应中利用Set-Cookie header来创建一个Cookie,然后,浏览器在它的请求中通过Cookie header包含这个已经创建的Cookie,并且反它返回至服务器,从而完成浏览器的论证。 例如,我们创建了一个名字为login的Cookie来包含访问者的信息,创建Cookie时,服务器端的Header如下面所示,这里假设访问者的注册名是"Michael Jordan",同时还对所创建的Cookie的属性如path、domain、expires等进
行了指定。
Set-Cookie:login=Michael Jordan;path=/;domain=msn.com;
expires=Monday,01-Mar-99 00:00:01 GMT
上面这个Header会自动在浏览器端计算机的Cookie文件中添加一条记录。浏览器将变量名为"login"的Cookie赋值为"Michael Jordon"。注意,在实际传递过程中这个Cookie的值是经过了URLEncode方法的URL编码操作的。
这个含有Cookie值的HTTP Header被保存到浏览器的Cookie文件后,Header就通知浏览器将Cookie通过请求以忽略路径的方式返回到服务器,完成浏览器的认证操作。
此外,我们使用了Cookie的一些属性来限定该Cookie的使用。例如Domain属性能够在浏览器端对Cookie发送进行限定,具体到上面的例子,该Cookie只能传达室到指定的服务器上,而决不会跑到其他的如www.hp.com的Web站点上去。Expires属性则指定了该Cookie保存的时间期限,例如上面的Cookie在浏览器上只保存到1999年3月1日1秒。当然,如果浏览器上Cookie太多,超过了系统所允许的范
围,浏览器将自动对它进行删除。至于属性Path,用来指定Cookie将被发送到服务器的哪一个目录路径下。
说明:浏览器创建了一个Cookie后,对于每一个针对该网站的请求,都会在Header中带着这个Cookie;不过,对于其他网站的请求Cookie是绝对不会跟着发送的。而且浏览器会这样一直发送,直到Cookie过期为止。
2.2.2 要点方法
setcookie-----送出 Cookie 信息到浏览器。
语法: int setcookie(string name, string value, int expire, string path, string domain, int secure);
返回值: 整数
本函数会跟着标识 Header 送出一段小信息字符串到浏览器。使用本函数要在送出 HTML 数据前,实际上 cookie 也算标识的一部份。本函数的参数除了第一个 name 之外,都是可以省略的。参数 name 表示 cookie 的名称;value 表示这个 cookie 的值,这个参数为空字符串则表示取消浏览器中该 cookie 的数据;expire 表示该 cookie 的有效时间;path 为该 cookie 的相关路径;domain 表示 cookie 的网站;secure 则需在 https 的安全传输时才有效。想得到更多的 cookie 信息可以到
http://www.netscape.com/newsref/std/cookie_spec.html,由
cookie 原创者 Netscape 所提供的完整信息。
对于一个网站会员而言,经常存在需要一次注册,多次认证的问题,例如我们经常接触到的论坛、社区等,一般采用手段为cookie或 input type=hidden来传递认证参数。这里面有几点隐患:
I. setcookie内容必须完整包含帐号密码,或类似的完整安全信息,如果只携带帐号信息或用某种权限标志来认证,极容易造成非法入侵。
例如某站点中的会员更新页面中携带的认证信息是两个,用户名和Uid(均为明文传送)已知Uid对于每个会员是唯一的。由于我们只需要知道对方的帐号和Uid就可以更改对方信息(不需要知道密码!),只要攻击者知道Uid(攻击者可以通过暴力猜测的方法来得到Uid,有时候站点本身也会泄露用户的Uid,例如在论坛等处)那么,攻击者就可以通过遍历攻击完成对任意一个帐号的信息更改。
II. 必须所有需要权限操作的页面都必须执行认证判断的操作。如果任何一页没有进行这种认证判断,都有可能给攻击者以恶意入侵的机会。
III. 很多网站为了方便,将用户名以及口令信息储存在Cookie中,有的甚至以明文方式保存口令。如果攻击者可以访问到用户的主机,就可能通过保存的Cookie文件得到用户名和口令。
3. 脚本保护的问题
3.1 概念介绍
在程序编写时优秀的程序员都会知道,用有意义的变量名,文件名有助于增加程序的可读性,具有良好的程序风格。这个非常好但在脚本语言不太适合,为了不让恶意用户猜到你的变量或数据库名等信息,必须改掉这些信息。动态的网页在服务器端执行后返回给客户的是执行后的代码,这可以保护服务器端的很多不想叫或不能叫浏览者知道的信息。安全是相对的,每天都在有新的安全漏洞被发现,如果恶意的用户在你之前知道了一个可以看你的脚本源代码的漏洞或这个漏洞一时间无法修补怎么办?
3.2 主意要点
建议用一些比较怪异的名字命名,删掉脚本中的注释。如果还需要保持程序的可读性的话,可以建立一个映射,你可以写个具有良好风格的脚本程序,然后再做一个变量名映射建立一个具有较安全命名方法的脚本,去掉这个脚本中的注视和所有能去掉的信息,修改时作个同步就可以了我们可以在程序的使用前对程序进行加密,以保护我们自己的程序再万一的情况下部被泄漏。
3.3 保护方法
我看到过很多的对脚本的加密方法,都很不错,有的是专门的加密软件,有的是通过一些技巧加上利用语言的特性进行加密的,例如随机生成一个密匙,把密匙放在"不可见的"地方,通过一些算法对脚本进行加解密,就是由于某些系统漏洞导致你的脚本源代码泄漏,也无济于事。
4 .实例说明
下面这个例子是在网上经常被提到的,这是个非常经典的例子,所以在这里通过这个实例告诉大家可能存在的危险。问题描述:
大部分网站把密码放到数据库中,在登陆验证中用以下sql,(以asp为例)
sql="select * from user where username=\'"&username&"\'and pass=\'"& pass &\'"
此时,您只要根据sql构造一个特殊的用户名和密码,如:ben\' or \'1\'=\'1
就可以进入本来你没有特权的页面。再来看看上面那个语句吧:
sql="select * from user where username=\'"&username&"\'and pass=\'"& pass&\'"
此时,您只要根据sql构造一个特殊的用户名和密码,如:ben\' or \'1\'=\'1 这样,程序将会变成这样:
sql="select*from username where
username="&ben\'or\'1\'=1&"and pass="&pass&" or 是一个逻辑运算符,作用是在判断两个条件的时候,只要其中一个条件成立,那么等式将会成立.而在语言中,是以1来代表真的(成立).那么在这行语句中,原语句的"and"验证将不再继续,而因为"1=1"和"or"令语句返回为真值.。
另外我们也可以构造以下的用户名:
username=\'aa\' or username<>\'aa\'
pass=\'aa\' or pass<>\'aa\'
相应的在浏览器端的用户名框内写入:aa\' or username<>\'aa 口令框内写入:aa\' or pass<>\'aa,注意这两个字符串
两头是没有\'的。这
样就可以成功的骗过系统而进入。
具体实施是这样的,首先我会到注册的地方去收集信息,了解尽可能多的信息,例如目标数据库中都有用户的什么样的信息,随便的填写信息然后提交,当你要注册的用户名被注册的是有系统会提示你已被注册,有的网站做的更好的,就是他们专门给你设置的检测是否有已经被注册的功能,通过这样就会非常容易的找到目标--那个提示已被注册的用户,让后你在这个注册页里填写一些特殊的字符,如\',/,,等字符看系统如何提示,以证明程序员是否注意到了应该过滤字符或懂得是否应该过滤那些字符,在这页进行尝试是因为有的网站在登录的时候他会记录你的ip地址,当然你也可以找一个比你直接登录要快的代理服务器来做跳板。后面你要做的就是察看登录页的html源代码,看看是否有在客户端的字符过滤,看看这个程序员是用什么风格来编写程序,尽可能多的了解程序编写风格,这对你以后的某些判断有好处。如果有在客户端的过滤也不怕,你要搞清是什么样的过滤,能不能对攻击造成威胁,不要一看有过滤就害怕,可以尝试着用别的方法绕,就是使用自己精心打造的独立脚本,进行攻击。然后你要看看form的action中的url是否可以直接提交,在浏览器地址栏里直接提交,看看返回什么,是否有来路检测。还有很多细小的地方,你也应该可以注意到,例如那些地方程序员的整体的编写风格是什么,变量名定义的风格是什么等等,这个会帮我们"猜"到很多东西。还有别的其他什么,我也记不太清楚了,临场发挥吧。通过这些了解我们有如下几种可能:
1.那个程序员非常善良相信全世界都是好人,什么都没做,根本没有任何检测机制,我们直接用username=\'aa\' or
username<>\'aa\',
pass=\'aa\' or pass<>\'aa\'就可以搞定,现在这么善良的人少啦,可是你要是有耐心,找到这种人还是不难的。
2.这个程序员可能听别人提起过一些安全问题,毕竟现在这个那里都有人说,很多书中都有提及,但是做得不够好,他只进行了简单的输入过滤。
过滤有两种方式,一种是在客户端的过滤,一种是在服务器端的过滤。现在很多的程序员考虑到再服务器端进行过滤可能给服务器造成更多的负荷,会把检测过程放在客户端。如果他在服务器端没做任何事情,那么还是可以对其进行攻击的,我可以将这个登录页的源代码COPY下来,然后自己建立一个文件把这些代码PASTE进去,再对这个文件进行进一步的深加工,去掉原来页的过滤机制,或者直接将攻击代码写到这个文件中去,然后将form中的action中的地址改成绝对地址,也就是将文件名改成"http://www.target.com/targer.php"这样,然后就可
以提交啦。但是如
果服务器端加上了"来路检测",你就白玩了。如果这样还是不行,我再换一种方法,在浏览器的地址栏里用?来输入参数,就好像
"http://www.targer.com/targer.php?username=\'aa\' or username<>\'aa\'&pass=\'aa\' or pass<>\'aa\' "然后敲回车吧,其
实应该先
尝试这种方法因为这用方法更简单,防护起来也很简单,这种提交方式不是post 而是get ,只要服务器端程序检测你的提交方法,就可以kill掉这
个阴谋。如果单纯的只检测了"来路",还是不太安全的,可以先正确的提交一次,在提交过程中马上停止,就是保存这个环境,然后再构造请求。
(我做过几次试验得到的结果都不太一样,应该是和终止的时机有关,欢迎大家来交流)。
3.一个很出色的程序员,安全意识非常高,他在服务器端做了如下检测:检测提交的方法;检测提交的"来路";检测提交内容的长度;全面检测提交内容,这样我们就很难通过上面的方法对其进行攻击,那到保密的资料就已经不太可能了(如果各位还有什么好的办法,请一定来信告诉小弟,小弟在这里先谢了)。但是我还想说的是攻击并不代表是非要入侵进去,拿到某些东西才叫入侵,对你的机器进行破坏也叫入侵啊,例如提交一些错误的请求,脚本解释程序就会非常规矩的给你返回错误信息,最浅显的后果就是暴露物理路经,有的时候一些特殊的请求会使web服务宕掉,这些个我认为绝对是属于攻击,绝对是危害,也许你认为暴露物理路径没有什么,是在单独看来没有什么,但要是在一个有计划的攻击里,这个就会发挥很多作用,那时你可能还会莫名为什么他们找到了我的文件呢。也许有人认为这个是脚本解释程序的bug,也许有的是,但是返回错误信息绝对不是脚本解释程序的错误,这个是每个解释程序都要做到的,在我看来这个应该是还是程序员的问题,程序员没有做好对错误的处理。每一本教你如何编写程序的书籍里基本都会有错误处理之类的章节,并且每种语言基本都有错误处理函数和方法,只不过你没有想到罢了。至于究竟要怎么处理那就要看你对cgi程序安全的熟悉程度了,那就要看你对这种脚本语言的特性熟悉多少了,说到底就是经验,唯一的办法就是多看多写多想多交流。
4.非常优秀的程序员,以上那些做的都非常好(也许就是你啊,毕竟不难嘛,加上很少的代码就可以了),怎么办??怎么办?!怎么办!!在一旁偷偷的佩服吧!哈哈。
5. 其它注意事项:思路和方法
指导思想:
I.严格控制程序与用户交互的途径
II.严格控制程序与用户交互的内容
III.尽可能好的保护我们控制
基本思路:
I.为没一个功能写一个独立的程序,程序页
II.尽可能少的让客户了解你的服务器端信息
III.不要用"客户应该这么写"这个思路想问题
IV.尽可能多的想到不可能发生的事情
基本方法:
尽可能多的控制交互:
I.检测提交的方法,就是控制他的post还是get;
II.检测提交的"来路",就是检测一个环境变量HTTP_REFERER;
III.检测提交内容的长度;
IV全面检测提交内容;
积极-消极防护:
I.尽可能多的错误处理,例如当检测到了不正确的输入时,应该怎么做,是强制返回,还是发出警告;
II.充分发挥日志功用,例如在你检测到了不正确的提交时,就记录下客户端的信息,例如IP,系统配置,请求等等,毕竟现在是技术飞跃的时代,不能保证可以想到每一种可能,这也是我在这篇文章里不止一次提到"尽可能"这个词的原因。充分的日志记录不全是为了抓住入侵者(如果入侵者使用了跳板,记录了IP也是没有用的),更重要的是为了能发现问题的所在,找到问题,改正问题,亡羊补牢,这个才是最重要的。
III.充分发挥你的想象力,用一种入侵者的思想考虑问题,用一种另类的思想考虑问题,尽可能想到不可能发生的事,把问题扼杀在萌芽里。
我们xundi哥说的好:掌握方法!!!现在脚本语言层出不穷,asp,perl,php,jsp等等,基本不可能精通每一种,(也许你厉害,都能精通,我比较呆,会一个就不错啦),但是要是掌握了方法就不同了啊,各位网络的精英举一反三触类旁通,肯定是优秀的不得了。我写脚本一共也没多少天,写这个东西我知道肯定是班门弄斧了,错误之处还请各位大虾抱着挽救和帮助的精神,告知小弟(方式、方法、态度不限),小弟我在这里先谢了。写这个东西,我只是想说说小弟的一些小的心得,与大家共勉,我想告诉大家的就是"领会精神",嘿嘿,"领会精神"。大家要是有什么好的方法,希望不要保留,充分发挥网络的自用共享,拿出来,大家交流交流,不胜感激。袭来的,这种东西小弟不敢自己写(嘿嘿,实际还有不少懒的成分,哈哈),希望大家不要见怪。
为没一个功能写一个独立的程序,程序页
尽可能少的让客户了解你的服务器端信息
不要用"客户应该这么写"这个思路想问题
尽可能多的想到不可能发生的事情
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
2.2 cookie的问题
2.2.1 概念介绍
按照Netscape官方文档中的定义,Cookie是在HTTP协议下,服务器或脚本可以维护客户工作站上信息的一种方式。Cookie是由Web服务器保存在用户浏览器上的小广西文件,它可以包含有关用户的信息(如身份识别号码、密码、用户在Web站点购物的方式或用户访问该站点的次数)。无论何时用户链接到服务器,Web站点都可以访问Cookie信息。
通俗地讲,浏览器用一个或多个限定的文件来支持Cookie。这些文件在使用Windows操作系统的机器上叫做Cookie文件,在Macintosh机器上叫做magic Cookie 文件,这些文件被网站用来在上面存储Cookie数据。网站可以在这些Cookie文件中插入信息,这样对有些网络用户就有些副作用。有些用户认为这造成了对个人隐私的侵犯,更糟的是,有些人认为Cookie是对个人空间的侵占,而且会对用户的计算机带来安全性的危害。
目前有些Cookie是临时的,另一些则是持续的。临时的Cookie只在浏览器上保存一段规定的时间,一旦超过规定的时间该Cookie就会被系统清除。例如在PHP中Cookie被用来跟踪用户进程直到用户离开网站。持续的Cookie则保存在用户的Cookie文件中,下一次用户返回时,仍然可以对它进行调用。
要了解Cookie,必不可少地要知道它的工作原理。一般来说,Cookie通过HTTP Headers从服务器端返回到浏览器上。首先,服务器端在响应中利用Set-Cookie header来创建一个Cookie,然后,浏览器在它的请求中通过Cookie header包含这个已经创建的Cookie,并且反它返回至服务器,从而完成浏览器的论证。 例如,我们创建了一个名字为login的Cookie来包含访问者的信息,创建Cookie时,服务器端的Header如下面所示,这里假设访问者的注册名是"Michael Jordan",同时还对所创建的Cookie的属性如path、domain、expires等进
行了指定。
Set-Cookie:login=Michael Jordan;path=/;domain=msn.com;
expires=Monday,01-Mar-99 00:00:01 GMT
上面这个Header会自动在浏览器端计算机的Cookie文件中添加一条记录。浏览器将变量名为"login"的Cookie赋值为"Michael Jordon"。注意,在实际传递过程中这个Cookie的值是经过了URLEncode方法的URL编码操作的。
这个含有Cookie值的HTTP Header被保存到浏览器的Cookie文件后,Header就通知浏览器将Cookie通过请求以忽略路径的方式返回到服务器,完成浏览器的认证操作。
此外,我们使用了Cookie的一些属性来限定该Cookie的使用。例如Domain属性能够在浏览器端对Cookie发送进行限定,具体到上面的例子,该Cookie只能传达室到指定的服务器上,而决不会跑到其他的如www.hp.com的Web站点上去。Expires属性则指定了该Cookie保存的时间期限,例如上面的Cookie在浏览器上只保存到1999年3月1日1秒。当然,如果浏览器上Cookie太多,超过了系统所允许的范
围,浏览器将自动对它进行删除。至于属性Path,用来指定Cookie将被发送到服务器的哪一个目录路径下。
说明:浏览器创建了一个Cookie后,对于每一个针对该网站的请求,都会在Header中带着这个Cookie;不过,对于其他网站的请求Cookie是绝对不会跟着发送的。而且浏览器会这样一直发送,直到Cookie过期为止。
2.2.2 要点方法
setcookie-----送出 Cookie 信息到浏览器。
语法: int setcookie(string name, string value, int expire, string path, string domain, int secure);
返回值: 整数
本函数会跟着标识 Header 送出一段小信息字符串到浏览器。使用本函数要在送出 HTML 数据前,实际上 cookie 也算标识的一部份。本函数的参数除了第一个 name 之外,都是可以省略的。参数 name 表示 cookie 的名称;value 表示这个 cookie 的值,这个参数为空字符串则表示取消浏览器中该 cookie 的数据;expire 表示该 cookie 的有效时间;path 为该 cookie 的相关路径;domain 表示 cookie 的网站;secure 则需在 https 的安全传输时才有效。想得到更多的 cookie 信息可以到
http://www.netscape.com/newsref/std/cookie_spec.html,由
cookie 原创者 Netscape 所提供的完整信息。
对于一个网站会员而言,经常存在需要一次注册,多次认证的问题,例如我们经常接触到的论坛、社区等,一般采用手段为cookie或 input type=hidden来传递认证参数。这里面有几点隐患:
I. setcookie内容必须完整包含帐号密码,或类似的完整安全信息,如果只携带帐号信息或用某种权限标志来认证,极容易造成非法入侵。
例如某站点中的会员更新页面中携带的认证信息是两个,用户名和Uid(均为明文传送)已知Uid对于每个会员是唯一的。由于我们只需要知道对方的帐号和Uid就可以更改对方信息(不需要知道密码!),只要攻击者知道Uid(攻击者可以通过暴力猜测的方法来得到Uid,有时候站点本身也会泄露用户的Uid,例如在论坛等处)那么,攻击者就可以通过遍历攻击完成对任意一个帐号的信息更改。
II. 必须所有需要权限操作的页面都必须执行认证判断的操作。如果任何一页没有进行这种认证判断,都有可能给攻击者以恶意入侵的机会。
III. 很多网站为了方便,将用户名以及口令信息储存在Cookie中,有的甚至以明文方式保存口令。如果攻击者可以访问到用户的主机,就可能通过保存的Cookie文件得到用户名和口令。
3. 脚本保护的问题
3.1 概念介绍
在程序编写时优秀的程序员都会知道,用有意义的变量名,文件名有助于增加程序的可读性,具有良好的程序风格。这个非常好但在脚本语言不太适合,为了不让恶意用户猜到你的变量或数据库名等信息,必须改掉这些信息。动态的网页在服务器端执行后返回给客户的是执行后的代码,这可以保护服务器端的很多不想叫或不能叫浏览者知道的信息。安全是相对的,每天都在有新的安全漏洞被发现,如果恶意的用户在你之前知道了一个可以看你的脚本源代码的漏洞或这个漏洞一时间无法修补怎么办?
3.2 主意要点
建议用一些比较怪异的名字命名,删掉脚本中的注释。如果还需要保持程序的可读性的话,可以建立一个映射,你可以写个具有良好风格的脚本程序,然后再做一个变量名映射建立一个具有较安全命名方法的脚本,去掉这个脚本中的注视和所有能去掉的信息,修改时作个同步就可以了我们可以在程序的使用前对程序进行加密,以保护我们自己的程序再万一的情况下部被泄漏。
3.3 保护方法
我看到过很多的对脚本的加密方法,都很不错,有的是专门的加密软件,有的是通过一些技巧加上利用语言的特性进行加密的,例如随机生成一个密匙,把密匙放在"不可见的"地方,通过一些算法对脚本进行加解密,就是由于某些系统漏洞导致你的脚本源代码泄漏,也无济于事。
4 .实例说明
下面这个例子是在网上经常被提到的,这是个非常经典的例子,所以在这里通过这个实例告诉大家可能存在的危险。问题描述:
大部分网站把密码放到数据库中,在登陆验证中用以下sql,(以asp为例)
sql="select * from user where username=\'"&username&"\'and pass=\'"& pass &\'"
此时,您只要根据sql构造一个特殊的用户名和密码,如:ben\' or \'1\'=\'1
就可以进入本来你没有特权的页面。再来看看上面那个语句吧:
sql="select * from user where username=\'"&username&"\'and pass=\'"& pass&\'"
此时,您只要根据sql构造一个特殊的用户名和密码,如:ben\' or \'1\'=\'1 这样,程序将会变成这样:
sql="select*from username where
username="&ben\'or\'1\'=1&"and pass="&pass&" or 是一个逻辑运算符,作用是在判断两个条件的时候,只要其中一个条件成立,那么等式将会成立.而在语言中,是以1来代表真的(成立).那么在这行语句中,原语句的"and"验证将不再继续,而因为"1=1"和"or"令语句返回为真值.。
另外我们也可以构造以下的用户名:
username=\'aa\' or username<>\'aa\'
pass=\'aa\' or pass<>\'aa\'
相应的在浏览器端的用户名框内写入:aa\' or username<>\'aa 口令框内写入:aa\' or pass<>\'aa,注意这两个字符串
两头是没有\'的。这
样就可以成功的骗过系统而进入。
具体实施是这样的,首先我会到注册的地方去收集信息,了解尽可能多的信息,例如目标数据库中都有用户的什么样的信息,随便的填写信息然后提交,当你要注册的用户名被注册的是有系统会提示你已被注册,有的网站做的更好的,就是他们专门给你设置的检测是否有已经被注册的功能,通过这样就会非常容易的找到目标--那个提示已被注册的用户,让后你在这个注册页里填写一些特殊的字符,如\',/,,等字符看系统如何提示,以证明程序员是否注意到了应该过滤字符或懂得是否应该过滤那些字符,在这页进行尝试是因为有的网站在登录的时候他会记录你的ip地址,当然你也可以找一个比你直接登录要快的代理服务器来做跳板。后面你要做的就是察看登录页的html源代码,看看是否有在客户端的字符过滤,看看这个程序员是用什么风格来编写程序,尽可能多的了解程序编写风格,这对你以后的某些判断有好处。如果有在客户端的过滤也不怕,你要搞清是什么样的过滤,能不能对攻击造成威胁,不要一看有过滤就害怕,可以尝试着用别的方法绕,就是使用自己精心打造的独立脚本,进行攻击。然后你要看看form的action中的url是否可以直接提交,在浏览器地址栏里直接提交,看看返回什么,是否有来路检测。还有很多细小的地方,你也应该可以注意到,例如那些地方程序员的整体的编写风格是什么,变量名定义的风格是什么等等,这个会帮我们"猜"到很多东西。还有别的其他什么,我也记不太清楚了,临场发挥吧。通过这些了解我们有如下几种可能:
1.那个程序员非常善良相信全世界都是好人,什么都没做,根本没有任何检测机制,我们直接用username=\'aa\' or
username<>\'aa\',
pass=\'aa\' or pass<>\'aa\'就可以搞定,现在这么善良的人少啦,可是你要是有耐心,找到这种人还是不难的。
2.这个程序员可能听别人提起过一些安全问题,毕竟现在这个那里都有人说,很多书中都有提及,但是做得不够好,他只进行了简单的输入过滤。
过滤有两种方式,一种是在客户端的过滤,一种是在服务器端的过滤。现在很多的程序员考虑到再服务器端进行过滤可能给服务器造成更多的负荷,会把检测过程放在客户端。如果他在服务器端没做任何事情,那么还是可以对其进行攻击的,我可以将这个登录页的源代码COPY下来,然后自己建立一个文件把这些代码PASTE进去,再对这个文件进行进一步的深加工,去掉原来页的过滤机制,或者直接将攻击代码写到这个文件中去,然后将form中的action中的地址改成绝对地址,也就是将文件名改成"http://www.target.com/targer.php"这样,然后就可
以提交啦。但是如
果服务器端加上了"来路检测",你就白玩了。如果这样还是不行,我再换一种方法,在浏览器的地址栏里用?来输入参数,就好像
"http://www.targer.com/targer.php?username=\'aa\' or username<>\'aa\'&pass=\'aa\' or pass<>\'aa\' "然后敲回车吧,其
实应该先
尝试这种方法因为这用方法更简单,防护起来也很简单,这种提交方式不是post 而是get ,只要服务器端程序检测你的提交方法,就可以kill掉这
个阴谋。如果单纯的只检测了"来路",还是不太安全的,可以先正确的提交一次,在提交过程中马上停止,就是保存这个环境,然后再构造请求。
(我做过几次试验得到的结果都不太一样,应该是和终止的时机有关,欢迎大家来交流)。
3.一个很出色的程序员,安全意识非常高,他在服务器端做了如下检测:检测提交的方法;检测提交的"来路";检测提交内容的长度;全面检测提交内容,这样我们就很难通过上面的方法对其进行攻击,那到保密的资料就已经不太可能了(如果各位还有什么好的办法,请一定来信告诉小弟,小弟在这里先谢了)。但是我还想说的是攻击并不代表是非要入侵进去,拿到某些东西才叫入侵,对你的机器进行破坏也叫入侵啊,例如提交一些错误的请求,脚本解释程序就会非常规矩的给你返回错误信息,最浅显的后果就是暴露物理路经,有的时候一些特殊的请求会使web服务宕掉,这些个我认为绝对是属于攻击,绝对是危害,也许你认为暴露物理路径没有什么,是在单独看来没有什么,但要是在一个有计划的攻击里,这个就会发挥很多作用,那时你可能还会莫名为什么他们找到了我的文件呢。也许有人认为这个是脚本解释程序的bug,也许有的是,但是返回错误信息绝对不是脚本解释程序的错误,这个是每个解释程序都要做到的,在我看来这个应该是还是程序员的问题,程序员没有做好对错误的处理。每一本教你如何编写程序的书籍里基本都会有错误处理之类的章节,并且每种语言基本都有错误处理函数和方法,只不过你没有想到罢了。至于究竟要怎么处理那就要看你对cgi程序安全的熟悉程度了,那就要看你对这种脚本语言的特性熟悉多少了,说到底就是经验,唯一的办法就是多看多写多想多交流。
4.非常优秀的程序员,以上那些做的都非常好(也许就是你啊,毕竟不难嘛,加上很少的代码就可以了),怎么办??怎么办?!怎么办!!在一旁偷偷的佩服吧!哈哈。
5. 其它注意事项:思路和方法
指导思想:
I.严格控制程序与用户交互的途径
II.严格控制程序与用户交互的内容
III.尽可能好的保护我们控制
基本思路:
I.为没一个功能写一个独立的程序,程序页
II.尽可能少的让客户了解你的服务器端信息
III.不要用"客户应该这么写"这个思路想问题
IV.尽可能多的想到不可能发生的事情
基本方法:
尽可能多的控制交互:
I.检测提交的方法,就是控制他的post还是get;
II.检测提交的"来路",就是检测一个环境变量HTTP_REFERER;
III.检测提交内容的长度;
IV全面检测提交内容;
积极-消极防护:
I.尽可能多的错误处理,例如当检测到了不正确的输入时,应该怎么做,是强制返回,还是发出警告;
II.充分发挥日志功用,例如在你检测到了不正确的提交时,就记录下客户端的信息,例如IP,系统配置,请求等等,毕竟现在是技术飞跃的时代,不能保证可以想到每一种可能,这也是我在这篇文章里不止一次提到"尽可能"这个词的原因。充分的日志记录不全是为了抓住入侵者(如果入侵者使用了跳板,记录了IP也是没有用的),更重要的是为了能发现问题的所在,找到问题,改正问题,亡羊补牢,这个才是最重要的。
III.充分发挥你的想象力,用一种入侵者的思想考虑问题,用一种另类的思想考虑问题,尽可能想到不可能发生的事,把问题扼杀在萌芽里。
我们xundi哥说的好:掌握方法!!!现在脚本语言层出不穷,asp,perl,php,jsp等等,基本不可能精通每一种,(也许你厉害,都能精通,我比较呆,会一个就不错啦),但是要是掌握了方法就不同了啊,各位网络的精英举一反三触类旁通,肯定是优秀的不得了。我写脚本一共也没多少天,写这个东西我知道肯定是班门弄斧了,错误之处还请各位大虾抱着挽救和帮助的精神,告知小弟(方式、方法、态度不限),小弟我在这里先谢了。写这个东西,我只是想说说小弟的一些小的心得,与大家共勉,我想告诉大家的就是"领会精神",嘿嘿,"领会精神"。大家要是有什么好的方法,希望不要保留,充分发挥网络的自用共享,拿出来,大家交流交流,不胜感激。袭来的,这种东西小弟不敢自己写(嘿嘿,实际还有不少懒的成分,哈哈),希望大家不要见怪。
- 上一篇: 关于分页办法
- 下一篇: 如何使REPLACE方法不区分大小写
-= 资 源 教 程 =-
文 章 搜 索