65.9K
CodeProject 正在变化。 阅读更多。
Home

HTTP 请求查询字符串保护

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.44/5 (27投票s)

2007年9月9日

CPOL

4分钟阅读

viewsIcon

128185

downloadIcon

934

为您的 Web 应用程序添加一层安全。

目录

  1. 引言
  2. 动机
  3. TagSinj 干预
  4. 功能概述
  5. 背后的实际代码
  6. Using the Code
  7. 注释

引言

本文将介绍一种安全地保护查询字符串免受 SQL 注入的可靠方法。总体思路受到了支付网关保护其参数方式的启发。

TagSinj(代表 **Tag** **S**ecure **Inj**ection)类包含两个主要函数,可以轻松集成到所有 Web 应用程序中。

动机...

在构建应用程序时,保护您获取 HTTP 查询字符串发送的参数的方式非常必要。用户很容易简单地修改这些参数并弄乱您的应用程序。例如,假设您在查询字符串中使用两个参数,一个用于标识您要加载的页面,另一个用于加载具有其 ID(数据库 ID,即主键)的特定产品,您的查询字符串可能如下所示:

http://www.yourdomain.com/default.aspx?page=products&id=234

假设您正在获取这些参数并生成数据库查询。您的数据库查询可能如下所示:

SELECT * FROM product WHERE ProductID = '234'

简单地修改查询字符串如下(删除参数“id”的值):

http://www.yourdomain.com/default.aspx?page=products&id=

您动态生成的数据库查询将变成:

SELECT * FROM product WHERE ProductID = '' 

这通常不会造成太大危害,除了用户无法正常加载之外,但如果您的环境不够安全呢?例如:

http://www.yourdomain.com/default.aspx?page=products&id=';DROP DATABASE databasename;--

您动态生成的数据库查询将变成:

SELECT * FROM product WHERE ProductID = '';DROP DATABASE databasename;--'

这可能非常有害……

TagSinj 干预

TagSinj 在生成数据库查询字符串之前的一个层进行干预。页面加载后,TagSinj 将检查发送的参数。如果它们是真实的,那么您可以继续执行代码,否则它们已被修改。您可以中断代码执行并相应地处理异常。

功能概述

这个想法背后的主要概念是确认从一个页面发送的参数与接收页面收到的参数完全相同(即使两个页面是同一个页面,也能正常工作)。
为此,此类将向查询字符串附加一个额外的参数(称为“mac”),它是一个 MD5 字符串(mac 参数是所有参数连接起来与安全访问代码的 MD5 结果)。

因此,为了锁定您的查询字符串免受注入,您需要生成安全链接(generateSecureLink(string link)),并在加载页面时,需要一个方法来验证参数(validateLink(HttpRequest Request))。

背后的实际代码……

首先,我将讨论生成安全链接的方法。此方法将获取您使用的原始链接,例如:default.aspx?par1=hello&par2=world 并返回 default.aspx?par1=hello&par2=world&mac=MD5STRING 其中 MD5STRING 是您的 par1 值与您的 par2 值以及您的安全访问代码连接起来的结果,即在这种情况下(如果我们的访问代码是“howareyou”)我们将拥有:helloworldhowareyou

/// <summary>
/// This method takes a link and appends to it the secure hash used to
/// validate the query string
/// </summary>
/// <param name="""""link""""" />link</param>
/// <returns>input link with mac paramater appended</returns>
        public static string generateSecureLink(string link)
        {
            string toHash = "";
            string[] querystring = null;
            string[] vars = null;
            string[] vals = null;
//if the link has some parameters            
if (link.Contains("?"))
            {
                querystring = link.Split('?'); vars = querystring[1].Split('&');
                foreach (string st in vars)
                {
                    vals = st.Split('=');
                    //toHash has all parameters value appended next to each other
                    toHash += vals[1].ToString();
                }
            }
            //otherwise
            else
            {
                querystring = link.Split('?');
                vars = querystring[1].Split('=');
                toHash += vals[1].ToString();
            }
            //append the access code to the end of the string and MD5 the result
            string hashed = TagSinj.Hash(toHash + TagSinj.AccessCode);
            //returns the mac parameter appended to the link
            return link + "&mac=" + hashed;
        }

其次,您需要一种方法来验证生成的安全链接(无论何时您想验证您的查询字符串是否以与发送时完全相同的方式接收)。

此方法获取 HttpRequest (从中使用的查询字符串)。它基本上会重新获取通过查询字符串传递的所有参数(除了“mac”),将它们按传递的顺序重新连接,并附加访问代码。

然后,它将生成的 MD5 字符串与抓取的 MD5 字符串进行匹配。如果两者匹配,则查询字符串是安全的,否则已被修改,存在潜在威胁。

/// <summary>
/// This method takes an HttpRequest as a parameter and checks 
/// whether the query string parameters have been
/// manipulated by the user
/// </summary>
/// <param name="""""Request""""" />
/// HttpRequest, used to take the querystring item</param>
/// <returns>true if query string is authentic, false otherwise</returns>
public static bool validateLink(HttpRequest Request)
{
    try
    {
        //loop through all the parameters and recreate the hash
        if (Request.QueryString.Count > 0)
        {
            String[] queryKeys = Request.QueryString.AllKeys;
            int queryCount = Request.QueryString.Count;

            string toHash = "";
            for (int m = 0; m < queryCount; m++)
            {
                if (queryKeys[m] != "mac")
                {
                    toHash += Request.QueryString[queryKeys[m]];
                }
            }
            string hashed = TagSinj.Hash(toHash + TagSinj.AccessCode);
            if (hashed != Request.QueryString["mac"])
            {
                return false;
            }
            else
            {
                return true;
            }
        }
        else
        {
            return false;
        }
    }
    catch
    {
        return false;
    }
}

Using the Code

下面,我将说明使用此类的方法。

步骤 1:包含

  • 下载 TagSinj.zip
  • *.dll 文件作为引用添加到您的项目中。
  • 在您的 *.cs 文件中包含该文件。
using System.Web.UI.WebControls; 
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using TagSinj;

完成上述步骤后,您现在就可以使用此类提供的两个方法了。

步骤 2:设置访问代码

为了获得唯一的“mac”,您必须为您的访问代码设置一个值。这可以在您的 global.asax 页面中设置一次,或者在您使用此类的页面中设置。访问代码可以是您选择的任何 string

//The below selected access code is for illustration purposes only
//Simpler or more complex codes can be randomly generated
TagSinj.TagSinj.AccessCode = "AV$%990LK_12";

步骤 3:生成安全链接

为了让您的应用程序接受查询字符串,您必须使用以下方法生成安全链接:

//the generateSecureLink function will append to the parameter added a
//"mac" parameter which will be a unique way of identifying your
//sequence of parameters
secureLink = TagSinj.TagSinj.generateSecureLink
	("anyPage.aspx?var=test1&var1=test2&var2=test3");
Your resulting value should look like: 
anyPage.aspx?var=test1&var1=test2&var2=test3&mac=bc2d6cb550c88bed381521bea654ea11

步骤 4:获取您的变量

现在您的链接已安全,是时候确保没有人篡改您的查询字符串了。为此,在 Page_Load 事件下,添加这段代码:

if (TagSinj.TagSinj.validateLink(this.Request))
{
   //parameters are exactly the same way you have sent them
   //Do action
   Response.Write("The parameters are correct");
}
else
{
   //somebody is playing around with the parameters
   //Do action
   Response.Write("The parameters are incorrect");
}
结论

这样,您就可以确保从一个页面发送的参数与收到的参数完全相同。此功能将大大减少甚至消除您网站遭受 SQL 注入的威胁。

注释

这是我在 CodeProject 发表的第一篇文章。欢迎任何评论。如果您计划使用此 DLL,请给我发电子邮件。
感谢您的阅读。

© . All rights reserved.