PowerShell 函数需要运行一个 .exe,其位置在设计时未知,因为它是 NuGet 包的一部分。如果我使用
Invoke-Expression
运行它,那么 PSScriptAnalyzer 会发出警告,告诉我寻找替代方法,但是如果我使用 &
运行它,那么我不会收到任何警告。
这是一个模块的一部分,用于在安装的 IDE 不支持代码覆盖率的计算机(例如 Visual Studio Community Edition)上运行单元测试并生成代码覆盖率报告。
function Invoke-ReportGenerator {
param (
[Parameter(Mandatory=$true)][string]$testProjectFolder,
[Parameter(Mandatory=$true)][string]$testProjectName,
[Parameter(Mandatory=$true)][string]$assemblyUnderTest,
[Parameter(Mandatory=$false)][string]$coverageXmlFilename,
[Parameter(Mandatory=$false)][string]$reportGeneratorPath
)
if ([System.String]::IsNullOrWhiteSpace($coverageXmlFilename)) {
$coverageXmlFilename = "coverage.opencover.xml";
}
$absoluteOutputPath = [System.IO.Path]::Combine($testProjectFolder, "CodeCoverage");
$absoluteInputPath = [System.IO.Path]::Combine($testProjectFolder, $coverageXmlFilename);
$argumentArray = @(
"-reports:$absoluteInputPath",
"-targetDir:$absoluteOutputPath",
"-title:$testProjectName",
"-assemblyFilters:$assemblyUnderTest"
);
if ([System.String]::IsNullOrWhiteSpace($reportGeneratorPath)) {
$reportGeneratorPath = "$env:USERPROFILE\.nuget\packages\reportgenerator\5.2.4\tools\net6.0\reportgenerator.exe ";
}
$reportGeneratorCommand = "$reportGeneratorPath $argumentArray";
Invoke-Expression $reportGeneratorCommand;
}
这是 PSScriptAnalyzer 发出的警告
Invoke-Expression is used. Please remove Invoke-Expression from script and find other options instead.
Microsoft 文档说避免使用 Invoke-Expression
仔细考虑安全隐患。当来自不受信任源(例如用户输入)的字符串直接传递到 Invoke-Expression 时,可以执行任意命令。始终首先考虑不同的、更强大、更安全的解决方案。
如果我改变线路
Invoke-Expression $reportGeneratorCommand;
到
& $reportGeneratorCommand;
然后警告消失。但这肯定和
Invoke-Expression
一样容易受到代码注入攻击吗?我错过了什么?
编辑:按照@MathiasRJessen的建议,用
& $reportGeneratorPath @argumentArray
替换函数的最后两行稍微简化了函数,但我相信仍然容易受到攻击。
Invoke-Expression
和调用运算符(&
和.
)之间的区别是结构化语法。
与
Invoke-Expression
不同,运算符单独接受目标命令和参数,并且按照注释中的建议,您应该像这样使用它们:
& $command @arguments
但我相信它仍然很脆弱。
也许下面的例子会动摇你的信念。
让我们首先定义一个目标命令和一些用户提供的参数,包括尝试的命令注入:
$command = 'Write-Host'
$arguments = @(
'Legitimate message'
';'
'Write-Host'
'malware'
)
让我们看看当我们构造一个字符串并将其传递给
Invoke-Expression
时会发生什么,就像您到目前为止所做的那样:
PS ~> $expression = "$command $arguments"
PS ~> Invoke-Expression $expression
Legitimate message
malware
如您所见,
Invoke-Expression
愉快地评估了目标命令和最后添加的 Write-Host malware
命令。
让我们尝试使用调用运算符进行相同的操作:
PS ~> & $command @arguments
Legitimate message ; Write-Host malware
正如您在此处看到的,所有参数都按原样传递 - 不调用调用者注入的任何其他命令。