是否有人知道触发ASP.NET的HttpRequestValidationException的确切内容列表? [这是常见错误的背后:“检测到潜在危险的Request.Form值,”等等]
我已经在这里,网络和MSDN库中查了但是找不到这个记录。我知道一些生成错误的方法,但是希望有一个完整的列表,以便我可以防范并有选择地绕过它(我知道如何禁用页面的请求验证,但这不是一个选项情况)。
这是“通过默默无闻的安全”的案例吗?
感谢。
[注意:在IE8中不会为我加载脚本(如在Meta论坛中经常描述的那样),所以我将无法“添加评论。”]
编辑1:您好Oded,您是否知道列出用于确定“潜在恶意输入字符串”的条件的列表?这就是我在寻找的东西。
编辑2:@Chris Pebble:是的,你说的话。 :)答案 0 :(得分:35)
我找不到描述结论性列表的文档,但是通过Reflector查看并使用HttpRequestValidationException进行一些分析,看起来下面的验证错误会导致请求验证失败:
那么,问题是“将这些事情中的一项视为危险的投入?”这似乎发生在内部方法System.Web.CrossSiteScriptingValidation.IsDangerousString(string,out int)中,它看起来像这样决定:
<
或&
。如果它不存在,或者它是值中的最后一个字符,那么值就可以了。&
字符位于&#
序列中(例如, 
表示不间断的空格),则为“危险字符串”。<
字符属于<x
(其中“x”是任何字母字符az),<!
,</
或<?
,这是一个“危险的字符串。”System.Web.CrossSiteScriptingValidation类型似乎有其他方法用于确定事物是危险的URL还是有效的JavaScript ID,但至少通过Reflector分析不会出现这些方法导致抛出HttpRequestValidationExceptions。
答案 1 :(得分:16)
警告:原始答案(下方)中代码的某些部分已被删除并标记为已过时。
http://referencesource.microsoft.com/#System.Web/CrossSiteScriptingValidation.cs
在检查了最新的代码后,您可能会同意Travis Illig explained是2018年现在使用的唯一验证(并且自2014年发布源代码时似乎没有任何更改in GitHub)。但是,如果使用旧版本的框架,下面的旧代码可能仍然相关。
使用Reflector,我做了一些浏览。这是原始代码。当我有时间时,我会将其转化为一些有意义的规则:
HttpRequestValidationException
命名空间中只有一个方法抛出System.Web
,所以它相当孤立。这是方法:
private void ValidateString(string s, string valueName, string collectionName)
{
int matchIndex = 0;
if (CrossSiteScriptingValidation.IsDangerousString(s, out matchIndex))
{
string str = valueName + "=\"";
int startIndex = matchIndex - 10;
if (startIndex <= 0)
{
startIndex = 0;
}
else
{
str = str + "...";
}
int length = matchIndex + 20;
if (length >= s.Length)
{
length = s.Length;
str = str + s.Substring(startIndex, length - startIndex) + "\"";
}
else
{
str = str + s.Substring(startIndex, length - startIndex) + "...\"";
}
throw new HttpRequestValidationException(HttpRuntime.FormatResourceString("Dangerous_input_detected", collectionName, str));
}
}
上面的方法调用IsDangerousString
类中的CrossSiteScriptingValidation
方法,该方法根据一系列规则验证字符串。它看起来如下:
internal static bool IsDangerousString(string s, out int matchIndex)
{
matchIndex = 0;
int startIndex = 0;
while (true)
{
int index = s.IndexOfAny(startingChars, startIndex);
if (index < 0)
{
return false;
}
if (index == (s.Length - 1))
{
return false;
}
matchIndex = index;
switch (s[index])
{
case 'E':
case 'e':
if (IsDangerousExpressionString(s, index))
{
return true;
}
break;
case 'O':
case 'o':
if (!IsDangerousOnString(s, index))
{
break;
}
return true;
case '&':
if (s[index + 1] != '#')
{
break;
}
return true;
case '<':
if (!IsAtoZ(s[index + 1]) && (s[index + 1] != '!'))
{
break;
}
return true;
case 'S':
case 's':
if (!IsDangerousScriptString(s, index))
{
break;
}
return true;
}
startIndex = index + 1;
}
}
IsDangerousString
方法似乎引用了一系列验证规则,概述如下:
private static bool IsDangerousExpressionString(string s, int index)
{
if ((index + 10) >= s.Length)
{
return false;
}
if ((s[index + 1] != 'x') && (s[index + 1] != 'X'))
{
return false;
}
return (string.Compare(s, index + 2, "pression(", 0, 9, true, CultureInfo.InvariantCulture) == 0);
}
-
private static bool IsDangerousOnString(string s, int index)
{
if ((s[index + 1] != 'n') && (s[index + 1] != 'N'))
{
return false;
}
if ((index > 0) && IsAtoZ(s[index - 1]))
{
return false;
}
int length = s.Length;
index += 2;
while ((index < length) && IsAtoZ(s[index]))
{
index++;
}
while ((index < length) && char.IsWhiteSpace(s[index]))
{
index++;
}
return ((index < length) && (s[index] == '='));
}
-
private static bool IsAtoZ(char c)
{
return (((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')));
}
-
private static bool IsDangerousScriptString(string s, int index)
{
int length = s.Length;
if ((index + 6) >= length)
{
return false;
}
if ((((s[index + 1] != 'c') && (s[index + 1] != 'C')) || ((s[index + 2] != 'r') && (s[index + 2] != 'R'))) || ((((s[index + 3] != 'i') && (s[index + 3] != 'I')) || ((s[index + 4] != 'p') && (s[index + 4] != 'P'))) || ((s[index + 5] != 't') && (s[index + 5] != 'T'))))
{
return false;
}
index += 6;
while ((index < length) && char.IsWhiteSpace(s[index]))
{
index++;
}
return ((index < length) && (s[index] == ':'));
}
所以你有它。解密并不是很好,但它就在那里。
答案 2 :(得分:2)
这个脚本怎么样?你的代码无法检测到这个脚本,对吗?
";}alert(1);function%20a(){//
答案 3 :(得分:0)
试试这种正则表达式模式。
您可能需要转义\ for javascript ex \\
var regExpPattern = '[eE][xX][pP][rR][eE][sS][sS][iI][oO][nN]\\(|\\b[oO][nN][a-zA-Z]*\\b\\s*=|&#|<[!/a-zA-Z]|[sS][cC][rR][iI][pP][tT]\\s*:';
var re = new RegExp("","gi");
re.compile(regExpPattern,"gi");
var outString = null;
outString = re.exec(text);
答案 4 :(得分:0)
根据Travis的回答,“危险”字符序列的列表可以简化如下;
基于此,在ASP.Net MVC Web应用程序中,可以在模型字段上使用以下Regex验证属性,以在提交表单时抛出HttpRequestValidationException之前触发客户端验证;
[RegularExpression(@"^(?![\s\S]*(&#|<[a-zA-Z!\/?]))[\s\S]*$", ErrorMessage = "This field does not support HTML or allow any of the following character sequences; "&#", "<A" through to "<Z" (upper and lower case), "<!", "</" or "<?".")]
请注意,当服务器端验证输出时,验证属性错误消息是HTML编码的,但在客户端验证中使用时则不是HTML编码,因此该代码已经被编码,因为我们只打算在客户端验证中看到它。
答案 5 :(得分:-1)
来自MSDN:
'作为请求数据的一部分从客户端收到潜在恶意输入字符串时引发的异常。 “
很多时候,当JavaScript以一种导致ViewState与发布数据不一致的方式更改服务器端控件的值时,会发生这种情况。