【问题标题】:Store encrypted string in script在脚本中存储加密字符串
【发布时间】:2016-01-31 13:00:37
【问题描述】:

我需要在我的脚本中存储一些 SMTP 服务器的凭据,但我自然不希望密码以明文形式存储。

到目前为止,我一直在像这样加密密码:

"password" | ConvertTo-SecureString -AsPlainText -Force |
    ConvertFrom-SecureString

并在这样的脚本中使用它:

$password = "(the long string generated from above command)"
$username = "Test@testdomain.com"

$cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $username,($password | ConvertTo-SecureString)

但是,在生成 $cred 对象时,我收到以下错误:

ConvertTo-SecureString : 密钥在指定状态下无效。

【问题讨论】:

  • 这可能会有所帮助:stackoverflow.com/questions/7109958/…
  • 您想如何/在哪里使用该脚本?您不能简单地获取加密字符串并在任何地方神奇地解密它而无需提供密钥。对创建加密字符串的用户而言,解密看似有效的原因是因为它通过Data Protection API 绑定到用户密码,Windows 对当前用户透明地处理它。

标签: powershell securestring


【解决方案1】:

删除ConvertFrom-SecureString 并像这样重新加载它:

$Password = "password" | ConvertTo-SecureString -AsPlainText -Force 
$username = "Test@testdomain.com"
$cred = New-Object System.Management.Automation.PsCredential($username, $Password)

【讨论】:

  • 我不想将文件存储在文本文件中 - 我希望它只存储在脚本本身中。
  • @PnP 请注意,默认情况下ConvertTo-SecureString 会将其私钥存储在您用于创建密钥的用户的密钥库中,并且只有该用户将来才能解密密钥。要在不同的环境下进行这项工作,您需要创建自己的密钥(然后需要存储)
  • 但是请注意,如果您要存储密钥,也可以存储密码,因为无论哪种方式,您的安全性都依赖于密钥/密码位置的访问权限。
  • @AnsgarWiechers 你是完全正确的,这确实成为下一个要解决的问题。我发现基于证书的加密可以解决这组问题。因为可以安全地安装和存储证书。
【解决方案2】:

也许在 Carbon 模块中 Protect-StringUnprotect-String 是您正在寻找的。我一直在使用它,而且效果很好。

Carbon 是一个 PowerShell 模块,用于自动配置运行 Windows 7、8、2008 和 2012 的计算机。

【讨论】:

  • 虽然这些链接可能提供相关信息,但您不能保证它们的可用性。请将这些链接中的相关信息添加到您的答案中。
【解决方案3】:

请仔细阅读以下内容并仔细考虑要点,然后再决定这对 OP 解决他的问题没有帮助。

使用 PS 或 .NET 机制对密码进行加密是一种“通过隐蔽实现安全”的情况,除非有一种可靠的方法来存储密钥。 (通常的“稳健方法”是“我所知道的”、“我是什么”(生物识别技术)和“我所拥有的”。)但默默无闻是 OP 似乎要求的安全级别(“我自然而然地不想密码以明文形式存储”)。这并没有错。但与由于编译代码而获得一些隐蔽性的情况不同,PS 情况并非如此。

但是,安全性取决于谁是“攻击者”。如果您正在处理当前用户生成的密码,则当前用户不是攻击者。但是,如果您正在处理由其他实体设置的密码,但您需要用户使用它,但看不到它,那么当前用户是潜在的攻击者。 (这种情况的一个示例:将工作站加入域的脚本需要具有正确的域权限集的用户。您可能希望用户能够作为映像/重新映像其桌面的一部分加入域,但是您不希望他的域用户帐户有权加入域,因此您的脚本使用一组您不希望用户知道的不同凭据)。我猜OP正在询问用户未分配密码的情况。这个答案的其余部分解决了这种情况。

使用 PS/.NET 方法来加密/获取密码,是“通过默默无闻的安全”,因为攻击者只需要在使用密码的位置之前放置一个断点。使用像 $password 这样的变量名,很容易找到设置断点的位置。如果 1) 脚本很短和/或 2) 很明显什么命令需要密码,则隐藏变量名称(例如,调用密码变量 $exectionContext,这是 PS 自动变量的拼写错误)不会起到太大作用。

因此,您可以通过将$password(或任何您称之为var)设置为它的技巧来获得可以说是更好的安全性,而不是以相当透明且易于反转的方案来加密密码终极价值。例如,如果密码是“join-theE_domain”,您可以执行以下操作:

...other script code...
$windowTitle="Install/deinstaller joint script"
...other script code...
$paramName = "-th"
...other script code...
$status = "End main"
...other script code...
$subTitle = $windowTitle.substring(20,4)
...other script code...
$count = 32
...other script code...
# Use a regex in the following to make it more obscure
$fixedStatus = $status -replace "n","_" -replace "o",[string][char]$count
...other script code...
# If cmdlet/cmd doesn't support password as a positional parameter then 
# write a function that calls cmdlet/cmd and takes password as positional parm
cmdlet-that-needs-password "arg value 1" ("$subTitle$paramName"+$fixedStatus) "arg value 3"
...other script code... 
# extra code at the bottom is important to keep someone from 
# just scrolling to bottom of script to see password being used
# This extra code could be just dummy code that doesn't really do anything
# Extra code can be placed throughout the script to make it more obscure
...other script code... 

【讨论】:

  • Powershell 使使用强加密成为一件相当简单的事情。当您可以简单地通过加密保护秘密时,无需使脚本晦涩难懂。默认情况下,加密与用户帐户相关联,因此要插入断点,攻击者需要访问该帐户才能访问解密的机密。如果攻击者可以做到这一点,那么您已经被破坏了。从那时起添加晦涩难懂只会使脚本维护变得更加困难
  • @MichaelB 强加密如果很容易可逆则无济于事(因为密钥不安全)。这里就是这种情况。
  • 发明自己的混淆算法也无济于事。
  • *打哈欠* 报复反对票是 so 蹩脚的。相信我,他们对你的伤害比我更大。祝你有美好的一天。
  • 如何轻松地从加密存储中检索密码?如果没有该帐户的密码(OP 没有说要保护它免受登录用户的影响),并且无论您如何混淆它,您都无法逃避这样一个事实,即在代码中的某个时刻您将拥有表示-credential $No-Really-This-Isnt-A-Credential-Cause-Like-I-Hid-It-Really-Well 的参数 - 任何能够理解如何解包加密的人都会知道如何通过变量回溯。像这样的混淆不会增加安全性,但会增加管理和维护。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-08-19
  • 2014-11-24
  • 2014-05-22
  • 1970-01-01
  • 2016-06-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多