一个较完整的关键字过滤解决方案(上)

如果您希望看到关键字过滤算法的话那么可能就要失望了。博客园中已经有不少关于此类算法的文章(例如这里和这里),虽然可能无法直接满足特定需求,但是已经足够作为参考使用。而本文的目的,是给出一个较为完整的关键字过滤功能,也就是将用户输入中的敏感字符进行替换——这两者有什么区别?那么就请继续看下去吧。:)

有趣的需求

关键字过滤功能自然无比重要,但是如果要在代码中对每个输入进行检查和替换则会是一件非常费神费事的事情。尤其是如果网站已经有了一定规模,用户输入功能已经遍及各处,而急需对所有输入进行关键字过滤时,上述做法更可谓“远水解不了近渴”。这时候,如果有一个通用的办法,呼得一下为整站的输入加上了一道屏障,那该是一件多么惬意的事情。这就是本文希望解决的问题。是不是很简单?我一开始也这么认为,不过事实上并非那么一帆风顺,而且在某些特定条件下似乎更是没有太好的解决方法……

您慢坐,且听我慢慢道来……

实现似乎很简单

数据结构中的单向链表可谓无比经典。有人说:单向链表的题目好难啊,没法逆序查找,很多东西都不容易做。有人却说:单向链表既然只能向一个方向遍历,那么变化就会很有限,所以题目不会过于复杂。老赵觉得后者的说法不无道理。例如在现在的问题上,我们如果要在一个ASP.NET应用程序中做一个统一的“整站方案”,HttpModule似乎是唯一的选择。

思路如下:我们在Request Pipeline中最早的阶段(BeginRequest)将请求的QueryString和Form集合中的值做过滤,则接下来的ASP.NET处理过程中一切都为“规范”的文字了。说干就干,不就是替换两个NameValueCollection对象中的值吗?这再简单不过了:

public class FilterForbiddenWordModule : IHttpModule
{void IHttpModule.Dispose() { }void IHttpModule.Init(HttpApplication context){context.BeginRequest += new EventHandler(OnBeginRequest);}private static void OnBeginRequest(object sender, EventArgs e){var request = (sender as HttpApplication).Request;ProcessCollection(request.QueryString);ProcessCollection(request.Form);}private static void ProcessCollection(NameValueCollection collection){var copy = new NameValueCollection();foreach (string key in collection.AllKeys){Array.ForEach(collection.GetValues(key),v => copy.Add(key, ForbiddenWord.Filter(v)));}collection.Clear();collection.Add(copy);}
}

在BeginRequest阶段,我们将调用ProcessCollection将QueryString和Form两个NameValueCollection中的值使用ForbiddenWord.Filter方法进行处理。ForbiddenWord是一个静态类,其中的Filter方法会将原始字符串中的敏感字符使用“**”进行替换。替换方法不在本文的讨论范围内,因此我们就以如下方式进行简单替换:

public static class ForbiddenWord
{public static string Filter(string original){return original.Replace("FORBIDDEN_WORD", "**");}
}

看似没有问题,OK,随便打开一张页面看看……

Collection is read-only.Description: An unhandled exception occurred during the execution of the current web request... 
Exception Details: System.NotSupportedException: Collection is read-only.

呀,只读……这是怎么回事?不就是一个NameValueCollection吗?在不得不请出.NET Reflector之后,老赵果然发现其中有猫腻……

public class HttpRequest
{ ...public NameValueCollection Form{get{if (this._form == null){this._form = new HttpValueCollection();if (this._wr != null){this.FillInFormCollection();}this._form.MakeReadOnly();}if (this._flags[2]){this._flags.Clear(2);ValidateNameValueCollection(this._form, "Request.Form");}return this._form;}}...
}

虽然HttpRequest.Form属性为NameValueCollection类型,但是其中的_form变量事实上是一个HttpValueCollection对象。而HttpValueCollection自然是NameValueCollection的子类,而造成其“只读”的最大原因便是:

[Serializable]
internal class HttpValueCollection : NameValueCollection
{ ...internal void MakeReadOnly(){base.IsReadOnly = true;} ...
}

IsReadOnly是定义在NameValueCollection基类NameObjectCollectionBase上的protected属性,这意味着如果我们只有编写一个如同NameValueCollection或HttpValueCollection般的子类才能直接访问它,而现在……反射吧,兄弟们。

public class FilterForbiddenWordModule : IHttpModule
{private static PropertyInfo s_isReadOnlyPropertyInfo;static FilterForbiddenWordModule(){Type type = typeof(NameObjectCollectionBase);s_isReadOnlyPropertyInfo = type.GetProperty("IsReadOnly",BindingFlags.Instance | BindingFlags.NonPublic);}...private static void ProcessCollection(NameValueCollection collection){var copy = new NameValueCollection();foreach (string key in collection.AllKeys){Array.ForEach(collection.GetValues(key),v => copy.Add(key, ForbiddenWord.Filter(v)));}// set readonly to false.s_isReadOnlyPropertyInfo.SetValue(collection, false, null);collection.Clear();collection.Add(copy);// set readonly to true.s_isReadOnlyPropertyInfo.SetValue(collection, true, null);}   
}

现在再打开个页面看看,似乎没事。那么就来体验一下这个HttpModule的功效吧。我们先准备一个空的aspx页面,加上以下代码:

<form id="form1" runat="server"><asp:TextBox runat="server" TextMode="MultiLine" /><asp:Button runat="server" Text="Click" />
</form>

打开页面,在文本框内填写一些敏感字符并点击按钮:

1.jpg

嗨,效果似乎还不错!

问题来了

太简单了,是不?

可惜问题才刚开始:如果业务中有些字段不应该被替换怎么办?例如“密码”。如果我们只做到现在这点,那么密码“let-us-say-shit”和“let-us-say-fuck”则会被认为相同——服务器端逻辑接收到的都是“let-us-say-**”。也就是说,我们必须提供一个机制,让上面的HttpModule可以“忽略”掉某些内容。

如果是其他一些解决方案,我们可以在客户端进行一些特殊标记。例如在客户端增加一个“-noffw-password”字段来表示忽略对“password”字段的过滤。不过根据著名的“Don't trust the client”原则,这种做法应该是第一个被否决掉的。试想,如果某些哥们发现了这一点(别说“不可能”),那么想要绕开这种过滤方式实在是一件非常容易的事情。不过我们应该可以把这种“约定”直接运用在字段名上。例如原本我们如果取名为“password”的字段,现在直接使用“-noffw-password”,而HttpModule发现了这种前缀就会放它一马。由于字段的命名完全是由服务器端决定,因此采取这种方式之后客户端的恶人们就无法绕开我们的过滤了。

还有一种情况就是我们要对某些特定的字段采取一些特殊的过滤方式。例如,之前相当长的一段时间内我认为在服务器端反序列化一段JSON字符串是非常不合理的,不过由于AJAX几乎成了事实标准,亦或是现在的Web应用程序经常需要传递一些结构复杂的对象,JSON格式已经越来越多地被服务器端所接受。假如一个字段是表示一个JSON字符串,那么首先我们只应该对它的“值”进行过滤,而忽略其中的“键”。对于这种字段,我们依旧可以使用如上的命名约定来进行忽略。例如,我们可以使用-json-data的方法来告诉服务器端这个字段应该被当作JSON格式进行处理。

如何?其实问题远没有解决。

相关文章

  • 一个较完整的关键字过滤解决方案(上)
  • 一个较完整的关键字过滤解决方案(中)
  • 一个较完整的关键字过滤解决方案(下)

转载于:https://www.cnblogs.com/JeffreyZhao/archive/2008/12/22/filter-forbidden-word-solution.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/262697.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

核能力将定手机浏览器HTML5之争成败

目前&#xff0c;国内手机浏览器市场竞争异常激烈&#xff0c;UC、腾讯、欧朋、海豚等各大手机浏览器品牌频频亮出各自的HTML5跑分一比高下。然而各大厂商的HTML5功力到底有多深却众说纷纭&#xff0c;能否迅速适应对HTML5的支持&#xff0c;对厂商来说面临的可能是实力的巨大挑…

【转】Thunderbird中配置签名

原文网址&#xff1a;https://support.mozilla.org/zh-CN/kb/Thunderbird%E4%B8%AD%E9%85%8D%E7%BD%AE%E7%AD%BE%E5%90%8D “签名”是一块自动附加到每个您发出的消息的文字&#xff08;包括新消息和对收到消息的回复&#xff09;。他们通常用来提供与每个消息有关的附加联系信…

base css

body,ul,ol,dt,dd,img,p,h1,h2,h3,h4,h5,h6,input,textarea,select,fieldset,legend,ul,ol,dl,th{margin: 0;padding: 0; } body {font-family: "微软雅黑";color: #333; } input,img{border: 0;outline: none; } img {display: block; } ul,ol,li{list-style: none …

Windows下的常用的DOS命令

用的DOS命令。 1.dir dir是英文单词directory(目录&#xff09;的缩写&#xff0c;主要用来显示一个目录下的文件和子目录。 [功能]显示指定磁盘、目录中的文件和子目录信息&#xff0c;包括文件及子目录所在磁盘的卷标、文件与子目录的名称、每个文件的大小、文件及目录建立的…

依赖注入Bean属性——手动装配Bean

一、构造方法注入 其中&#xff0c;可以根据不同的参数列表调用不同的重载的构造方法&#xff1b; 其中&#xff0c;基本数据类型没有包&#xff0c;引用类型都有包路径&#xff0c;基本类型对应封装类&#xff1b; 二、通过property标签调用类的set方法注入 三、通过p命名空间…

ADO.NET数据库

ASP.NET提供了ADO.NET技术&#xff0c;它是ASP.NET应用程序与数据库进行交互的一种技术。 ADO.NET技术把对数据库的操作分为几个步骤&#xff0c;并为每个步骤提供对象来封装操作过程&#xff0c;从而使对数据库的操作变得简单易行。 ADO.NET组件通过以下两个主要的组件将数据访…

获取滚动文本框TextArea焦点位置信息

//输入参数&#xff1a;// _mOffset 滚动文本框对象//返回值:// OffsetObject 位置信息对象// length 焦点位置长度// leftValue 滚动文本框从开始到焦点所在位置的文本值// rightValue 滚动文本框从焦点位置到结束的文本值// scrollTop 滚动框位置//更新记录:// 2…

十天学会ASP.Net——(2)

2.Web控件 1&#xff09;WebControl基类属性 参考http://msdn.microsoft.com/zh-cn/library/7zt8s89c 2&#xff09;Form控件&#xff08;很简单&#xff09; 应用&#xff1a;实现如下效果 <form id"form1" runat"server"> <div> 班级:<br…

Spring表达式

一、SpEL 其中&#xff0c;直接写也可以赋值&#xff0c;‘ ’ 单引号引起来后成为一个字符串对象&#xff0c;可以调用String的方法&#xff1b; 二、引用另外一个bean 装配这个类的bean&#xff1a; 1、第一种方法&#xff0c;property标签中使用bean引用 2、使用Spring表达…

sama5d3 环境检测 gpio--yk测试

说明:  &#xff47;&#xff50;&#xff49;&#xff4f;的&#xff2d;&#xff21;&#xff30;关系 yk0--pioA7 yk1--pioA5 yk2--pioA9 yk3--pioA3 yk4--pioA1 yk5--pioA8 (端子从左&#xff0d;&#xff0d;&#xff1e;右 QD--pioA21内部总启动信号&#…

【Vegas原创】X connection to localhost:11.0 broken (explicit kill or server shutdown)解决方法...

以oracle 进入系统&#xff08;不要使用su切换到oracle&#xff09; 执行env 显示 DISPLAYlocalhost:10.0 执行dbca &#xff0c;出现图形界面 转载于:https://www.cnblogs.com/amadeuslee/archive/2009/01/04/3744408.html

关于偏微分

在图像处理里面&#xff0c;偏微分主要体现在能量极小化上面&#xff0c;而这种极小化泛函往往包含变量的微分&#xff0c;所以只要掌握Euler-Lagrange方程就可以知道其演化方程了&#xff0c;而这个方程就是极小化能量泛函的解。辅以梯度下降法之类的迭代策略&#xff0c;和离…

集合属性注入值

一、集合注入&#xff0c;装配bean的时候&#xff0c;即在xml中添加bean的时候 1、List集合 2、set集合&#xff0c;无序&#xff0c;即无索引&#xff0c;所以也无重复&#xff0c; 3、map key-value键值对双列集合&#xff0c;内置接口Entry 4、Properties集合&#xff0c;可…

用C/C++实现倒序输出,以12345为例

用C/C语言实现倒序输出12345,代码如下#include <stdio.h>int main(){ int i12345; int b; for(;i>1;ii/10) { bi%10; printf("%d",b); } return 0;}转载于:https://blog.51cto.com/cheng618/1701515

QuerySyntax(查询语法)

Code/// <summary>/// QuerySyntax&#xff08;查询语法&#xff09;的摘要说明/// </summary>public class QuerySyntax { public int ID { get; set; } public string Name { get; set; } public void QuerySyntaxTest() { List<Quer…

名词解释CPC、CPM、CPA.......[来源于网络]

这几天有点忙&#xff0c;所以没有很多时间把写的东西上传上来&#xff0c;这个拿出来是应一些做市场分析的童鞋的要求&#xff0c;我还记得这是我刚去金山工作时整理的&#xff0c;出处我忘记了&#xff0c;如果有谁知道&#xff0c;别忘记提醒我&#xff0c;这个算是扫盲吧&a…

节流防抖学习与实践

先看看概念 函数防抖(debounce)&#xff1a; 在事件被触发n秒后再执行回调&#xff0c;如果在这n秒内又被触发&#xff0c;则重新计时&#xff1b;典型的案例就是输入搜索&#xff1a;输入结束后n秒才进行搜索请求&#xff0c;n秒内又输入的内容&#xff0c;就重新计时。像是两…

SQL SERVER 与ACCESS、EXCEL的数据转换

熟悉SQL SERVER 2000的数据库管理员都知道&#xff0c;其DTS可以进行数据的导入导出&#xff0c;其实&#xff0c;我们也可以使用Transact-SQL语句进行导入导出操作。在Transact-SQL语句中&#xff0c;我们主要使用OpenDataSource函数、OPENROWSET 函数&#xff0c;关于函数的详…

二、ceph编译源码、单机搭建调试环境

2019独角兽企业重金招聘Python工程师标准>>> 准备一台机器&#xff1a; roottest3:~# cat /proc/version Linux version 3.13.0-32-generic (builddkissel) (gcc version 4.8.2 (Ubuntu 4.8.2-19ubuntu1) ) #57-Ubuntu SMP Tue Jul 15 03:51:08 UTC 2014 一、下载ce…

C#与Unity 数据存储

使用Json存储数据 1.创建Json文件&#xff0c;直接创建txt文件&#xff0c;将后缀名改为xx.json 2.Json文件的数据格式&#xff0c;中括号表示列表&#xff0c;即中括号下的每个逗号隔开的内容都是列表的每个元素&#xff0c;花括号表示对象&#xff0c;冒号前面的表示属性名&a…