#.net #powershell #cruisecontrol.net #dpapi
#.net #powershell #cruisecontrol.net #dpapi
Вопрос:
У нас есть процесс сборки, которому необходимо расшифровать пароль, который он затем использует для подключения к базе данных. Мы используем API защиты данных (DPAPI) для шифрования пароля в области компьютера на сервере сборки (я вошел в систему с моей собственной учетной записью домена) с помощью PowerShell:
[Security.Cryptography.ProtectedData]::Protect( $passwordBytes, $null, [Security.Cryptography.DataProtectionScope]::LocalMachine );
Расшифровка также выполняется в скрипте PowerShell, который выполняется CruiseControl.NET, запущенный от имени нашего пользователя сборки:
[Security.Cryptography.ProtectedData]::Unprotect( $encryptedbytes, $null, [Security.Cryptography.DataProtectionScope]::LocalMachine );
Однако вызов Unprotect
завершается ошибкой со следующим сообщением: «Ключ недопустим для использования в указанном состоянии».. Согласно документации, эта ошибка может возникнуть при использовании олицетворения, и код олицетворения должен загрузить профиль пользователя.
В целях безопасности пользователю сборки отказано в праве входа в систему через службы терминалов. Чтобы проверить проблему, я вошел на сервер сборки под своим именем, затем использовал runas для открытия командной строки PowerShell от имени пользователя сборки:
runas /profile /user:DOMAINBUILDUSER powershell.exe
Затем я запускаю скрипт PowerShell для снятия защиты / расшифровки пароля и получаю ту же ошибку.
Я использовал Process Monitor для отслеживания любых сбоев или событий отказа в доступе, и их не было.
Я могу расшифровать пароль при входе в систему с моей собственной учетной записью домена.
Что происходит? Профиль моего пользователя сборки не загружается? Есть ли где-нибудь какой-нибудь параметр безопасности, о котором я не знаю, чтобы включить это? Почему я не могу расшифровать пароль?
Ответ №1:
Ошибка разработчика. Оказывается, я шифровал в области CurrentUser, а не в области LocalMachine. Я обновил свой скрипт, и теперь все работает.
Ответ №2:
Вы обращаете внимание на то, как вы кодируете зашифрованный ByteArray в вашем файле. Здесь в разделе я извлекаю способ, которым я делаю это на одном из моих серверов, для строки подключения (я заменяю здесь введенной строкой)
Преобразовать в Base64, чтобы поместить его в конфигурационный файл
Clear-Host
Add-Type -assembly System.Security
$passwordASCII = Read-Host -Prompt "Enter Password"
$bakCryptedPWD_ByteArray = [System.Security.Cryptography.ProtectedData]::Protect( $passwordASCII.tochararray(), $null, [System.Security.Cryptography.DataProtectionScope]::LocalMachine )
Set-Content -LiteralPath c:Temppass.txt -Value ([Convert]::ToBase64String($bakCryptedPWD_ByteArray))
Вернуться к строке, использующей регистр символов ANSI (в пароле могут быть специальные символы)
Clear-Host
Add-Type -assembly System.Security
$resCryptedPWD_ByteArray = [Convert]::FromBase64String((Get-Content -LiteralPath c:Temppass.txt))
$clearPWD_ByteArray = [System.Security.Cryptography.ProtectedData]::Unprotect( $resCryptedPWD_ByteArray, $null, [System.Security.Cryptography.DataProtectionScope]::LocalMachine )
$enc = [system.text.encoding]::Default
$enc.GetString($clearPWD_ByteArray)
Комментарии:
1. Проблема не в этом. Вы получаете ошибку, отличную от моей, если передаете массив байтов, которые не могут быть расшифрованы.