【问题标题】:Prevent PowerShell script from being read防止读取 PowerShell 脚本
【发布时间】:2016-10-25 07:32:45
【问题描述】:

我有以下 PowerShell 脚本 (myscript.ps1),我在其中询问用户名和密码。根据用户名和密码,它将文件复制到某个目的地。

$credentials = Get-Credential
if ($credentials.Username -eq "user1" -And $credentials.GetNetworkCredential().password -eq "pass1") 
{ Copy-Item "test1.pdf" "\test\test1.pdf"; } 
else 
{ Copy-Item "test2.pdf" "\test\test2.pdf"; }

要求:我想让这个文件受到保护,这样任何人都无法编辑它并查看用户名和密码。

PS2EXE

我找到了一个解决方案 here,它将 PowerShell 脚本转换为 .exe 文件。当我最初使用 PowerShell 运行脚本时,会出现一个对话框,允许我输入用户名和密码:

生成 .exe 后,当我运行它时,凭据对话框不再出现。相反,控制台显示“凭据:”

我不知道为什么?我希望凭据表单在运行 exe 时仍然出现。请问有什么想法吗?

【问题讨论】:

  • 您无法保护脚本。但是您可以将 uname 和密码保存在加密文件中,并在运行时读取它们。
  • @RyanBemrose 你能给我发一份参考资料吗?
  • 这听起来不安全,脚本需要硬编码的加密密钥,这与拥有密码一样糟糕。为什么不对脚本文件应用 ACL?
  • This article 展示了如何在 Windows 凭据管理器或安全字符串中存储加密密码。您可以在网上搜索“powershell 安全密码”以获取有关将密码存储在加密文件中的其他教程。
  • @Burt_Harris 是否有可以应用的 ACL 允许执行文件但不读取文件?

标签: powershell


【解决方案1】:

问:为什么EXE提示“凭据”?

这不是真正问题的答案,而是基于对 PS2EXE 的猜测/假设,但我希望它有助于消除一些困惑。

简要查看上面链接的 PS2EXE 页面后,该实用程序似乎将脚本编码为 Base64 并将其与轻量级 (?) 自定义 PowerShell 主机捆绑在一起。运行时,我假设 EXE 启动主机,解码脚本并运行它。

问题在于Get-Credential cmdlet 在可能无法与桌面交互的 PS 主机中运行。也就是说,它不能为凭据提供 GUI 提示。因此,它需要在命令行上提示输入 Credential 属性,解释您看到该行为的原因。

使用读取主机的解决方法?

与其尝试使用Get-Credential 来提示输入用户名和密码,您可以接受PS2EXE 似乎正在做的事情并使用Read-Host:

$UserName = Read-Host "Enter username"
$Password = Read-Host "Enter password" -AsSecureString

$Credentials = New-Object System.Management.Automation.PSCredential $UserName,$Password

if ($credentials.Username -eq "user1" -And $credentials.GetNetworkCredential().password -eq "pass1") 
{ ... }

使用-AsSecureString 将隐藏屏幕上的密码。 $Password 变量的类型为 System.Security.SecureString,可用于创建 PSCredential 对象,如图所示。

您需要对此进行测试,但您似乎可以从 shell 读取,但不能从 GUI 提示符读取。

并且要明确一点:这些都不是最佳实践安全性。如果您需要对这些活动进行身份验证/授权,请退后一步,再次查看问题。

使用两个脚本的解决方法?

似乎 PS2EXE 不像普通 PowerShell 那样支持-AsSecureString,即它不隐藏字符。一种可能的解决方法是在一个脚本中收集用户的用户名和密码,然后将它们传递给 PS2EXE 转换的脚本进行处理。

Launch-MyScript.ps1:

$Credentials = Get-Credential
& MyScript.exe $Credentials.Username $Credentials.Password

MyScript.exe(被 PS2EXE 覆盖):

param($Username,$Password)

$Credentials = New-Object System.Management.Automation.PSCredential $Username,$Password

if ($Credentials.Username -eq "user1" -and
  $Credentials.GetNetworkCredential().password -eq "pass1")
{
  ...
}

用户运行 Launch-MyScript.ps1 并完成密码提示。然后使用作为参数传入的用户名和密码自动运行 EXE。请注意,如上所示,密码是安全字符串。测试这个;我没有使用 PS2EXE,所以目前这是一个理论上的解决方案。

如果您无法将 $Password 作为安全字符串对象沿管道传递,您可以在第一个脚本中使用 ConvertFrom-SecureString 将其转换为文本,然后使用 ConvertTo-SecureString 将其转换回来在第二个。

【讨论】:

  • 感谢您的解释。那么当 Credential 属性出现在命令行时我该怎么办呢?
  • 如果命令行提示是可以接受的,那么您可以使用 Read-Host 单独提示输入用户名和密码,并完全放弃使用 PSCredential 对象的任何伪装。
  • 你能告诉我怎么做吗?因为我不熟悉这个。也没有办法将其转换为 .exe 并出现 Get-Credential 表单?
  • 已按答案更新。在我看来,我们在解决你最终想要做的事情上走错了路。
  • 非常感谢。我已经这样做了,但现在我试图掩盖密码,但使用 $Password = Read-Host -assecurestring "Enter password" 没有任何想法?
【解决方案2】:

根据这篇文章http://windowsitpro.com/powershell/protect-your-powershell-scripts,您应该首先通过 Set-ExecutionPolicy AllSigned 将您的执行策略设置为 AllSigned,然后使用 makecert cmdlet 创建证书。

然后您可以使用 Set-AuthenticodeSignature cmdlet 签署单个脚本或使用 .pfx 文件签署看起来更安全的脚本。

希望对你有所帮助。

【讨论】:

  • 我认为问题是关于隐藏脚本内容。签署脚本控制脚本的执行,而不是是否有人可以读取文件内容。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-10
  • 1970-01-01
  • 1970-01-01
  • 2013-11-26
  • 1970-01-01
  • 2014-11-27
  • 2011-01-02
相关资源
最近更新 更多