,,HttpRequest的QueryString属性 的一点认识
我们在开发ASP.NET程序获取查询字符串时,经常会遇到一些url编码问题。
比如:
当然我们一般都是按照提示来把结构版本设置2.0来解决。为什么可以这么解决了,还有没有其它的解决方法了。先让我们看看查询字符串的源代码吧:复制代码代码如下:公共名称值集合查询字符串{ get { if(this ._queryString==null) { this ._ query string=new HttpValueCollection();如果(这个. wr!=null) {这个FillInQueryStringCollection();}这个queryString .make readonly();}如果(这个. flags[1]) {这._flags .明确(1);这个ValidateNameValueCollection(this ._queryString,RequestValidationSource .查询字符串);}还这个. private void FillInQueryStringCollection(){ byte[]query string bytes=this .QueryStringBytesif(queryStringBytes!=null) { if (queryStringBytes .长度!=0) {这个queryString .FillFromEncodedBytes(查询字符串字节,this .QueryStringEncoding);} } else if(!字符串IsNullOrEmpty(这个QueryStringText)) { this ._queryString .FillFromString(这个QueryStringText,true,this .QueryStringEncoding);} } 先让我们插入一点那就是查询字符串默认已经做了全球资源定位器(统一资源定位器)解码。其中HttpValueCollection的FillFromEncodedBytes方法如下复制代码代码如下:内部void fillfrocencodedbytes(byte[]bytes,Encoding Encoding){ int num=(bytes!=null)?字节。长度:0;for(int I=0;i numi ) {字符串潜艇用热中子反应堆(submarine thermal reactor的缩写)字符串str2这个ThrowIfMaxHttpCollectionKeysExceeded();int offset=I;int num 4=-1;while(I num){ byte num 5=bytes[I];if(num 5==0x3d){ if(num 4 0){ num 4=I;} }否则if(num 5==0x 26){ break;}我;} if (num4=0) { str=HttpUtility .UrlDecode(字节,偏移量,num4 -偏移量,编码);str2=HttpUtility .UrlDecode(字节,num4 1,(i - num4) - 1,编码);} else { str=nullstr2=HttpUtility .UrlDecode(字节、偏移量、我偏移量、编码);}基地. Add(str,str 2);if((I==(num-1))(bytes[I]==0x 26)){ base .添加(空,字符串。空);} } } 从这里我们可以看到查询字符串已经为我们做了解码工作,我们不需要写成属性HtmlDecode(请求QueryString['xxx'])而是直接写成请求QueryString['xxx']就好的了。现在让我们来看看你查询字符串的验证,在代码中有复制代码代码如下:如果(这个. flags[1]) {这._flags .明确(1);这个ValidateNameValueCollection(this ._queryString,RequestValidationSource .查询字符串);} 一看这个ValidateNameValueCollection。这个方法名称就知道是干什么的了,验证查询字符串数据;那么在什么情况下验证的了?让我们看看这个. flags[1]在什么地方设置的:复制代码代码如下:public void ValidateInput() { if(!这个. flags[0x8000]) {这个._flags .set(0x 8000);这个.旗帜.集合(1);这个.旗帜.集合(2);这个.旗帜.集合(4);这个.旗帜.集合(0x 40);这个.旗帜.设置(0x 80);这个.旗帜.设置(0x 100);这个.旗帜.设置(0x 200);这个.旗帜.设置(8);} } 而该方法在ValidateInputIfRequiredByConfig中调用,调用代码复制代码代码如下:内部void ValidateInputIfRequiredByConfig(){..if (httpRuntime .RequestValidationMode=版本实用程序.框架40) {这.验证输入();} } 我想现在大家都应该明白为什么错题提示让我们把结构改为2.0了吧。应为在4.0后才验证。
这种解决问题的方法是关闭验证,那么我们是否可以改变默认的验证规则了?让我们看看ValidateNameValueCollection复制代码代码如下:private void ValidateNameValueCollection(NameValueCollection NVC,RequestValidationSource请求集合){ int count=NVC .数数;for(int I=0;我数;i ) { string key=nvc .GetKey(I);if ((key==null) ||!钥匙StartsWith('__ '),StringComparison .序数)){ string str2=nvc .get(I);如果(!字符串IsNullOrEmpty(str2)) { this .ValidateString(str2,key,请求集合);} } } } private void validate string(string value,string collectionKey,RequestValidationSource请求集合){ int numvalue=RemoveNullCharacters(值);如果(!请求验证器目前。IsValidRequestString(this .Context,value,requestCollection,collectionKey,out num)){ string str=集合键'=' ';int startIndex=num-10;if(startIndex=0){ startIndex=0;} else { str=str '.} int length=num 20if(长度=值。长度){长度=值。长度;str=字符串值Substring(startIndex,length-startIndex)" ";} else { str=str值Substring(startIndex,length - startIndex)' . ';} string requestValidationSourceName=GetRequestValidationSourceName(请求集合);抛出new HttpRequestValidationException(SR . GetString(' Dangerous _ input _ detected ',new object[]{ requestValidationSourceName,str });} } 哦?原来一切都明白了,验证是在请求验证器做的。复制代码代码如下:公共类RequestValidator { //字段私有静态请求验证器_自定义验证器;private static readonly LazyRequestValidator _ customValidatorResolver=new LazyRequestValidator(new funcrestvalidator(请求验证器.GetCustomValidatorFromConfig));//方法私有静态请求验证器GetCustomValidatorFromConfig(){ HttpRuntimeSection httpRuntime=runtime config .GetAppConfig().HttpRuntime类型userBaseType=ConfigUtil .GetType(httpRuntime .RequestValidationType,' requestValidationType ',httpRuntime);配置工具.CheckBaseType(请求验证器的类型),userBaseType,' requestValidationType ',httpRuntime);返回(请求验证器)http运行时.createpublicsinstance(用户基本类型);}内部静态void InitializeOnFirstRequest(){请求验证器local 1=_ customValidatorResolver .价值;}私有静态bool IsAtoZ(char c){ return((c=' A ')(c=' Z '))| |((c=' A ')(c=' Z ');}受保护的内部虚拟bool IsValidRequestString(HttpContext context,string value,RequestValidationSource RequestValidationSource,string collectionKey,out int validationfailurendex){ if(RequestValidationSource==RequestValidationSource .headers){ validationfailurendex=0;返回真实}返回!交叉站点描述验证.isdangeroustring(value,out validationfailurendex);} //属性公共静态请求验证器当前{ get { if(_ custom validator==null){ _ custom validator=_ custom validator解析器.价值;} return _ custom validator } set { if(value==null){ throw new ArgumentNullException(' value ');} _ customValidator=value} } }主要的验证方法还是在交叉站点描述验证.isdangeroustring(value,out validationfailurendex);而CrossSiteScriptingValidation是一个内部类,无法修改。
让我们看看CrossSiteScriptingValidation类大代码把复制代码代码如下:内部静态类CrossSiteScriptingValidation {//Fields private static char[]starting chars=new char[]{ ' ',' ' };//方法私有静态bool IsAtoZ(char c){ return((c=' A ')(c=' Z '))| |((c=' A ')(c=' Z ');}内部静态bool IsDangerousString(string s,out int match index){ match index=0;int startIndex=0;while(true){ int num 2=s . IndexOfAny(starting chars,startIndex);if (num2 0) {返回false} if (num2==(s.Length - 1)) {返回false } match index=num 2 char ch=s[num 2];如果(ch!=' '){ if((ch==' ')((IsAtoZ(s[num 2 1])| |(s[num 2 1]=='!'))| |((s[num 2 1]=='/')| |(s[num 2 1]=='?')))){返回true} } else if(s[num 2 1]==' # '){返回true;} startIndex=num 2 1;} }内部静态bool是dangerousurl(string s){ if(string .IsNullOrEmpty)){返回false } s=s . Trim();(同Internationalorganizations)国际组织长度=s . Lengthif(((((长度4))((S[0]==' H ')| |(S[0]==' H ')((S[1]==' T ')|(S[2]=' T ')(((S[2]=' T ')|(S[2]=' T ')((S[3]=' P ')|(S[3]=' P '))((S[4]=':')|((长度5)((s[4]} if(s . index of(':')==-1){返回false}返回真实}内部静态bool是有效的javascriptid(字符串id){ if(!字符串IsNullOrEmpty(id)) {返回代码生成器isvalidlanguageindependentifier(id);}返回true} }结果我们发现# !/?[阿扎兹]这些情况验证都是通不过的。所以我们只需要重写请求验证器就可以了。例如我们现在需要处理我们现在需要过滤查询字符串中k=.的情况复制代码代码如下:公共类CustRequestValidator:请求验证器{ protected override bool IsValidRequestString(HttpContext context,string value,RequestValidationSource RequestValidationSource,string collectionKey,out int validationfailurendex){ validationfailurendex=0;//我们现在需要过滤查询字符串中k=.的情况if(requestValidationSource==requestValidationSource .QueryStringcollectionKey。等于(' k ')值.开头为(" " { return true}返回基地IsValidRequestString(context,value,requestValidationSource,collectionKey,out validationfailurendex);} } httpRuntime requestValidationType=' mv CAPP .CustRequestValidator'/个人在这里只是提供一个思想,欢迎大家拍砖!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。