Hello World
Spiga

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

2008-12-22 09:11 by 老赵, 21468 visits

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

有趣的需求

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

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

实现似乎很简单

数据结构中的单向链表可谓无比经典。有人说:单向链表的题目好难啊,没法逆序查找,很多东西都不容易做。有人却说:单向链表既然只能向一个方向遍历,那么变化就会很有限,所以题目不会过于复杂。老赵觉得后者的说法不无道理。例如在现在的问题上,我们如果要在一个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格式进行处理。

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

相关文章

Creative Commons License

本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名赵劼(包含链接),具体操作方式可参考此处。如您有任何疑问或者授权方面的协商,请给我留言

Add your comment

98 条回复

  1. 老赵
    admin
    链接

    老赵 2008-12-21 23:21:00

    越写越长,发作两段了……明天再发。

  2. willsmith3389
    *.*.*.*
    链接

    willsmith3389 2008-12-21 23:36:00

    占坑

  3. 老赵
    admin
    链接

    老赵 2008-12-21 23:39:00

    @willsmith3389
    谢谢,谢谢……

  4. shawnliu
    *.*.*.*
    链接

    shawnliu 2008-12-22 00:16:00

    想法很好 不过感觉不要过滤的地方比要过滤的地方要多

  5. 老赵
    admin
    链接

    老赵 2008-12-22 00:18:00

    @shawnliu
    恰恰相反,根据我的实际经验,很少有不需要过滤的地方
    或者说,很少有过滤后会出错的地方。

  6. 韦恩卑鄙
    *.*.*.*
    链接

    韦恩卑鄙 2008-12-22 07:39:00

    老赵 连密码也不让丫写脏话吧 穆哈哈
    恩 也不一定完全就在第一层就把所有内容屏蔽掉
    在FilterForbiddenWordModule 提供
    Value,Is_Modified_By_Filter,OrinValue 三个属性来让服务器逻辑自己选择如何

  7. 天启
    *.*.*.*
    链接

    天启 2008-12-22 07:47:00

    果然是终极解决方案!

  8. Microshaoft
    *.*.*.*
    链接

    Microshaoft 2008-12-22 07:54:00

    以前用 httpmodule/Global.asax 实现过 恶意字符查找:SQL inject、 XSS Attack
    发现后恶意字符达到一定数量阀值重定向到出错页面
    还实现过urlrewrite
    后来发现效率不行,最后改用 UserControl ,按需控制某些页面请求
    不过现在 .Net 3.5 的 Web.config 默认加载了一堆这玩意,支持wcf之类的
    multia Part 的表单?

  9. xland
    *.*.*.*
    链接

    xland 2008-12-22 07:58:00

    支持下
    期待下文

  10. yzlhccdec
    *.*.*.*
    链接

    yzlhccdec 2008-12-22 08:01:00

    期待下文,我准备用MVC中BinderAttribute类似的方法做,写成Attribute,提供includes和excludes属性

  11. Q.Lee.lulu
    *.*.*.*
    链接

    Q.Lee.lulu 2008-12-22 08:35:00

    头像的照片是不是换了 ?

  12. 紫色永恒
    *.*.*.*
    链接

    紫色永恒 2008-12-22 08:38:00

    啥时候换的照片啊。。年轻了。。

  13. 过路人[未注册用户]
    *.*.*.*
    链接

    过路人[未注册用户] 2008-12-22 08:51:00

    老赵年轻了~

  14. aierong
    *.*.*.*
    链接

    aierong 2008-12-22 08:53:00

    换的照片啊

  15. 老农
    *.*.*.*
    链接

    老农 2008-12-22 09:04:00

    赵老师,我的衣厨是不是您的项目,最近发邮件是不是密集了点.

  16. 福州 老吴[未注册用户]
    *.*.*.*
    链接

    福州 老吴[未注册用户] 2008-12-22 09:04:00

    这样搞会很慢的...我有惨痛的经验

  17. 老赵
    admin
    链接

    老赵 2008-12-22 09:06:00

    --引用--------------------------------------------------
    yzlhccdec: 期待下文,我准备用MVC中BinderAttribute类似的方法做,写成Attribute,提供includes和excludes属性
    --------------------------------------------------------
    嘿,下文正想提这个

  18. 老赵
    admin
    链接

    老赵 2008-12-22 09:06:00

    @韦恩卑鄙
    密码当然可以写脏话,我不是提到提供例外的方式了吗?
    //你的建议的确不错,实现起来也不麻烦。

  19. 老赵
    admin
    链接

    老赵 2008-12-22 09:07:00

    --引用--------------------------------------------------
    福州 老吴: 这样搞会很慢的...我有惨痛的经验
    --------------------------------------------------------
    看你怎么实现了,从事实和理论上来看,这个做法都很恰当,呵呵。

  20. 老赵
    admin
    链接

    老赵 2008-12-22 09:07:00

    --引用--------------------------------------------------
    老农: 赵老师,我的衣厨是不是您的项目,最近发邮件是不是密集了点.
    --------------------------------------------------------
    一周一次,有多吗?有的话请告诉我。

  21. 老赵
    admin
    链接

    老赵 2008-12-22 09:09:00

    --引用--------------------------------------------------
    Q.Lee.lulu: 头像的照片是不是换了 ?
    --------------------------------------------------------
    没错没错……

  22. 老赵
    admin
    链接

    老赵 2008-12-22 09:09:00

    --引用--------------------------------------------------
    Microshaoft: 以前用 httpmodule/Global.asax 实现过 恶意字符查找:SQL inject、 XSS Attack

    发现后恶意字符达到一定数量阀值重定向到出错页面

    还实现过urlrewrite

    后来发现效率不行,最后改用 UserControl ,按需控制某些页面请求

    不过现在 .Net 3.5 的 Web.config 默认加载了一堆这玩意,支持wcf之类的

    multia Part 的表单?
    --------------------------------------------------------
    效率没啥不行的,其实。
    还有这个和.net 3.5加载的东西有什么关系?什么东西?和wcf有什么关系?

  23. 老赵
    admin
    链接

    老赵 2008-12-22 09:10:00

    @紫色永恒
    @aierong
    @过路人
    谢谢,谢谢……

  24. 老赵
    admin
    链接

    老赵 2008-12-22 09:13:00

    现在好像保存发布一下就会顶到最上面去了……感觉还是保留以前的“是否更新”时间比较好……

  25. Leem
    *.*.*.*
    链接

    Leem 2008-12-22 09:14:00

    如果脏字库很庞大,会不会严重影响性能呢?

  26. 老赵
    admin
    链接

    老赵 2008-12-22 09:14:00

    --引用--------------------------------------------------
    天启: 果然是终极解决方案!
    --------------------------------------------------------
    世界上不可能有这种解决方案的……

  27. 老赵
    admin
    链接

    老赵 2008-12-22 09:16:00

    --引用--------------------------------------------------
    Leem: 如果脏字库很庞大,会不会严重影响性能呢?
    --------------------------------------------------------
    这就是具体算法的说法了,与本文的作法无关。我使用前缀树的方式构造索引。
    其实也不会影响性能,更谈不上严重了。

  28. 张蒙蒙
    *.*.*.*
    链接

    张蒙蒙 2008-12-22 09:22:00

    @Jeffrey Zhao
    密码:
    let-us-say-fuck
    let-us-say-shit
    和普通字段fuck aaa;
    你担心fuck都会被替换成**,
    你现在在服务端为密码字段做处理加前缀noffw,
    听起来不错,服务端可以不考虑带noffw的值,但是老赵,这里有两点需要注意的地方,第1如果出现这种noffw-fuck aaa字符,恰巧这段字符不是密码,那么服务端也会放掉不处理,你不要说出现这个可能性底,呵呵。第2看似服务端自己定义前缀不会被客户端恶人自己添加安全了,但是如果恶人真的了解你添加的什么你完蛋了,他会这么说:“noffw-fuck aaa”。
    NameValueCollection 值如果存的是个可以区分字符种类标志的类对象就好了,不是普通字段,可是这个可能又不现实。
    还有一个既然老赵打算在密码前加关键字,要是此刻能把NameValueCollection的值(也许此刻你不能拿到这个东西,或者即时拿到也不是和Request Pipeline中最早的阶段(BeginRequest)相同,)替换**,此刻你是可以知道什么是密码的,不是密码的不用换。可是这个好像不行,也即NameValueCollection的值好像和BeginRequest时的值不一致吧。

  29. 王国金
    *.*.*.*
    链接

    王国金 2008-12-22 09:25:00

    等待下文啊。支持支持!!!

  30. 韦恩卑鄙
    *.*.*.*
    链接

    韦恩卑鄙 2008-12-22 09:27:00

    --引用--------------------------------------------------
    Jeffrey Zhao: @韦恩卑鄙

    密码当然可以写脏话,我不是提到提供例外的方式了吗?

    //你的建议的确不错,实现起来也不麻烦。
    --------------------------------------------------------
    我前面一句的意思是 干脆就不让他写脏话 连密码也不让 嘿嘿

  31. 张蒙蒙
    *.*.*.*
    链接

    张蒙蒙 2008-12-22 09:29:00

    @韦恩卑鄙
    想法不错不过您看public static class ForbiddenWord
    是个静态类,您的属性用的地方是不同的字符串替换时刻,那么静态类的属性如何做到,另外一个地方 ForbiddenWord 本来得到的东西都是一致的就是普通的字符,那么针对这个看似一样的字符你怎么假设有修改和没修过给他们呢。。。。。

  32. 戏水
    *.*.*.*
    链接

    戏水 2008-12-22 09:30:00

    @JeffreyZhao
    呵呵 本来想提几点疑问 ,但仔细看了赵兄的文章 ,觉得我的疑问应该会在下篇文章中得到答案。 如果到时候没有 ,再喝老赵探讨探讨 ^_^

    对于实际的情况Discuz!NT 采用了关键词过滤 + 文本内容特征分析的方法 来过滤 信息中的违禁内容。实际应用的效果还不错,spam 少了很多。 广告时间:Discuz!NT 2.6 Beta已经发布咯 参考:http://nt.discuz.net/showtopic-60652.html

  33. 韦恩卑鄙
    *.*.*.*
    链接

    韦恩卑鄙 2008-12-22 09:31:00

    --引用--------------------------------------------------
    这就是具体算法的说法了,与本文的作法无关。我使用前缀树的方式构造索引。
    其实也不会影响性能,更谈不上严重了。
    --------------------------------------------------------
    恩 好多基础的东西 大家都不太重视
    现在随便拉出来一个都不知道用栈和循环模仿递归调用怎么做。
    前几天还有人问我.net的queue 怎么实现的,我给他看源代码说循环队列他都不懂。。。


  34. 老赵
    admin
    链接

    老赵 2008-12-22 09:33:00

    --引用--------------------------------------------------
    张蒙蒙: @韦恩卑鄙
    想法不错不过您看public static class ForbiddenWord
    是个静态类,您的属性用的地方是不同的字符串替换时刻,那么静态类的属性如何做到,另外一个地方 ForbiddenWord 本来得到的东西都是一致的就是普通的字符,那么针对这个看似一样的字符你怎么假设有修改和没修过给他们呢。。。。。
    --------------------------------------------------------
    要实现总归可以实现的,何必拘泥于我示例里用的FobiddenWord写法……

  35. Joyaspx
    *.*.*.*
    链接

    Joyaspx 2008-12-22 09:34:00

    --引用------------------------------------------------ 过路人: 老赵年轻了~ ------------------------------------------------------ 老赵本年就很年轻吧。印象中好像是84年的

  36. 老赵
    admin
    链接

    老赵 2008-12-22 09:35:00

    --引用--------------------------------------------------
    韦恩卑鄙:
    恩 好多基础的东西 大家都不太重视
    现在随便拉出来一个都不知道用栈和循环模仿递归调用怎么做。
    前几天还有人问我.net的queue 怎么实现的,我给他看源代码说循环队列他都不懂。。。
    --------------------------------------------------------
    的确是个大问题……

  37. 老赵
    admin
    链接

    老赵 2008-12-22 09:35:00

    --引用--------------------------------------------------
    戏水: @JeffreyZhao
    呵呵 本来想提几点疑问 ,但仔细看了赵兄的文章 ,觉得我的疑问应该会在下篇文章中得到答案。 如果到时候没有 ,再喝老赵探讨探讨 ^_^

    对于实际的情况Discuz!NT 采用了关键词过滤 + 文本内容特征分析的方法 来过滤 信息中的违禁内容。实际应用的效果还不错,spam 少了很多。

    广告时间:Discuz!NT 2.6 Beta已经发布咯
    参考:http://nt.discuz.net/showtopic-60652.html
    --------------------------------------------------------
    欢迎高质量广告,hoho。
    现在也可以多提点问题吧,我不一定能想到。
    我提供的是一个“方法”,具体替换时的处理和变化,其实可以自己根据实际情况修改的。

  38. 张蒙蒙
    *.*.*.*
    链接

    张蒙蒙 2008-12-22 09:37:00

    @Jeffrey Zhao
    我能感觉到你打算加修饰判断是否修改,不过修饰自己已经做的说明是被修改过了,我和ForbiddenWord 即是不是静态类也没太大理由来个属性说明这个字段是修改过的啊,因为修没修过是字段自己的属性,还是那句话NameValueCollection的值如果不是普通字符而是一个可以鉴别的对象就好了

  39. 基础课()[未注册用户]
    *.*.*.*
    链接

    基础课()[未注册用户] 2008-12-22 09:47:00

    我怎么觉得老赵的新头像笑的比以前淫荡了,哇哈哈

  40. kwanhong young
    *.*.*.*
    链接

    kwanhong young 2008-12-22 09:48:00

    @戏水
    discuznt不是用正则表达式来扫描用户输入文本的吗?如果关键字表有上万个字,扫描次数明显会增多导致速度下降不说,而且也不能过滤中间插入繁体字或特殊字符的情况

  41. GUO Xingwang
    *.*.*.*
    链接

    GUO Xingwang 2008-12-22 10:02:00

    等待下文!

  42. 老赵
    admin
    链接

    老赵 2008-12-22 10:04:00

    --引用--------------------------------------------------
    张蒙蒙: @Jeffrey Zhao
    我能感觉到你打算加修饰判断是否修改,不过修饰自己已经做的说明是被修改过了,我和ForbiddenWord 即是不是静态类也没太大理由来个属性说明这个字段是修改过的啊,因为修没修过是字段自己的属性,还是那句话NameValueCollection的值如果不是普通字符而是一个可以鉴别的对象就好了
    --------------------------------------------------------
    我还是那句话,只有需要不需要,没有做不做得到。
    至于需不需要是业务关心的,就像是否需要得到过滤前的词,这个不是一句话就能说是无用的阿……

  43. 老赵
    admin
    链接

    老赵 2008-12-22 10:04:00

    --引用--------------------------------------------------
    GUO Xingwang: 等待下文!
    --------------------------------------------------------
    谢谢。

  44. 老赵
    admin
    链接

    老赵 2008-12-22 10:04:00

    --引用--------------------------------------------------
    kwanhong young: @戏水
    discuznt不是用正则表达式来扫描用户输入文本的吗?如果关键字表有上万个字,扫描次数明显会增多导致速度下降不说,而且也不能过滤中间插入繁体字或特殊字符的情况
    --------------------------------------------------------
    如果真是Regex,的确性能会很差,不过我觉得DNT不是带内容分析吗?这不是一个Regex能搞定的。

  45. 老赵
    admin
    链接

    老赵 2008-12-22 10:04:00

    --引用--------------------------------------------------
    基础课(): 我怎么觉得老赵的新头像笑的比以前淫荡了,哇哈哈
    --------------------------------------------------------
    说的好啊

  46. hdl253
    *.*.*.*
    链接

    hdl253 2008-12-22 10:12:00

    期待下文

  47. jetwangsir[未注册用户]
    *.*.*.*
    链接

    jetwangsir[未注册用户] 2008-12-22 10:13:00

    不好用,比如你要过滤fuck这个词
    但是有个人的邮箱是defucke@163.com的
    你怎么办

  48. 另一面[未注册用户]
    *.*.*.*
    链接

    另一面[未注册用户] 2008-12-22 10:14:00

    @Jeffrey Zhao
    你还记得你写过一篇文章提到博客园的浮躁么?
    你希望别人给你提出别的意见,而不是恭维。
    而今天我看到的多是恭维,真的想问有多少是看完你的文章的,是不是简单的回复等待下文比大篇的认真回复要让你好理解,如果你没有时间回复别人的质疑就别轻易的回复,老赵你也浮躁了。

  49. 老赵
    admin
    链接

    老赵 2008-12-22 10:20:00

    --引用--------------------------------------------------
    另一面: @Jeffrey Zhao
    你还记得你写过一篇文章提到博客园的浮躁么?
    你希望别人给你提出别的意见,而不是恭维。
    而今天我看到的多是恭维,真的想问有多少是看完你的文章的,是不是简单的回复等待下文比大篇的认真回复要让你好理解,如果你没有时间回复别人的质疑就别轻易的回复,老赵你也浮躁了。
    --------------------------------------------------------
    我当然那希望别人认真看我的文章。
    不过我觉得奇怪,怎么别人没有认真看我的文章,就变成了我的浮躁了?难道我非要把所有的简单回复都删除,才算我做足了“表面功夫”?
    您看到我哪里没有认真回复别人的质疑?亦或是您觉得我写文章不认真?

  50. 老赵
    admin
    链接

    老赵 2008-12-22 10:21:00

    --引用--------------------------------------------------
    jetwangsir: 不好用,比如你要过滤fuck这个词
    但是有个人的邮箱是defucke@163.com的
    你怎么办
    --------------------------------------------------------
    我文章里不是写着如何不过滤一些字段了吗?当然后文就要提更多方面的东西了。

  51. Kevin-moon
    *.*.*.*
    链接

    Kevin-moon 2008-12-22 10:52:00

    期待下文... (尽快!)

  52. Astar
    *.*.*.*
    链接

    Astar 2008-12-22 10:56:00

    学习

  53. 玉开
    *.*.*.*
    链接

    玉开 2008-12-22 11:14:00

    这和具体需求有关系,出现禁用词就替换在有些产品中是不可接受的。

  54. Selfocus
    *.*.*.*
    链接

    Selfocus 2008-12-22 11:22:00

    其实我是进来学IHttpModule和Array.ForEach的

  55. 谦虚的天下
    *.*.*.*
    链接

    谦虚的天下 2008-12-22 11:24:00

    楼主发福了!!

  56. 戏水
    *.*.*.*
    链接

    戏水 2008-12-22 11:36:00

    @kwanhong young
    请您下一次正确输入我们产品的名称 : Discuz!NT 。这就好比
    叫曹操的时候 不说他的姓 。很不礼貌的!

    @Jeffrey Zhao
    我其实也没别的 最主要的就是关心效率问题 。 毕竟需要过滤的内容可能很多,量大的那几天,真的很难受。 另外 过滤关键字列表可能很庞大 ,这效率问题 不得不考虑啊。 老赵 真诚期待你的高见 ^_^

  57. Henllyee Cui
    *.*.*.*
    链接

    Henllyee Cui 2008-12-22 11:52:00

    老赵,头像换掉了啊,这个很性感啊

  58. 老赵
    admin
    链接

    老赵 2008-12-22 11:52:00

    --引用--------------------------------------------------
    玉开: 这和具体需求有关系,出现禁用词就替换在有些产品中是不可接受的。
    --------------------------------------------------------
    那就自己进行变化,我的文章只是提供了一个方法。
    文章中已经提出一些作法了。

  59. 老赵
    admin
    链接

    老赵 2008-12-22 11:53:00

    --引用--------------------------------------------------
    谦虚的天下: 楼主发福了!!
    --------------------------------------------------------
    今年都减肥70斤了

  60. 老赵
    admin
    链接

    老赵 2008-12-22 11:54:00

    --引用--------------------------------------------------
    戏水: @Jeffrey Zhao
    我其实也没别的 最主要的就是关心效率问题 。 毕竟需要过滤的内容可能很多,量大的那几天,真的很难受。 另外 过滤关键字列表可能很庞大 ,这效率问题 不得不考虑啊。 老赵 真诚期待你的高见 ^_^
    --------------------------------------------------------
    性能和我这个文章内容无关,是算法的关系,我实际中使用前缀树的方式,在内存中构造一棵很大的索引,性能不是问题。

  61. 老赵
    admin
    链接

    老赵 2008-12-22 11:55:00

    --引用--------------------------------------------------
    Henllyee Cui: 老赵,头像换掉了啊,这个很性感啊
    --------------------------------------------------------
    谢谢,谢谢……

  62. glonely11[未注册用户]
    *.*.*.*
    链接

    glonely11[未注册用户] 2008-12-22 12:18:00


    老赵哇...

    黑了,胖了..有味了.

    哈哈.. 顶起先

  63. Leem
    *.*.*.*
    链接

    Leem 2008-12-22 12:42:00

    --引用--------------------------------------------------
    性能和我这个文章内容无关,是算法的关系,我实际中使用前缀树的方式,在内存中构造一棵很大的索引,性能不是问题。
    --------------------------------------------------------
    希望能够深入讲解.

  64. 老赵
    admin
    链接

    老赵 2008-12-22 12:45:00

    @Leem
    嗯,那就试着另开话题。

  65. Microshaoft
    *.*.*.*
    链接

    Microshaoft 2008-12-22 13:43:00

    @Jeffrey Zhao
    我是说 .Net3.5/VS2008 的Web工程的Web.Config
    天然自动就有类似
    <httpModules>
    <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
    </httpModules>
    这样的module, 支持json接口的WCF webservice
    每一个http request都会走这里,性能也许不存在问题

  66. 老赵
    admin
    链接

    老赵 2008-12-22 13:49:00

    @Microshaoft
    httpmodule这个机制肯定不会带来性能问题,带来性能问题的是特定的module是怎么写的。

  67. 青羽
    *.*.*.*
    链接

    青羽 2008-12-22 14:53:00

    看过这样做的:http://www.pxce.com/Article/ShowArticle.asp?ArticleID=7083&Page=1
    另:
    谁能给提供一个脏字库,谢了!

  68. 老赵
    admin
    链接

    老赵 2008-12-22 15:27:00

    @青羽
    它只是跳到错误页面去吧。

  69. 黑羽飘舞
    *.*.*.*
    链接

    黑羽飘舞 2008-12-22 15:27:00

    老赵的这个文章果然有些深度,不过上篇顶多算是开了个序,期待下篇中。

  70. try fuck ![未注册用户]
    *.*.*.*
    链接

    try fuck ![未注册用户] 2008-12-22 15:53:00

    几大发现!
    1、老赵的头像换掉了,老赵憔悴了,尺寸比原来小了一圈!
    2、老赵喜欢fuck……
    3、老赵的我的衣橱是一周发一次邮件

    几大建议!
    1、我的衣橱一周一次确实很多,关键是内容都是女性朋友,而老赵的粉丝一般都是男的!老赵带过去的只是粉丝的数量,实际用户数不多!
    2、过滤应该是在输出的时候用,而不是在提交的时候用,这样就不必担心了,如果遇到要显示用户密码的部分则只需要做一个小的标记就可以了

  71. try fuck ![未注册用户]
    *.*.*.*
    链接

    try fuck ![未注册用户] 2008-12-22 15:54:00

    补充一个建议!
    我的衣橱的广告不要发买什么衣服好!要发,老赵最近在忙什么!看什么书!泡什么妞!吃什么套餐!这样估计回访率高~

  72. 老赵
    admin
    链接

    老赵 2008-12-22 16:26:00

    @try fuck !
    关于过滤应该在输出还是输入时的问题……看情况。
    个人认为很多时候输出时过滤对于性能影响可能略大,而且缓存起来不一定方便。

  73. 坐断东南 笑煞之!!
    *.*.*.*
    链接

    坐断东南 笑煞之!! 2008-12-22 18:01:00

    关键字过滤,
    想法就是将表单的数据与URL传值的数据,进行整理后,再放回原来的Request里面。。但.net的request是不可写入的,实现起来得转转脑子。

    在其他语言里面,像php里面,$_POST,$_GET是可写可读的。
    foreach($_POST as $key=>$val)
    {
    $_POST[$key]=fiter($val);
    }
    拿出来$_POST再行过滤再放到$_POST中去。

  74. VisualStudio
    *.*.*.*
    链接

    VisualStudio 2008-12-22 19:01:00

    学习了……

  75. oahZyerffeJ[未注册用户]
    *.*.*.*
    链接

    oahZyerffeJ[未注册用户] 2008-12-22 20:03:00

    请问如何得到整个HTML的文本(在HTTPMoudle中),或者在别的地方呢?

  76. 老赵
    admin
    链接

    老赵 2008-12-22 20:43:00

    --引用--------------------------------------------------
    坐断东南 笑煞之!!: 关键字过滤,
    想法就是将表单的数据与URL传值的数据,进行整理后,再放回原来的Request里面。。但.net的request是不可写入的,实现起来得转转脑子。

    在其他语言里面,像php里面,$_POST,$_GET是可写可读的。
    foreach($_POST as $key=&gt;$val)
    {
    $_POST[$key]=fiter($val);
    }
    拿出来$_POST再行过滤再放到$_POST中去。
    --------------------------------------------------------
    没错,一个原理

  77. 老赵
    admin
    链接

    老赵 2008-12-22 20:44:00

    --引用--------------------------------------------------
    oahZyerffeJ: 请问如何得到整个HTML的文本(在HTTPMoudle中),或者在别的地方呢?
    --------------------------------------------------------
    Request.Stream吧,我想。
    // 您的名字真好看

  78. Microshaoft
    *.*.*.*
    链接

    Microshaoft 2008-12-22 21:09:00

    @Jeffrey Zhao
    Request.InputStream 仅能得到 post 方法提交的完整的 http 请求的 body
    Response.OutputStream 不能直接取出最终的 html
    httpmodule 参阅
    http://microshaoft.cnblogs.com/archive/2005/12/03/289665.html

  79. oahZyerffeJ[未注册用户]
    *.*.*.*
    链接

    oahZyerffeJ[未注册用户] 2008-12-22 21:26:00

    @Jeffrey Zhao
    void context_EndRequest(object sender, EventArgs e) {
    var app = (sender as HttpApplication);
    System.IO.StreamReader sr = new System.IO.StreamReader(app.Request.);
    var s = sr.ReadToEnd();
    }
    ????
    是酱紫吗?怎么搞?
    读不出来~

    你转过去就变成我了……在线等~

  80. oahZyerffeJ[未注册用户]
    *.*.*.*
    链接

    oahZyerffeJ[未注册用户] 2008-12-22 21:28:00

    没错,outputStream不可读

  81. Indigo Dai
    *.*.*.*
    链接

    Indigo Dai 2008-12-22 21:33:00

    老赵把ASP.NET玩得像庖丁解牛了……佩服

  82. 韦恩卑鄙
    *.*.*.*
    链接

    韦恩卑鄙 2008-12-22 21:39:00

    --引用--------------------------------------------------
    Leem: --引用--------------------------------------------------
    性能和我这个文章内容无关,是算法的关系,我实际中使用前缀树的方式,在内存中构造一棵很大的索引,性能不是问题。
    --------------------------------------------------------
    希望能够深入讲解.
    --------------------------------------------------------
    这就是我说的忽视基本 基础不牢了 其实听到"前缀树"就应该想到大学1年下学期的数据结构和大学3年纪的编译原理

    就算不知道 不是本专业的也要马上去google去搜索算法

    不能等易中天来讲小学语文
    更不能等老赵来普及基础知识

  83. Microshaoft
    *.*.*.*
    链接

    Microshaoft 2008-12-22 21:56:00

    @oahZyerffeJ
    不是处理Request.InputStream

    你可以 override
    public override void Write(byte[] buffer, int offset, int count)
    处理buffer得到 Response 的 Output String
    参阅
    httpmodule 参阅
    http://microshaoft.cnblogs.com/archive/2005/12/03/289665.html

  84. 老赵
    admin
    链接

    老赵 2008-12-22 23:37:00

    @oahZyerffeJ
    肯定有Stream可以读吧,看看API就好。
    // 你到底要读还是写?

  85. 老赵
    admin
    链接

    老赵 2008-12-22 23:38:00

    @Microshaoft
    不过我觉得你的文章里会有性能问题,要处理得东西太多了……

  86. oahZyerffeJ[未注册用户]
    *.*.*.*
    链接

    oahZyerffeJ[未注册用户] 2008-12-23 00:54:00

    @Jeffrey Zhao
    我要的差不多就是Microshaoft说的撒
    而且性能问题其实不大,你就想,Page的后面生命周期那么长都极力说自己是性能优异的,Microshaoft说的肯定问题不大……

  87. Microshaoft
    *.*.*.*
    链接

    Microshaoft 2008-12-23 08:50:00

    @Jeffrey Zhao
    肯定有性能问题

  88. 老赵
    admin
    链接

    老赵 2008-12-23 09:13:00

    --引用--------------------------------------------------
    oahZyerffeJ: @Jeffrey Zhao
    我要的差不多就是Microshaoft说的撒
    而且性能问题其实不大,你就想,Page的后面生命周期那么长都极力说自己是性能优异的,Microshaoft说的肯定问题不大……
    --------------------------------------------------------
    别那么肯定。
    性能问题不是因为生命周期长,生命周期长当然不会有问题,因为基本上都不做事情。
    我说性能低,是因为在某个过程中,做了一件代价太大的事情。你想想看,Microshaoft要对整个输出内容作替换啊。

  89. 疑问[未注册用户]
    *.*.*.*
    链接

    疑问[未注册用户] 2008-12-23 09:13:00

    看不懂这段:
    Array.ForEach(
    collection.GetValues(key),
    v => copy.Add(key, ForbiddenWord.Filter(v)));
    1.=> 是什么?
    2.v是从那来的?

  90. 老赵
    admin
    链接

    老赵 2008-12-23 09:14:00

    @疑问
    您可以去了解一下Lambda Expression

  91. Leem
    *.*.*.*
    链接

    Leem 2008-12-23 12:22:00

    --引用--------------------------------------------------
    韦恩卑鄙: --引用--------------------------------------------------
    Leem: --引用--------------------------------------------------
    性能和我这个文章内容无关,是算法的关系,我实际中使用前缀树的方式,在内存中构造一棵很大的索引,性能不是问题。
    --------------------------------------------------------
    希望能够深入讲解.
    --------------------------------------------------------
    这就是我说的忽视基本 基础不牢了 其实听到&quot;前缀树&quot;就应该想到大学1年下学期的数据结构和大学3年纪的编译原理

    就算不知道 不是本专业的也要马上去google去搜索算法

    不能等易中天来讲小学语文
    更不能等老赵来普及基础知识
    --------------------------------------------------------
    这里我并不是让老赵讲解"前缀树"的概念,而是想了解老赵是具体怎么运用来提高性能的?

  92. 老赵
    admin
    链接

    老赵 2008-12-23 14:47:00

    @Leem
    最简单的使用,一点窍门也没有

  93. 韦恩卑鄙
    *.*.*.*
    链接

    韦恩卑鄙 2008-12-24 00:58:00

    前缀树 就是了解的人一听名字 马上就知道时间空间复杂度是多少的名词 已经没有什么变化可做了

  94. xjb
    *.*.*.*
    链接

    xjb 2008-12-24 22:57:00

    老赵出手果然不一样

  95. Indigo Dai
    *.*.*.*
    链接

    Indigo Dai 2008-12-26 13:15:00

    我在期待哪天能把ASP.NET玩得像老赵这样,hoho……

  96. kkun
    *.*.*.*
    链接

    kkun 2009-01-05 15:16:00

    把我逗乐了~还学到了东西

  97. 阿瑞--16hi
    *.*.*.*
    链接

    阿瑞--16hi 2009-04-13 13:44:00

    效率估计有点问题,用正则来做的话应该稍微高点~

  98. 老赵
    admin
    链接

    老赵 2009-04-13 13:47:00

    @阿瑞--16hi
    “替换方法不在本文的讨论范围内,因此我们就以如下方式进行简单替换”
    “实际过程中使用前缀树的方式”
    如果您仔细看过文章我会很感激地……

发表回复

登录 / 登录并记住我 ,登陆后便可删除或修改已发表的评论 (请注意保留评论内容)

昵称:(必填)

邮箱:(必填,仅用于Gavatar

主页:(可选)

评论内容(大于5个字符):

  1. Your Name yyyy-MM-dd HH:mm:ss

使用Live Messenger联系我