Преобразование защищенной строки в обычный текст

87

Я работаю в PowerShell, и у меня есть код, который успешно преобразует введенный пользователем пароль в обычный текст:

$SecurePassword = Read-Host -AsSecureString  "Enter password" | convertfrom-securestring | out-file C:\Users\tmarsh\Documents\securePassword.txt

Я пробовал несколько способов вернуть его обратно, но ни один из них не работает должным образом. Совсем недавно я пробовал следующее:

$PlainPassword = Get-Content C:\Users\tmarsh\Documents\securePassword.txt

#convert the SecureString object to plain text using PtrToString and SecureStringToBSTR
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($PlainPassword)
$PlainPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
[Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR) #this is an important step to keep things secure

Это тоже дает мне ошибку.

Cannot convert argument "s", with value: "01000000d08c9ddf0115d1118c7a00c04fc297eb0100000026a5b6067d53fd43801a9ef3f8ef9e43000000000200000000000366000
0c0000000100000008118fdea02bfb57d0dda41f9748a05f10000000004800000a000000010000000c50f5093f3b87fbf9ee57cbd17267e0a10000000833d1d712cef01497872a3457bc8
bc271400000038c731cb8c47219399e4265515e9569438d8e8ed", for "SecureStringToBSTR" to type "System.Security.SecureString": "Cannot convert the "01000000
d08c9ddf0115d1118c7a00c04fc297eb0100000026a5b6067d53fd43801a9ef3f8ef9e430000000002000000000003660000c0000000100000008118fdea02bfb57d0dda41f9748a05f10
000000004800000a000000010000000c50f5093f3b87fbf9ee57cbd17267e0a10000000833d1d712cef01497872a3457bc8bc271400000038c731cb8c47219399e4265515e9569438d8e8
ed" value of type "System.String" to type "System.Security.SecureString"."
At C:\Users\tmarsh\Documents\Scripts\Local Admin Script\PlainTextConverter1.ps1:14 char:1
+ $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($PlainPassw ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodException
    + FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument

Cannot find an overload for "PtrToStringAuto" and the argument count: "1".
At C:\Users\tmarsh\Documents\Scripts\Local Admin Script\PlainTextConverter1.ps1:15 char:1
+ $PlainPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodException
    + FullyQualifiedErrorId : MethodCountCouldNotFindBest

Cannot convert argument "s", with value: "", for "ZeroFreeBSTR" to type "System.IntPtr": "Cannot convert null to type "System.IntPtr"."
At C:\Users\tmarsh\Documents\Scripts\Local Admin Script\PlainTextConverter1.ps1:16 char:1
+ [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR) #this is an important ste ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodException
    + FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument

Password is:  01000000d08c9ddf0115d1118c7a00c04fc297eb0100000026a5b6067d53fd43801a9ef3f8ef9e430000000002000000000003660000c0000000100000008118fdea02bfb57d0dda41f97
48a05f10000000004800000a000000010000000c50f5093f3b87fbf9ee57cbd17267e0a10000000833d1d712cef01497872a3457bc8bc271400000038c731cb8c47219399e4265515e9569
438d8e8ed

Кто-нибудь знает способ, который сработает для этого?

марш
источник

Ответы:

115

Вы близки, но передаваемый параметр SecureStringToBSTRдолжен быть SecureString. Кажется, вы передаете результат ConvertFrom-SecureString, который является зашифрованной стандартной строкой. Поэтому позвоните ConvertTo-SecureStringпо этому поводу, прежде чем переходить к SecureStringToBSTR.

$SecurePassword = ConvertTo-SecureString $PlainPassword -AsPlainText -Force
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecurePassword)
$UnsecurePassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
MatthewG
источник
4
Я рад, что это работает. Будьте осторожны со своей строкой, теперь это незащищенная строковая переменная, содержащая предположительно что-то важное, например пароль - она ​​больше не защищена в вашей памяти процесса и т. Д.
MatthewG
19
Согласно документации Marshal.SecureStringToBSTR : поскольку этот метод выделяет неуправляемую память, необходимую для строки, всегда освобождает BSTR по завершении, вызывая метод ZeroFreeBSTR . Таким образом, вы должны выполнить следующие действия в конце концов: [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR).
Rosberg Linhares
@RosbergLinhares - Поскольку мы (предположительно) сосредоточены на PowerShell, есть ли причина, по которой вы не могли просто так $BSTR = $null?
Orangutech
3
@Orangutech Вы не можете установить только значение переменной $null, потому что здесь мы имеем дело с неуправляемыми объектами. Вы не получите сообщение об ошибке сразу, но я думаю, что со временем у вас могут возникнуть проблемы.
Rosberg Linhares
1
Помимо утечки памяти из-за отсутствия вызова ZeroFreeBSTR() , как уже говорилось, использование PtrToStringAuto()всегда было концептуально ошибочным, и - теперь, когда PowerShell является кроссплатформенным - не работает на Unix-подобных платформах. Так должно было быть всегда PtrToStringBSTR() - см. Этот ответ .
mklement0
81

Вы также можете использовать PSCredential.GetNetworkCredential ():

$SecurePassword = Get-Content C:\Users\tmarsh\Documents\securePassword.txt | ConvertTo-SecureString
$UnsecurePassword = (New-Object PSCredential "user",$SecurePassword).GetNetworkCredential().Password
Николя Мелай
источник
Я протестировал оба метода, и они оба верны.
Максимилиан Бёрсли
10
Проголосовали за это решение, потому что оно более Powershelly.
Джим
1
Используйте System.Management.Automation.PSCredentialв старых версиях PS, когда короткое имя типа не распознается.
marsze
1
Короче:[PSCredential]::new(0, $SecurePassword).GetNetworkCredential().Password
majkinetor
Короче:[System.Net.NetworkCredential]::new("", $SecurePassword).Password
К. Франк
36

Самый простой способ конвертировать обратно в PowerShell

[System.Net.NetworkCredential]::new("", $SecurePassword).Password
Владимир Зеленов
источник
1
Действительно, не нужно проходить PSCredential.
Николас Мелай
Мне нравится такой подход. К вашему сведению, для любителей совместимости, эта перегрузка конструктора SecureStringбыла введена в .Net Framework 4.0. Я пробовал использовать PowerShell v2, (New-Object -TypeName System.Net.NetworkCredential -ArgumentList "u",$SecureString).Passwordно, к сожалению, SecureStringон незаметно конвертируется в файл String. Вызов кажется успешным, но в этом случае Passwordсвойство принимает буквальное значение «System.Security.SecureString». Быть осторожен.
Джон Рис,
17

В PS 7 вы можете использовать ConvertFrom-SecureStringи -AsPlainText:

 $UnsecurePassword = ConvertFrom-SecureString -SecureString $SecurePassword -AsPlainText

https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.security/ConvertFrom-SecureString?view=powershell-7#parameters

ConvertFrom-SecureString
           [-SecureString] <SecureString>
           [-AsPlainText]
           [<CommonParameters>]
Macke
источник
3
Это сводило меня с ума. Я безуспешно пытался использовать этот синтаксис в версии 5.
Тони