导入凭据时,Import-Clixml 中是否有任何隐含的假设?
Are there any implicit assumptions in Import-Clixml when importing credentials?
我想知道是否有任何隐含的假设可能会导致代码出现故障?
我想避免使用 Import-Clixml cmdlet 是有原因的吗?
因此,我开发了一个替代方案,即一系列命令,旨在从使用 Export-Clixml 创建的 CliXml 文件中提取用户名和密码。
它现在可以工作,但我不确定拆分解决方案是否可靠。
$credFileUriBld = [UriBuilder]::New('file','localhost',-1,"MyCredentials.xml"))
$credFile = [Xml.XMLDocument]::New()
$nsMgr4ps1xml = [Xml.XmlNamespaceManager]::New($credFile.NameTable)
$nsMgr4ps1xml.AddNamespace('ps1xml','http://schemas.microsoft.com/powershell/2004/04')
$credFile.Load($credFileUriBld.Path)
$netCredInfo = [System.Net.NetworkCredential]::New($credFile.SelectSingleNode('/ps1xml:Objs/ps1xml:Obj/ps1xml:Props/ps1xml:S[@N=''UserName'']/text()',$nsMgr4ps1xml).Get_Value(),
($credFile.SelectSingleNode('/ps1xml:Objs/ps1xml:Obj/ps1xml:Props/ps1xml:SS[@N=''Password'']/text()',$nsMgr4ps1xml).Get_Value().Split('00') |
ForEach-Object { if([String]::IsNullOrEmpty($_)) { } else { $_.Trim() } } |
ForEach-Object { [convert]::ToInt32($_,16) } |
ForEach-Object { [convert]::ToChar($_) } |
ForEach-Object -Begin { $ss=[SecureString]::New() } -Process {$ss.AppendChar($_)} -End { $ss }))
$netCredInfo.UserName
$netCredInfo.Password
如果有任何假设使代码不可靠,您能否瞥一眼并提出建议?
您的方法仅适用于类Unix平台[=90]上的PowerShell Core =](macOS,Linux),但出于安全原因不应该在那里使用 - 它不适用于Windows (既不在 Windows PowerShell 中也不在 PowerShell Core 中),因为那里的密码 - 明智地 - 真正加密,而 您的代码假定 未加密 密码存储.
安全警告:
[securestring]
在类 Unix 平台上不提供保护 - 字符存储 未加密 - [securestring]
on Windows only 的加密依赖于 Windows-only DPAPI(数据保护 API)。
[securestring]
通常 不推荐用于新代码 - 参见this Roslyn analyzer recommendation。
如果您在类 Unix 平台上通过 Export-CliXml
将 [securestring]
实例保存到 文件 - 例如使用 Get-Credential | Export-CliXml MyCredentials.xml
- "secure" 数据(密码)可以被任何可以读取文件 的人轻松检索。相比之下,在 Windows 上存储了一个 DPAPI 加密表示,只能由同一台机器上的同一用户解密。
如您的代码所示,在 Unix 上,持久化的 [securestring]
实例只是一个 "byte string",其中包含构成 的字符的 Unicode 代码点纯文本 内容;例如,包含字符串 'test'
的 [securestring]
被持久化为 '7400650073007400'
,可以按如下方式构造:
-join [Text.Encoding]::Unicode.GetBytes('test').ForEach({ $_.Tostring('x2') })
...并转换回来:
[Text.Encoding]::Unicode.GetString([byte[]] ('7400650073007400' -split '(..)' -ne '' -replace '^', '0x'))
简而言之:在类 Unix 平台上(PowerShell Core),不要使用 Get-Credential | Export-CliXml
来保存凭据 -它们将以未加密的方式存储。要提供任何保护,您必须通过 文件权限 .
拒绝其他所有人对该文件的读取访问权限
仅在 Windows 上使用 ,如果您确实需要避免 Import-CliXml
,这里有一个 大大简化的解决方案 那 也应该表现得更好 .
虽然这段代码技术上也可以在类 Unix 平台上运行,但如上所述,它不提供任何保护。
请注意,它需要在 CLIXML 文件中使用 ConvertTo-SecureString
cmdlet in order to convert the DPAPI 加密的密码表示形式到安全字符串([securestring]
实例)。
# Load the CLIXML file into a [System.Xml.XmlDocument] ([xml]) instance.
($credXml = [xml]::new()).Load($PWD.ProviderPath + '\MyCredentials.xml')
# Take an XPath shortcut that avoids having to deal with namespaces.
# This should be safe, if you know your XML file to have been created with
# Get-Credential | Export-CliXml MyCredentials.xml
$username, $encryptedPassword =
$credXml.SelectNodes('//*[@N="UserName" or @N="Password"]').'#text'
$networkCred = [System.Net.NetworkCredential]::new(
$username,
(ConvertTo-SecureString $encryptedPassword)
)
$networkCred.UserName
# $networkCred.Password # CAUTION: This would echo the plain-text password.
我想知道是否有任何隐含的假设可能会导致代码出现故障?
我想避免使用 Import-Clixml cmdlet 是有原因的吗? 因此,我开发了一个替代方案,即一系列命令,旨在从使用 Export-Clixml 创建的 CliXml 文件中提取用户名和密码。 它现在可以工作,但我不确定拆分解决方案是否可靠。
$credFileUriBld = [UriBuilder]::New('file','localhost',-1,"MyCredentials.xml"))
$credFile = [Xml.XMLDocument]::New()
$nsMgr4ps1xml = [Xml.XmlNamespaceManager]::New($credFile.NameTable)
$nsMgr4ps1xml.AddNamespace('ps1xml','http://schemas.microsoft.com/powershell/2004/04')
$credFile.Load($credFileUriBld.Path)
$netCredInfo = [System.Net.NetworkCredential]::New($credFile.SelectSingleNode('/ps1xml:Objs/ps1xml:Obj/ps1xml:Props/ps1xml:S[@N=''UserName'']/text()',$nsMgr4ps1xml).Get_Value(),
($credFile.SelectSingleNode('/ps1xml:Objs/ps1xml:Obj/ps1xml:Props/ps1xml:SS[@N=''Password'']/text()',$nsMgr4ps1xml).Get_Value().Split('00') |
ForEach-Object { if([String]::IsNullOrEmpty($_)) { } else { $_.Trim() } } |
ForEach-Object { [convert]::ToInt32($_,16) } |
ForEach-Object { [convert]::ToChar($_) } |
ForEach-Object -Begin { $ss=[SecureString]::New() } -Process {$ss.AppendChar($_)} -End { $ss }))
$netCredInfo.UserName
$netCredInfo.Password
如果有任何假设使代码不可靠,您能否瞥一眼并提出建议?
您的方法仅适用于类Unix平台[=90]上的PowerShell Core =](macOS,Linux),但出于安全原因不应该在那里使用 - 它不适用于Windows (既不在 Windows PowerShell 中也不在 PowerShell Core 中),因为那里的密码 - 明智地 - 真正加密,而 您的代码假定 未加密 密码存储.
安全警告:
[securestring]
在类 Unix 平台上不提供保护 - 字符存储 未加密 -[securestring]
on Windows only 的加密依赖于 Windows-only DPAPI(数据保护 API)。[securestring]
通常 不推荐用于新代码 - 参见this Roslyn analyzer recommendation。
如果您在类 Unix 平台上通过
Export-CliXml
将[securestring]
实例保存到 文件 - 例如使用Get-Credential | Export-CliXml MyCredentials.xml
- "secure" 数据(密码)可以被任何可以读取文件 的人轻松检索。相比之下,在 Windows 上存储了一个 DPAPI 加密表示,只能由同一台机器上的同一用户解密。如您的代码所示,在 Unix 上,持久化的
[securestring]
实例只是一个 "byte string",其中包含构成 的字符的 Unicode 代码点纯文本 内容;例如,包含字符串'test'
的[securestring]
被持久化为'7400650073007400'
,可以按如下方式构造:-join [Text.Encoding]::Unicode.GetBytes('test').ForEach({ $_.Tostring('x2') })
...并转换回来:
[Text.Encoding]::Unicode.GetString([byte[]] ('7400650073007400' -split '(..)' -ne '' -replace '^', '0x'))
简而言之:在类 Unix 平台上(PowerShell Core),不要使用 Get-Credential | Export-CliXml
来保存凭据 -它们将以未加密的方式存储。要提供任何保护,您必须通过 文件权限 .
仅在 Windows 上使用 ,如果您确实需要避免 Import-CliXml
,这里有一个 大大简化的解决方案 那 也应该表现得更好 .
虽然这段代码技术上也可以在类 Unix 平台上运行,但如上所述,它不提供任何保护。
请注意,它需要在 CLIXML 文件中使用 ConvertTo-SecureString
cmdlet in order to convert the DPAPI 加密的密码表示形式到安全字符串([securestring]
实例)。
# Load the CLIXML file into a [System.Xml.XmlDocument] ([xml]) instance.
($credXml = [xml]::new()).Load($PWD.ProviderPath + '\MyCredentials.xml')
# Take an XPath shortcut that avoids having to deal with namespaces.
# This should be safe, if you know your XML file to have been created with
# Get-Credential | Export-CliXml MyCredentials.xml
$username, $encryptedPassword =
$credXml.SelectNodes('//*[@N="UserName" or @N="Password"]').'#text'
$networkCred = [System.Net.NetworkCredential]::new(
$username,
(ConvertTo-SecureString $encryptedPassword)
)
$networkCred.UserName
# $networkCred.Password # CAUTION: This would echo the plain-text password.