Как безопасно обрабатывать пароли в специально написанном командлете PowerShell?

Предположим, у меня есть собственный командлет PowerShell, который экспортирует данные и шифрует их с помощью пароля.

[Cmdlet(VerbsData.Export, "SampleData")]
public class ExportSampleData : PSCmdlet
{
    [Parameter(Mandatory = true)]
    public string Password
    {
        get;
        set;
    }

    /* additional parameters */
}

Как правильно обращаться с паролями безопасно? Например, я бы хотел, чтобы значение не отображалось, когда администратор вводит его в консоли. Другие варианты включают чтение файла, который содержит зашифрованный пароль.

Я знаю о PSCredential, но для этого требуется имя пользователя, которое не имеет смысла в этом сценарии.

4 ответа

Решение

Если вы хотите получить только пароль, вы можете использовать

Read-Host командлет с–asSecureString параметр.

Этот параметр маскирует ввод.

Вы можете найти в этом ответе способ шифрования с паролем компьютера (работает на безопасных машинах).

Используя ответ @Christian, вы можете поместить пароль на диск следующим образом:

PS > $cred.Password | ConvertFrom-SecureString | Set-Content c:\temp\password.txt

И получить это с:

$password = Get-Content c:\temp\password.txt | ConvertTo-SecureString
$cred = New-Object System.Management.Automation.PsCredential "UserName",$password

Если вы пишете командлет C# PowerShell и один из параметров требует от пользователя ввода пароля, его следует запутать.

Для этого нужно быть using System.Security;

И тогда ваш тип параметра должен быть SecureString,

Итак, используя ваш пример:

[Cmdlet(VerbsData.Export, "SampleData")]
public class ExportSampleData : PSCmdlet
{
    [Parameter(Mandatory = true)]
    public SecureString Password
    {
        get;
        set;
    }

/* additional parameters */
}

Измените тип параметра Password на SecureString; если администратор пропускает параметр -Password, PowerShell поступит правильно, предложив администратору ввести обязательный параметр и отобразив при этом звездочку.

В идеале реализация вашего командлета передаст SecureString некоторому API, который изначально поддерживает SecureString (наиболее безопасный); если нет, вам придется извлечь пароль из SecureString. Вот хорошая статья о том, как это сделать: Как правильно конвертировать SecureString в String

SecureString-Handling дает вам ощущение большей безопасности, даже если это не так. Вы можете легко зашифровать любую SecureString вот так...

$mrsh = [System.Runtime.InteropServices.Marshal]
$ptr  = $mrsh::SecureStringToBSTR($secureString)
$pass = $mrsh::PtrToStringAuto($ptr)

или даже без маршалинга только с таким объектом webclient...

$cred = Get-Credential
$web = [Net.WebClient]::new()
$web.Credentials = [System.Net.NetworkCredential]::new($cred.UserName,$cred.Password)
$pass = $web.Credentials.Password 

Итак, в целом ни пароль, ни SecureString-Password не должны храниться постоянно в виде файла или чего-либо еще. Сделайте время жизни этой информации как можно короче - например, от ввода пароля до очистки парольной переменной и всех ее унаследованных переменных, например:

Remove-Variable pass, cred, web -ea 0 
Другие вопросы по тегам