`
bianku
  • 浏览: 69949 次
  • 性别: Icon_minigender_1
  • 来自: 常州
社区版块
存档分类
最新评论

关键字过滤解决方案

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

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

实现似乎很简单
  数据结构中的单向链表可谓无比经典。有人说:单向链表的题目好难啊,没法逆序查找,很多东西都不容易做。有人却说:单向链表既然只能向一个方向遍历,那么变化就会很有限,所以题目不会过于复杂。老赵觉得后者的说法不无道理。例如在现在的问题上,我们如果要在一个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>
  打开页面,在文本框内填写一些敏感字符并点击按钮:

 

  嗨,效果似乎还不错!

问题来了
  太简单了,是不?

  可惜问题才刚开始:如果业务中有些字段不应该被替换怎么办?例如“密码”。如果我们只做到现在这点,那么密码“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格式进行处理

 

分享到:
评论

相关推荐

    text_rank:Ruby的TextRank解决方案对排名关键字提取的实现

    文字排名 自述文件: : 文档: : ...可扩展架构,可自定义关键字排名的过滤/处理方式 安装 gem install text_rank 要求 Ruby 2.1.2或更高版本 engtagger gem是可选的,但对于TextRank::TokenFi

    基于jquery的给文章加入关键字链接

    综合了一些情况后,感觉使用后台解决的方案行不通。于是我想到了前台脚本解决 思路: 关键字链接的信息任然存放在数据库中,在数据库中有一些字段来保存关键字的信息。 当用户添加,删除,更新关键字的时候,在后台...

    汇智创新教育行业反垃圾邮件解决方案

    可以不需要把垃圾信全部收下来,也不需要做关键字内容过滤,就可以直接拦截95%以上的垃圾邮件和病毒邮件,并且极大提高垃圾邮件的处理速度,并节省大量的系统资源和网络带宽。在实际应用中,单台网关处理能力达到了...

    校园网安全整体解决方案设计.doc

    关键字:校园网系统,管理,设置,软件维护,邮件过滤,入侵监测,防火墙 目 录 1 引言 1 1.1 课题背景 1 1.2 高校校园网的网络现状 1 1.3 校园网安全问题分析 2 1.4校园网安全问题存在的原因 3 2安全解决方案设计 ...

    扩展 Entity Framework支持复杂的过滤条件(多个关键字模糊匹配)

    之前遇到一个棘手的Linq to EF查询的技术问题,现有产品表Product,需要根据多个关键字模糊匹配产品名称, 现将解决方案分享出来。 问题描述 根据需求,我们需要编写如下的SQL语句来查询产品 代码如下: select * ...

    基于Hash表的代码相似度度量

    分别读取两个C++程序文件(p1.cpp, p2.cpp),自行设计哈希函数,分别利用开放地址法和链地址法的冲突解决方案,构建C++语言关键字的Hash表。在扫描源程序的过程中,每遇到关键字就查找相应Hash表,并累加相应关键字...

    解析mysql不重复字段值求和

    在使用mysql时,有时需要查询出某个字段不重复的记录,虽然mysql提供有...所以我花了很多时间来研究这个问题,网上也查不到解决方案。。下面先来看看例子: table id name 1 a 2 b 3 c 4 c 5 b库结构大概

    counsel-etags:快速,节能且功能强大的代码导航解决方案

    快速,节能且功能强大的代码导航解决方案。 它已经在Linux / Windows / macOS上进行了测试。 表中的内容 忽略目录和文件 对Emacs API的依赖性最小 指定多个标签文件 自动更新标签文件 Rust编程语言 列出所有标签 ...

    Document360-crx插件

    语言:English 知识库平台,专为成长中的公司而设计 Chrome浏览器上的一键式知识...子类别和文章★具有左侧或右侧自定义位置的页面上的动态启动标签★根据过去的搜索首选项列出的热门文章★根据文章标题中的关键字过滤搜

    Outpost Firewall Pro v9.1.4652.701.1951.zip

    来自俄罗斯的网络安全解决方案!它为您在网络冲浪时提供了全面的安全防护。具有一般防火墙常有的应用程序访问规则控制以及独特的私人信息保护 (防止密码泄露)、内容管理 (防止您的孩子或员工查看不合适的网页内容...

    基于最小二乘法的电压检测算法设计

    基于最小二乘法的电压检测算法设计 摘要:电压检测是工业自动化中一个重要的任务。传统的电压检测方法通常依赖于...该研究为电压检测和其他类似检测任务提供一种灵活简单的解决方案 关键字:电压检测 最小二乘法 残差

    SMCWBR14T-G无线路由器

    BarricadeTM g 802.11g 108Mbps无线Cable/DSL宽带路由器(SMCWBR14T-G)为您的家庭网络、小型办公室网络提供了完美的网络解决方案。 4个全双工10/100 Mbps自动MDI-MDIX端口,可以连接到PC或交换机,内置了108Mbps...

    158邮件地址搜索专家 v5.0.1.zip

    158邮件地址搜索专家为用户提供全方位的网络营销解决方案,可广泛用于网店推广、网络销售,短期内大幅提高网站访问量;可指定搜索深度,支持多线程搜索,具体设置可参考产品手册和FAQ。 支持大部分主流的搜索引擎的...

    海龟交易java源码-ddia:设计数据密集型应用程序的注意事项

    按关键字/过滤器搜索(搜索索引) 向另一个进程发送消息(流处理) 定期处理大量数据(批处理) 3大问题:可靠性、可扩展性、可维护性 可靠:业务执行、容忍用户错误、访问控制、性能 硬件错误:服务器故障; 软件...

    Sohu-2018-4th-place-solution:2018搜狐内容识别算法大赛-解决方案(4th)

    搜狐-2018年第四名 2018搜狐内容识别算法大赛 概述 前处理 HTML过滤器 分割 额外功能 数据扩充 ...关键字词 提取文字 任务3:图像分类 文字识别 文字分类 区域过滤(CTPN) 在我的博客中查看更多详细信息

    (Jsp项目)自然灾害论坛毕业设计(源码+说明+演示视频).zip

    (Jsp项目)自然灾害论坛毕业设计(源码+说明+演示视频).zip ...当发帖的内容有敏感词汇时,有两种解决方案,第一种是屏蔽帖子,第二种防和谐,即拆字。 14.发帖楼号的设置,还有电梯直达的功能 15.意见建议

    使用distinct在mysql中查询多条不重复记录值的解决办法

    在使用mysql时,有时需要查询出某个字段不重复的记录...所以我花了很多时间来研究这个问题,网上也查不到解决方案,期间把容容拉来帮忙,结果是我们两人都郁闷了。。。。。。。。。 下面先来看看例子: table id name

Global site tag (gtag.js) - Google Analytics