Trim().Split 导致 Contains() 出现问题

Trim().Split causes a problem in Contains()

我正在获取一个字符串并先对其进行修整,然后将其拆分并分配给 string[]。然后,我将数组中的每个元素用于 string.Contains()string.StartsWith() 方法。有趣的是,即使字符串包含元素,Contains() 也不能正常工作。 StartsWith() 的情况也一样。有人知道这个问题吗?

P.S.: 拆分后我修剪了字符串,问题就解决了。

string inputTxt = "tasklist";
string commands = "net, netsh, tasklist";

string[] maliciousConsoleCommands = commands.Trim(' ').Split(',');

for (int i = 0; i < maliciousConsoleCommands.Length; i++) {
    if (inputTxt.StartsWith(maliciousConsoleCommands[i])) {
        return false;
    }
} 

//此代码有效,但不知道为什么以前的代码无效。

string[] maliciousConsoleCommands = commands.Split(',');

for (int i = 0; i < maliciousConsoleCommands.Length; i++) {
    if (inputTxt.StartsWith(maliciousConsoleCommands[i].Trim(' '))) {
        return false;
    }
}

本以为可以正常使用,结果通过拆分后修剪解决了。

看来,你应该 Trim 每个 item :

// ["net", "netsh, "tasklist"]
string[] maliciousConsoleCommands = commands
  .Split(',')                   // "net" " netsh", " tasklist" - note leading spaces
  .Select(item => item.Trim())  // removing leading spaces from each item
  .ToArray();

最后,如果你想测试inputTxt是否是恶意的:

if (commands
      .Split(',')
      .Select(item => item.Trim()) // You can combine Select and Any            
      .Any(item => inputTxt.StartsWith(item))
  return false;

你的分隔符不是逗号字符,它是一个逗号后跟一个白色-space - 所以不要用 ',' 分割,只需用 ", ":[=13 分割=]

string[] maliciousConsoleCommands = commands.Split(new string[] {", "});

这将 return 没有前导的项目 space 因此 trim 将是多余的。

您提供的第一个代码将不起作用,因为您想要 trim 初始字符串,因此 "net, netsh, tasklist" 在 trim 之后将保持不变(没有前导和尾随 spaces),然后用逗号将其拆分将生成具有前导 space 的条目。因此,您会得到意想不到的结果。您应该 trimming after 拆分字符串。

第二个代码也不起作用,因为您在 StartsWith 之后使用 Trim,其中 return bool 值。您不能将 Trim 应用于 bool,此代码甚至不应该编译。

如果命令本身没有空格,另一种拆分方法是使用 ' ' 本身作为分隔符,并丢弃空条目:

var  maliciousConsoleCommands =  commands.Split(new[]{',',' '},StringSplitOptions.RemoveEmptyEntries)
                                         .ToArray();

这避免了每个字符串操作命令生成的临时字符串。

为了让您的代码正常工作,您需要为每个命令使用 Contains,而不是使用 StartWith :

var isSuspicious = maliciousCommands.Any(cmd=>input.Contains(cmd));

甚至:

var isSuspicious = maliciousCommands.Any(input.Contains);

如果您有多个命令,或者输入文本很大,这可能会变得相当慢

正则表达式替代

一种更快的技术是使用正则表达式。这比搜索单个关键字执行速度 很多 :

var regex=new Regex("net|netsh|tasklist");
var isSuspicious=regex.IsMatch(inputTxt);

正则表达式是线程安全的,这意味着它们可以被创建一次并被不同的人重复使用 threads/requests。

通过使用 Match/Matches 而不是 IsMatch,正则表达式可以 return 检测到的实际关键字:

var detection=regex.Match(inputTxt);
if (detection.Success)
{
    var detectedKeyword=detection.Value;
    ....
}

将原始逗号分隔列表转换为正则表达式可以使用单个 String.Replace(", ") 或另一个可以处理任何空白字符的正则表达式来执行:

string commands = "net , netsh, \ttasklist";
var pattern=Regex.Replace(commands,@"\s*,\s*","|").Dump();
var regex=new Regex(pattern);

只检测整个单词

Contains 和原始正则表达式都匹配 tasklist1tasklist。如果模式被单词定界符包围,则可以只匹配整个单词,\b :

@"\b(" + pattern + @")\b"

这将匹配 tasklistnet 但拒绝 tasklist1