从客户端(&)检测到潜在危险的Request.Path值

时间:2011-04-15 20:41:57

标签: security validation asp.net-mvc-3 razor

我理解为什么会这样,但我需要一个解决方法。我在StackOverflow上查看了一些其他问题,但没有一个是有用的。我不想在整个网站上禁用输入验证,因为这绝对是危险的。我只有一个(至少现在)我需要禁用输入验证的地方。

我用[ValidateInput(false)]属性修饰了Action方法,我用Html.Encode对字符串进行编码。但是,我仍然得到同样的错误。这是我的观点:

<div id="sharwe-categories">
    <ul class="menu menu-vertical menu-accordion">
        @foreach(var topLevel in Model)
        {
            var topLevelName = Html.Encode(topLevel.Name);
             <li class="topLevel">
                <h3>  
                    @Html.ActionLink(topLevel.Name, "Index", "Item", new { category = topLevelName }, new {@class = "main"} )
                    <a href="#" class="drop-down"></a>
                </h3>
                <ul>
                    @foreach (var childCategory in topLevel.Children)
                    {
                        var childcategoryName = Html.Encode(childCategory.Name);
                        <li>@Html.ActionLink(childCategory.Name, "Index", "Item", new RouteValueDictionary { { "category", topLevelName }, { "subcategory", childcategoryName } }, null)</li>
                    }
                </ul>
            </li>
        }

    </ul>

</div>

如您所见,没有用户输入。但是一些类别名称中有一些“危险”字符......任何解决方案?

3 个答案:

答案 0 :(得分:11)

尽管Darin的答案是完全可行的,但我不建议使用Scott Hanselman的技术逐步完成所有这些验证。你迟早会深陷......

使用ID和虚拟字符串(对SEO和人们来说很棒)的第二个建议是一种方法,但有时它们也不可行。想象一下这个请求URL:

/111/Electronics/222/Computers/333/Apple

虽然我们拥有这些ID,但我们也可以依赖这些ID和人类/ SEO友好类别名称,这绝对不是必需的。当我们需要代表一个单独的项目时,ID + Dummy字符串是可行的。在其他情况下,它不是。由于你必须显示类别和子类别,这是一个问题。

那你能做什么?

两种可能的解决方案:

  1. 清理类别名称只能包含有效字符 - 可以这样做但如果特权用户不是静态和可编辑的,那么你在这里运气不好,因为即使你现在已经清理它们了,有人会在以后输入无效的内容

  2. 随时随地清理字符串 - 当您使用类别名称时,清理它并在阅读和使用它时(为了获得实际的类别ID)您可以比较提供的(先前已清除的)类别名称和值您即时清理的数据库:

    1. 现在在过滤类别时
    2. 生成类别名称之前
  3. 我建议你采用2.2方法。将数据库表扩展为两列:

    • 类别显示名称
    • 类别网址友好名称

    您还可以在第二列上设置唯一约束,因此不会发生两个类别(即使它们具有不同的显示名称)具有相同的URL友好名称。

    如何清理

    首先想到的是剥离无效字符,但这非常繁琐,你很可能会遗漏一些东西。从类别显示名称中获取有效字符会更容易,更明智。生成虚拟 URL类别名称时,我也做了同样的事情。只需取出有效的东西,然后将其余部分分开。它通常工作得很好。这种正则表达式的两个例子:

    1. (\w{2,}) - 仅使用字母,数字和下划线以及其中至少两个(因此我们省略 a 或单个数字和相似内容,不会增加任何含义并且不必要地延长我们的网址
    2. ([a-zA-Z0-9]{2,}) - 只有字母和数字(也是2 +)
    3. 获取类别显示名称中的所有匹配项,并使用空格/破折号连接它们并与原始显示名称一起保存。另一个question of mine就是这个。

      为什么要添加其他列?因为您无法在SQL Server中运行正则表达式。如果您正在使用MySql,则可以使用一列并在DB上使用正则表达式。

答案 1 :(得分:2)

即使你不应该这样做......有时也没有一种简单的方法可以绕过它。 web.Config中的httpRuntime标记上的requestPathInvalidCharacters是您寻求的。只需在&lt; system.web&gt;中输入以下内容即可。部分:

<httpRuntime requestPathInvalidCharacters="&lt;,&gt;,*,%,:,\" />

我强烈建议使用以下内容将其锁定:

<location path="the/path/you/need/to/lock/down">
    <system.web>
        <httpRuntime requestPathInvalidCharacters="&lt;,&gt;,*,%,:,\"/>
    </system.web>
</location>

只需将其投入根&lt; configuration&gt;标签。这样......你不会打开你的整个网站,以允许在路径中使用&符号......并且可能会使整个站点暴露在不可预见的攻击中。

答案 2 :(得分:0)

您可能会发现following blog post对于在网址中使用特殊字符非常有用。但总的来说,最好的做法是replace those titles with slugs和StackOverflow一样,在url中使用问题标题来获得更好的搜索引擎优化,并使用ID来识别它们。