您的位置:首页 > 编程语言

WEB代码安全分析

2009-09-19 16:12 176 查看

WEB代码安全分析

下面这段代码是一个WEB系统中显示广告内容的程序,这个程序从发现漏洞到现在,历经多次修改,但是每次修改都有安全问题或隐患,这些问题虽然不会直接导致入侵,但是在其他非托管系统中或在使用其他非托管语言开发的组件中,则会引起更大的安全问题。

<% Response.WriteFile(AdvFile); %>
AdvFile = Request.QueryString["Path"];
AdvFile = @"../xdd/" + AdvFile;
代码 1
代码的目的是从用户端获取Path 参数并拼接上文件目录,然后读出文件并返回到客户端。开发人员认为PATH是A-Z这样的文件名,实际上攻击者可以输入”..”、”/”等特殊符,从而打破目录限制,访问当前WEB站点中的任何文件,如Path=../Web.Config,获取WEB应用程序的配置文件,Path=../Bin/APP.DLL获取DLL文件,Path=../Cert/App.Cert获取证书文件,通过这样一个漏洞,应用程序对攻击者而言,就成了“开放式系统”,给攻击者实施后续攻击提供了有力帮助。

改进一

开发人员为了防止攻击者通过以上方式非法访问机密文件,采用了下面的保护措施:

AdvFile = AdvFile.ToLower().Replace(".html", "") + ".html";
代码 2
通过强制在文件名后面加上.Html来达到限制只能访问HTML文件,从而保护其他类型的文件不被非法访问。这点在C#这样的托管代码中,确实可以达到限定访问文件类型的目的,当然,文件目录仍然不受限制,攻击者仍然可以使用..来访问其他非授权目录。但是,这种方式仅仅在托管代码内有效,如果是文件名传送到非托管代码,如VB开发的COM组件,则仍有安全风险。
以下VB代码是从参数FileName所指定的文件中获取内容并返回。
Public Function ReadFile(FileName As String) As String
Dim FileContent As String
Open FileName For Input As #1
Input #1, FileContent
Close #1
ReadFile = FileContent
End Function
代码 3
这段C#代码调用VB设置的COM组件读文件并返回客户端,在非托管语言中/0是字符串结束符,如果攻击者输入的字符串内含有/0这样的字符,参数传入VB开发的COM组件内,则系统会丢失在C#程序中加入的.Html。最后文件名会完全受到攻击者控制,这样就可以访问任何文件。
SecurityDemo.FileOperClass oFile = new SecurityDemo.FileOperClass();
AdvFile = AdvFile.ToLower().Replace(".html", "") + ".html";
Response.Write(oFile.ReadFile(ref AdvFile));
代码 4
如攻击者输入Path=C:/test.txt%00%00,在C#中字符串是C:/test.txt/0/0.html,但是在VB里面所访问的文件已经变成了C:/test.txt.
在JAVA和PHP等语言中,也存在类似的情况。所以采用拼接的方式在C#中不会有直接的问题,但是如果这种编程方式在其他情形下,就可能会有安全问题。

改进二:

开发人员后来又把上述代码改进行以下改进:
AdvFile = Request.QueryString["Path"];
Regex FileName = new Regex(@"^([A-Za-z](/w+.)+)/.htm|htm|html$");
if (FileName.IsMatch(AdvFile) == false)
{
AdvFile = "DefaultAdv.htm";
return;
}
AdvFile = @"../xdd/" + AdvFile;
代码 5
这段代码采用正则表达式来限制用户的输入,本意是要求输入的文件名必须是以.Html或.htm结尾,但是正则表达式没有写正确!这段正则表达式的限制是文件名必须以Html结尾或文件名中包含“htm”。
因此,这段代码又形成了一个可利用的漏洞,攻击者只需要输入Path=C:/a.html/../test.txt就会即满足正则表达式,又能达到非法访问的目的。同时,即便上面的正则表达式是正确的,由于攻击者可以使用%00来突破文件扩展名限制,所以,这种方式也是有安全隐患的。

推荐代码

实际上我们只需要简单使用C#的FileInfo类来获取文件真实的文件名以及扩展名并判定是否和我们许可的文件类型相同即可:
AdvFile = Request.QueryString["Path"];
AdvFile = Request.MapPath(".") + AdvFile;
try
{
System.IO.FileInfo oFileInfo = new System.IO.FileInfo(AdvFile);
if (oFileInfo.Extension.ToLower() != ".html" || oFileInfo.DirectoryName.ToLower() != "MyDirectory" || !System.IO.File.Exists(AdvFile))
{
AdvFile = "DefaultAdv.htm";
return;
}
AdvFile = oFileInfo.FullName;
return;
}
catch
{
AdvFile = "DefaultAdv.htm";
return;
}
代码 6
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: