1

在我处理(可能是敌对的)用户输入字段的控制器方法中,我有以下代码:

string tmptext = comment.Replace(System.Environment.NewLine, "{break was here}"); //marks line breaks for later re-insertion
tmptext = Encoder.HtmlEncode(tmptext);
//other sanitizing goes in here 
tmptext = tmptext.Replace("{break was here}", "<br />");

var regex = new Regex("(<br /><br />)\\1+");
tmptext = regex.Replace(tmptext, "$1");

我的目标是为典型的非恶意使用保留换行符,并以安全的 htmlencoded 字符串显示用户输入。我接受用户输入,将其解析为换行符,并在换行符处放置一个分隔符。我执行 HTML 编码并重新插入中断。(我可能会将其更改为将段落重新插入为 p 标签而不是 br,但现在我使用的是 br)

现在实际插入真正的 html 中断让我发现了一个微妙的漏洞:回车键。regex.replace 代码用于删除仅站在回车键上并用废话填充页面的恶意用户。

这是对只有白色的大垃圾泛滥的修复,但仍然让我容易受到滥用,例如输入一个字符,两个换行符,一个字符,两个换行符在整个页面上。

我的问题是确定这是滥用并在验证时失败的方法。我担心可能没有简单的程序方法来做到这一点,而是需要启发式技术或贝叶斯过滤器。希望有人有更简单,更好的方法。

编辑:也许我在问题描述中不清楚,正则表达式处理连续看到多个换行符并将它们转换为一个或两个。那个问题就解决了。真正的问题是将合法文本与垃圾泛滥区分开来,如下所示:

一种

一种

一种

...想象一下其中的 1000 个...

一种

一种

一种

一种

4

5 回答 5

0

听起来你很想用正则表达式尝试一些“聪明”的东西,但 IMO 最简单的方法是循环遍历字符串的字符,将它们复制到 StringBuilder,随时过滤。

任何未通过 char.IsWhiteSpace() 测试的内容都不会被复制。(如果其中一个是换行符,则插入一个 <br/> 并且在您遇到非空白字符之前不允许添加更多 <br/>)。

编辑

如果你想阻止用户输入任何旧的废话,现在就放弃吧。如果用户真的想要的话,你永远不会找到一种过滤方式,用户在一分钟内找不到解决办法。

在输入中限制换行数或字符总数会更好。

想想做一些聪明的事情来清理“错误输入”需要付出多少努力,然后考虑发生这种情况的可能性有多大。可能没有意义。可能您真正需要的所有清理工作是确保数据是合法的(对于您的系统来说不会太大而无法处理,所有危险字符都被剥离或转义等)。(这正是论坛有人工版主的原因,他们可以根据任何适当的标准过滤帖子)。

于 2012-04-12T13:26:54.817 回答
0

我将HttpUtility.HtmlEncode字符串,然后将换行符转换为<br/>.

HttpUtility.HtmlEncode(subject).Replace("\r\n", "<br/>").Replace("\r", "<br/>").Replace("\n", "<br/>");

此外,您应该在输出给用户时执行此逻辑,而不是在保存在数据库中时。我对数据库做的唯一验证是确保它被正确转义(除了正常的业务规则)。

编辑:但是,要解决实际问题,您可以使用 Regex 预先用单个换行符替换多个换行符。

subject = Regex.Replace(@"(\r\n|\r|\n)+", @"\n", RegexOptions.Singleline);

我不确定你是否需要RegexOptions.Singleline.

于 2012-04-12T13:34:53.320 回答
0

与其尝试用过滤后的文本替换换行符,然后尝试在其上使用正则表达式,为什么不在插入<br />标签之前清理您的数据呢?不要忘记先清理输入HttpUtility.HtmlEncode

为了尝试连续处理多条短线,这是我最好的尝试:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

class Program {
  static void Main() {
    // Arbirary cutoff used to join short strings.
    const int Cutoff = 6;

    string input =
      "\r\n\r\n\n\r\r\r\n\nthisisatest\r\nstring\r\nwith\nsome\r\n" + 
      "unsanatized\r\nbreaks\r\nand\ra\nsh\nor\nt\r\n\na\na\na\na" +
      "\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na";
    input = (input ?? String.Empty).Trim(); // Don't forget to HtmlEncode it.
    StringBuilder temp = new StringBuilder();
    List<string> result = new List<string>();
    var items = input.Split(
                        new[] { '\r', '\n' },
                        StringSplitOptions.RemoveEmptyEntries)
                     .Select(i => new { i.Length, Value = i });

    foreach (var item in items) {
      if (item.Length > Cutoff) {
        if (temp.Length > 0) {
          result.Add(temp.ToString());
          temp.Clear();
        }

        result.Add(item.Value);
        continue;
      }

      if (temp.Length > 0) { temp.Append(" "); }
      temp.Append(item.Value);
    }

    if (temp.Length > 0) {
      result.Add(temp.ToString());
    }

    Console.WriteLine(String.Join("<br />", result));
  }
}

产生以下输出:

thisisatest<br />string with some<br />unsanatized<br />breaks and a sh or t a a
 a a a a a a a a a a a a a a a a a a a

我敢肯定你已经想出了这个解决方案,但不幸的是你所要求的并不是很直接。

对于那些感兴趣的人,这是我的第一次尝试:

using System;
using System.Text.RegularExpressions;

class Program {
  static void Main() {
    string input = "\r\n\r\n\n\r\r\r\n\nthisisatest\r\nstring\r\nwith\nsome" +
                   "\r\nunsanatized\r\nbreaks\r\n\r\n";
    input = (input ?? String.Empty).Trim().Replace("\r", String.Empty);
    string output = Regex.Replace(
                      input,
                      "\\\n+",
                      "<br />",
                      RegexOptions.Multiline);
    Console.WriteLine(output);
  }
}

产生以下输出:

thisisatest<br />string<br />with<br />some<br />unsanatized<br />breaks
于 2012-04-12T13:35:36.363 回答
0

这不是处理这个问题的最有效方法,也不是最聪明的(免责声明),
但如果你的文本不是太大,那么它并不重要并且缺少任何更智能的算法(注意:很难检测到类似的东西,char\nchar\nchar\n...尽管你可以在行 len 上设置限制)

您可以只Split使用白色字符(添加您能想到的任何字符,除了 \n) - 然后Join只使用一个空格,然后拆分\n(以获取行) - 加入<br />. 在加入线路时,您可以测试line.Length > 2例如或其他内容。

为了使这更快,您可以使用更有效的算法进行迭代,逐个字符,使用 IndexOf 等。

同样不是最有效或最完美的处理方式,但会给你一些快速的东西。

编辑:过滤“相同行”-您可以使用例如DistinctUntilChanged-来自Ix - Interactive extensions(我认为请参阅 NuGet Ix-experimental)应该过滤“相同行”连续+您可以为这些添加行测试。

于 2012-04-12T13:43:26.167 回答
0

一个随机建议,灵感来自 slashdot.org 的评论过滤器:使用 System.IO.Compression.DeflateStream 压缩您的用户输入,如果它与原始文件相比太小(您必须做一些实验才能找到有用的截止)拒绝它。

于 2012-04-12T14:14:27.933 回答