Как безопасно обрабатывать пароли в специально написанном командлете 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