HttpRequest的QueryString屬性 的一點(diǎn)認(rèn)識(shí)

當(dāng)然我們一般都是按照提示來(lái)把framework版本設(shè)置2.0來(lái)解決。為什么可以這么解決了,還有沒(méi)有其它的解決方法了。
先讓我們看看QueryString的源代碼吧:
public NameValueCollection QueryString
{
get
{
if (this._queryString == null)
{
this._queryString = new HttpValueCollection();
if (this._wr != null)
{
this.FillInQueryStringCollection();
}
this._queryString.MakeReadOnly();
}
if (this._flags[1])
{
this._flags.Clear(1);
this.ValidateNameValueCollection(this._queryString, RequestValidationSource.QueryString);
}
return this._queryString;
}
}
private void FillInQueryStringCollection()
{
byte[] queryStringBytes = this.QueryStringBytes;
if (queryStringBytes != null)
{
if (queryStringBytes.Length != 0)
{
this._queryString.FillFromEncodedBytes(queryStringBytes, this.QueryStringEncoding);
}
}
else if (!string.IsNullOrEmpty(this.QueryStringText))
{
this._queryString.FillFromString(this.QueryStringText, true, this.QueryStringEncoding);
}
}
先讓我們插入一點(diǎn) 那就是QueryString默認(rèn)已經(jīng)做了url解碼。 其中HttpValueCollection的 FillFromEncodedBytes方法如下
internal void FillFromEncodedBytes(byte[] bytes, Encoding encoding)
{
int num = (bytes != null) ? bytes.Length : 0;
for (int i = 0; i < num; i++)
{
string str;
string str2;
this.ThrowIfMaxHttpCollectionKeysExceeded();
int offset = i;
int num4 = -1;
while (i < num)
{
byte num5 = bytes[i];
if (num5 == 0x3d)
{
if (num4 < 0)
{
num4 = i;
}
}
else if (num5 == 0x26)
{
break;
}
i++;
}
if (num4 >= 0)
{
str = HttpUtility.UrlDecode(bytes, offset, num4 - offset, encoding);
str2 = HttpUtility.UrlDecode(bytes, num4 + 1, (i - num4) - 1, encoding);
}
else
{
str = null;
str2 = HttpUtility.UrlDecode(bytes, offset, i - offset, encoding);
}
base.Add(str, str2);
if ((i == (num - 1)) && (bytes[i] == 0x26))
{
base.Add(null, string.Empty);
}
}
}
從這里我們可以看到QueryString已經(jīng)為我們做了解碼工作,我們不需要寫(xiě)成 HttpUtility.HtmlDecode(Request.QueryString["xxx"])而是直接寫(xiě)成Request.QueryString["xxx"]就ok了。
現(xiàn)在讓我們來(lái)看看你QueryString的驗(yàn)證,在代碼中有
if (this._flags[1])
{
this._flags.Clear(1);
this.ValidateNameValueCollection(this._queryString, RequestValidationSource.QueryString);
}
一看this.ValidateNameValueCollection這個(gè)方法名稱就知道是干什么的了,驗(yàn)證QueryString數(shù)據(jù);那么在什么情況下驗(yàn)證的了?
讓我們看看this._flags[1]在什么地方設(shè)置的:
public void ValidateInput()
{
if (!this._flags[0x8000])
{
this._flags.Set(0x8000);
this._flags.Set(1);
this._flags.Set(2);
this._flags.Set(4);
this._flags.Set(0x40);
this._flags.Set(0x80);
this._flags.Set(0x100);
this._flags.Set(0x200);
this._flags.Set(8);
}
}
而該方法在ValidateInputIfRequiredByConfig中調(diào)用,調(diào)用代碼
internal void ValidateInputIfRequiredByConfig()
{
.........
if (httpRuntime.RequestValidationMode >= VersionUtil.Framework40)
{
this.ValidateInput();
}
}
我想現(xiàn)在大家都應(yīng)該明白為什么錯(cuò)題提示讓我們把framework改為2.0了吧。應(yīng)為在4.0后才驗(yàn)證。這種解決問(wèn)題的方法是關(guān)閉驗(yàn)證,那么我們是否可以改變默認(rèn)的驗(yàn)證規(guī)則了?
讓我們看看ValidateNameValueCollection
private void ValidateNameValueCollection(NameValueCollection nvc, RequestValidationSource requestCollection)
{
int count = nvc.Count;
for (int i = 0; i < count; i++)
{
string key = nvc.GetKey(i);
if ((key == null) || !key.StartsWith("__", StringComparison.Ordinal))
{
string str2 = nvc.Get(i);
if (!string.IsNullOrEmpty(str2))
{
this.ValidateString(str2, key, requestCollection);
}
}
}
}
private void ValidateString(string value, string collectionKey, RequestValidationSource requestCollection)
{
int num;
value = RemoveNullCharacters(value);
if (!RequestValidator.Current.IsValidRequestString(this.Context, value, requestCollection, collectionKey, out num))
{
string str = collectionKey + "=\"";
int startIndex = num - 10;
if (startIndex <= 0)
{
startIndex = 0;
}
else
{
str = str + "...";
}
int length = num + 20;
if (length >= value.Length)
{
length = value.Length;
str = str + value.Substring(startIndex, length - startIndex) + "\"";
}
else
{
str = str + value.Substring(startIndex, length - startIndex) + "...\"";
}
string requestValidationSourceName = GetRequestValidationSourceName(requestCollection);
throw new HttpRequestValidationException(SR.GetString("Dangerous_input_detected", new object[] { requestValidationSourceName, str }));
}
}
哦?原來(lái)一切都明白了,驗(yàn)證是在RequestValidator做的。
public class RequestValidator
{
// Fields
private static RequestValidator _customValidator;
private static readonly Lazy<RequestValidator> _customValidatorResolver = new Lazy<RequestValidator>(new Func<RequestValidator>(RequestValidator.GetCustomValidatorFromConfig));
// Methods
private static RequestValidator GetCustomValidatorFromConfig()
{
HttpRuntimeSection httpRuntime = RuntimeConfig.GetAppConfig().HttpRuntime;
Type userBaseType = ConfigUtil.GetType(httpRuntime.RequestValidationType, "requestValidationType", httpRuntime);
ConfigUtil.CheckBaseType(typeof(RequestValidator), userBaseType, "requestValidationType", httpRuntime);
return (RequestValidator) HttpRuntime.CreatePublicInstance(userBaseType);
}
internal static void InitializeOnFirstRequest()
{
RequestValidator local1 = _customValidatorResolver.Value;
}
private static bool IsAtoZ(char c)
{
return (((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')));
}
protected internal virtual bool IsValidRequestString(HttpContext context, string value, RequestValidationSource requestValidationSource, string collectionKey, out int validationFailureIndex)
{
if (requestValidationSource == RequestValidationSource.Headers)
{
validationFailureIndex = 0;
return true;
}
return !CrossSiteScriptingValidation.IsDangerousString(value, out validationFailureIndex);
}
// Properties
public static RequestValidator Current
{
get
{
if (_customValidator == null)
{
_customValidator = _customValidatorResolver.Value;
}
return _customValidator;
}
set
{
if (value == null)
{
throw new ArgumentNullException("value");
}
_customValidator = value;
}
}
}
主要的驗(yàn)證方法還是在CrossSiteScriptingValidation.IsDangerousString(value, out validationFailureIndex);而CrossSiteScriptingValidation是一個(gè)內(nèi)部類,無(wú)法修改。
讓我們看看CrossSiteScriptingValidation類大代碼把
internal static class CrossSiteScriptingValidation
{
// Fields
private static char[] startingChars = new char[] { '<', '&' };
// Methods
private static bool IsAtoZ(char c)
{
return (((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')));
}
internal static bool IsDangerousString(string s, out int matchIndex)
{
matchIndex = 0;
int startIndex = 0;
while (true)
{
int num2 = s.IndexOfAny(startingChars, startIndex);
if (num2 < 0)
{
return false;
}
if (num2 == (s.Length - 1))
{
return false;
}
matchIndex = num2;
char ch = s[num2];
if (ch != '&')
{
if ((ch == '<') && ((IsAtoZ(s[num2 + 1]) || (s[num2 + 1] == '!')) || ((s[num2 + 1] == '/') || (s[num2 + 1] == '?'))))
{
return true;
}
}
else if (s[num2 + 1] == '#')
{
return true;
}
startIndex = num2 + 1;
}
}
internal static bool IsDangerousUrl(string s)
{
if (string.IsNullOrEmpty(s))
{
return false;
}
s = s.Trim();
int length = s.Length;
if (((((length > 4) && ((s[0] == 'h') || (s[0] == 'H'))) && ((s[1] == 't') || (s[1] == 'T'))) && (((s[2] == 't') || (s[2] == 'T')) && ((s[3] == 'p') || (s[3] == 'P')))) && ((s[4] == ':') || (((length > 5) && ((s[4] == 's') || (s[4] == 'S'))) && (s[5] == ':'))))
{
return false;
}
if (s.IndexOf(':') == -1)
{
return false;
}
return true;
}
internal static bool IsValidJavascriptId(string id)
{
if (!string.IsNullOrEmpty(id))
{
return CodeGenerator.IsValidLanguageIndependentIdentifier(id);
}
return true;
}
}
結(jié)果我們發(fā)現(xiàn)&# <! </ <? <[a-zA-z] 這些情況驗(yàn)證都是通不過(guò)的。
所以我們只需要重寫(xiě)RequestValidator就可以了。
例如我們現(xiàn)在需要處理我們現(xiàn)在需要過(guò)濾QueryString中k=&...的情況
public class CustRequestValidator : RequestValidator
{
protected override bool IsValidRequestString(HttpContext context, string value, RequestValidationSource requestValidationSource, string collectionKey, out int validationFailureIndex)
{
validationFailureIndex = 0;
//我們現(xiàn)在需要過(guò)濾QueryString中k=&...的情況
if (requestValidationSource == RequestValidationSource.QueryString&&collectionKey.Equals("k")&& value.StartsWith("&"))
{
return true;
}
return base.IsValidRequestString(context, value, requestValidationSource, collectionKey, out validationFailureIndex);
}
}
<httpRuntime requestValidationType="MvcApp.CustRequestValidator"/>
個(gè)人在這里只是提供一個(gè)思想,歡迎大家拍磚!
- Request.UrlReferrer中文亂碼解決方法
- 如何用ajax來(lái)創(chuàng)建一個(gè)XMLHttpRequest對(duì)象
- c# HttpWebRequest通過(guò)代理服務(wù)器抓取網(wǎng)頁(yè)內(nèi)容應(yīng)用介紹
- Javascript Request獲取請(qǐng)求參數(shù)如何實(shí)現(xiàn)
- Ajax通訊原理XMLHttpRequest
- jquery ajax學(xué)習(xí)筆記2 使用XMLHttpRequest對(duì)象的responseXML
- JavaScript下通過(guò)的XMLHttpRequest發(fā)送請(qǐng)求的代碼
- javascript一個(gè)無(wú)懈可擊的實(shí)例化XMLHttpRequest的方法
- javascript對(duì)XMLHttpRequest異步請(qǐng)求的面向?qū)ο蠓庋b
- jQuery ajax(復(fù)習(xí))—Baidu ajax request分離版
相關(guān)文章
詳解.NET Core+Docker 開(kāi)發(fā)微服務(wù)
這篇文章給大家分享了.NET Core+Docker 開(kāi)發(fā)微服務(wù)的相關(guān)知識(shí)點(diǎn)內(nèi)容,有興趣的朋友們參考下。2018-09-09
深入學(xué)習(xí).net驗(yàn)證碼生成及使用方法
這篇文章主要介紹了.net驗(yàn)證碼生成及使用方法,先了解驗(yàn)證碼是什么以及其作用,最后分享了如何制作驗(yàn)證碼,內(nèi)容很全面,感興趣的小伙伴們可以參考一下2015-11-11
c#生成圖片縮略圖的類(2種實(shí)現(xiàn)思路)
4個(gè)重載方法,有直接返回Image對(duì)象的,有生成縮略圖,并且保存到指定目錄的,具體祥看下文2013-05-05
.Net6集成IdentityServer4?+AspNetCore?Identity讀取數(shù)據(jù)表用戶且鑒權(quán)授權(quán)管理A
這篇文章主要介紹了.Net6集成IdentityServer4與AspNetCore?Identity讀取數(shù)據(jù)表用戶且鑒權(quán)授權(quán)管理API,IdentityServer4?實(shí)現(xiàn)鑒權(quán)、授權(quán),AspNetCore?Identity實(shí)現(xiàn)數(shù)據(jù)庫(kù)用戶管理表直接生成,下文詳情需要朋友可以參考一下2022-07-07
ASP.NET全棧開(kāi)發(fā)教程之在MVC中使用服務(wù)端驗(yàn)證的方法
這篇文章主要給大家介紹了關(guān)于ASP.NET全棧開(kāi)發(fā)教程之在MVC中使用服務(wù)端驗(yàn)證的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-07-07
ASP.NET下對(duì)cookies的操作實(shí)現(xiàn)代碼
ASP.NET下對(duì)cookies的操作實(shí)現(xiàn)代碼,需要的朋友可以參考下。2011-10-10
Opencv2.4.13與Visual Studio2013環(huán)境搭建配置教程
這篇文章主要為大家詳細(xì)介紹了Opencv2.4.13 與Visual Studio2013環(huán)境搭建配置教程的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03
使用正則Regex來(lái)移除網(wǎng)頁(yè)的EnableViewState實(shí)現(xiàn)思路及代碼
創(chuàng)建好網(wǎng)頁(yè)時(shí),什么都沒(méi)有寫(xiě),但運(yùn)行時(shí)會(huì)發(fā)現(xiàn)源程序(View Source),下面一段,此刻,也許你會(huì)想起,在網(wǎng)頁(yè)有一個(gè)屬性EnableViewState,在某些時(shí)候我們并不需要它,接下來(lái)將介紹如何移除它,感興趣的朋友可以了解下啊2013-01-01

