Uma função do PowerShell precisa executar um .exe cuja localização não é conhecida em tempo de design porque faz parte de um pacote NuGet. Se eu executá-lo usando Invoke-Expression
o PSScriptAnalyzer gera um aviso me dizendo para encontrar um método alternativo, no entanto, se eu executá-lo usando, &
não recebo nenhum aviso.
Esta é a função que faz parte de um módulo para executar testes de unidade e gerar um relatório de cobertura de código em uma máquina onde o IDE instalado não suporta cobertura de código (por exemplo, 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;
}
Este é o aviso levantado pelo PSScriptAnalyzer
Invoke-Expression is used. Please remove Invoke-Expression from script and find other options instead.
Os documentos da Microsoft dizem para evitar o uso de Invoke-Expression
Considere cuidadosamente as implicações de segurança. Quando uma string de uma fonte não confiável, como a entrada do usuário, é passada diretamente para Invoke-Expression, comandos arbitrários podem ser executados. Sempre considere primeiro uma solução diferente, mais robusta e segura.
Se eu mudar a linha
Invoke-Expression $reportGeneratorCommand;
para
& $reportGeneratorCommand;
Então o aviso desaparece. Mas certamente isso é tão vulnerável a um ataque de injeção de código quanto Invoke-Expression
? o que estou perdendo?
Editar: substituir as 2 últimas linhas da função pelas & $reportGeneratorPath @argumentArray
sugeridas por @MathiasRJessen simplifica um pouco a função, mas acredito que ainda a deixa vulnerável.
A diferença entre
Invoke-Expression
e os operadores de invocação (&
e.
) é a sintaxe estruturada .Ao contrário
Invoke-Expression
, os operadores aceitam o comando target e os argumentos separadamente , e conforme sugerido nos comentários você deve usá-los assim:Talvez o exemplo a seguir abale suas crenças.
Vamos começar definindo um comando de destino e alguns argumentos fornecidos pelo usuário, incluindo uma tentativa de injeção de comando:
Vamos ver o que acontece quando construímos uma string e a passamos
Invoke-Expression
como você tem feito até agora:Como você pode ver,
Invoke-Expression
avaliei com satisfação tanto o comando de destino quanto oWrite-Host malware
comando anexado no final.Vamos tentar o mesmo com um operador de invocação:
Como você pode ver aqui, todos os argumentos foram passados exatamente assim - sem invocação de nenhum comando adicional injetado pelo chamador.