[英]Remove excessive whitespace in user input field
在用于处理(可能是敌对的)用户输入字段的控制器方法中,我具有以下代码:
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");
我的目标是保留换行符以供典型的非恶意使用,并以安全的html编码字符串显示用户输入。 我接受用户输入,将其解析为换行符,并在换行符处放置定界符。 我执行HTML编码,然后重新插入中断。 (我可能会将其更改为将段落重新插入为p标签而不是br,但现在我正在使用br)
现在,实际上插入真正的html中断会使我面临一个微妙的漏洞:Enter键。 那里的regex.replace代码可以去除恶意用户,他们只是站在enter键上并用废话填满页面。
这是针对白色的废话泛滥的一种解决方法,但仍然使我容易受到滥用,例如在页面中输入一个字符,两个换行符,一个字符,两个换行符。
我的问题是一种确定该方法是否滥用并在验证时失败的方法。 我担心可能没有简单的过程方法可以执行此操作,而是需要启发式技术或贝叶斯过滤器。 希望有人有一个更简单,更好的方法。
编辑:也许我在问题描述中不清楚,正则表达式可以处理连续看到多个换行符并将其转换为一个或两个的情况。 这个问题解决了。 真正的问题是要区分合法文本和垃圾邮件,如下所示:
一种
一种
一种
想象其中的1000个
一种
一种
一种
一种
听起来您很想使用正则表达式尝试“巧妙地”操作,但是IMO最简单的方法是遍历字符串中的字符,将它们复制到StringBuilder中,然后进行过滤。
任何未通过char.IsWhiteSpace()测试的内容都不会被复制。 (如果其中之一是换行符,请插入<br/>,并且在遇到非空白字符之前,不允许再添加<br/>)。
编辑
如果要停止用户输入任何旧内容,请立即放弃。 如果用户真的愿意,您将永远找不到一种过滤方法,使用户在不到一分钟的时间内找不到解决方法。
您最好限制输入中的换行符或字符总数。
考虑做些聪明的事情来清理“错误的输入”将花费多少精力,然后考虑这种情况发生的可能性。 可能没有意义。 可能您真正需要的所有消毒措施都是确保数据合法(对于您的系统来说,它不是太大,不能删除或转义所有危险字符,等等)。 (这就是论坛拥有人工主持人的原因,他们可以根据适当的条件过滤帖子)。
我将对字符串进行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
。
与其尝试用过滤后的文本替换换行符,然后尝试使用正则表达式,不如在插入<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
这不是处理此问题的最有效方法,也不是最聪明的(免责声明),
但是,如果您的文字不是太大 ,就没有多大意义,而且缺少任何更智能的算法(请注意:尽管您可以在行len上设置一个限制,但是很难检测到char\\nchar\\nchar\\n...
类的东西)
您可以只用白色字符Split
(添加所有您能想到的,少于\\ n的字符)-然后仅Join
一个空格 然后在
\\n
上分割(以获取行)-与<br />
加入。 连接线时,您可以测试line.Length > 2
例如。
为了使其更快,您可以使用更高效的算法,逐个字符,使用IndexOf等进行迭代。
同样,这不是处理此问题的最有效或最完美的方法,但可以快速为您提供帮助。
编辑:过滤“相同的线”-您可以使用例如DistinctUntilChanged
来自Ix - Interactive extensions
(请参阅我认为的NuGet Ix实验),它应该连续过滤“相同的线” +您可以为这些添加线测试。
受到slashdot.org的评论过滤器启发的随机建议:使用System.IO.Compression.DeflateStream压缩用户输入,并且如果与原始输入相比太小(您必须做一些实验才能找到有用的截止)拒绝它。
问题未解决?试试以下方法:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.