PowerShell的安全目标

首先,PowerShell不会给被处理的对象任何额外的权限。也就是说,PowerShell仅会在你已拥有的权限主体下处理对象。比如,如果通过图形用户界面操作,你没有在活动目录中创建新用户的权限,那么在PowerShell中你也无法创建该用户。
其次,PowerShell无法绕过既有的权限。比如,想为你的用户部署某个脚本,并希望该脚本能完成某些操作:正常情况下这些用户会由于权限不足无法完成的某些操作,那么该脚本同样不能运行。

Tips:

  • 但还是存在一些其他方法可以使得用户在其他凭据(而非自有凭据)下运行某些命令,通常称这种技术为脚本封装。它是一些商业脚本开发环境的一个特性,比如SAPlEM PrimalScript
  • 创建一个脚本之后,你可以使用打包程序将这个脚本放入到一个可执行文件(.EXE)中。这并不是编码学中的编译过程:这个可执行文件并不是独立的,它需要在PowerShell安装之后才能执行。你也可以通过配置打包程序,将可用的凭据加密到可执行文件中。这样,如果有人运行该可执行文件,其中的脚本会在指定的凭据下被执行,而不依赖当前用户的凭据。

    执行策略和代码签名

    PowerShell中第一个安全措施是执行策略。执行策略是用来管理PowerShell执行脚本的一种计算机范围的设置选项。该策略主要用作防止用户被注入,从而执行一些非法脚本

    设置执行策略

    可以通过运行Get-ExecutionPolicy命令,来查看当前的执行策略。
    默认的执行策略是**Restricted**,该策略会阻止正常脚本的运行。也就是说,默认情况下,可以使用PowerShell进行交互式执行命令,但是不能使用PowerShell执行脚本。如果你尝试执行脚本,会产生错误。

如果想修改当前的执行策略,可以采用下面3种方式之一:
1)以管理员权限运行Set-ExecutionPolicy命令:

  • Set-ExecutionPolicy -ExecutionPolicy _RemoteSigned_
  • 该命令会修改Windows注册表中的HKEY_LOCAL_MACHINE部分。

2)使用组策略对象(GPO)。从WinServer 2008 R2开始,PowerShell相关的设置已经包含在内。

  • 在“本地计算机策略”→用户配置→管理模板→Windows组件→Windows PowerShell中找到PowerShell的设置选项。
  • 当通过组策略对象来配置时,组策略中的设定会覆盖本地的任何设置值(包括Set-ExecutionPolicy)。

3)通过手动运行PowerShell.exe,并且给出-ExecutionPolicy的命令行开关参数。

  • 如果采用这种方式,那么命令中指定的执行策略,会覆盖本地任何设置和组策略中的设置值。

    执行策略值

    可以将执行策略设置为5种值(组策略对象中包含下面列表中的3个选项):

  • **Restricted**:默认选项,除微软提供的一部分配置PowerShell的默认选项的脚本外,不允许执行其他任何脚本。这些脚本中附带微软的数字签名。如果修改这些数字签名,那么这些脚本就再也无法运行了。

  • **AllSigned**:经过受信任的证书颁发机构(CA)设计的数字证书签名之后的任意脚本,均可执行。
  • **RemoteSigned**:可运行本地任何脚本,同时也可以执行受信任的CA签发的数字证书签名之后的远程脚本。
    • “远程脚本”是指存在于远端计算机上的脚本,经常通过通用命名规则(UNC)方式访问这些脚本。
    • 来自网络上的脚本也称为“远程脚本”。Internet Explorer、Firefox和Outlook中提供的可下载的脚本。
  • **Unrestricted**:可以运行所有脚本。不建议使用该设置选项,因为此选项无法提供足够的保护功能。
  • **Bypass**:这个特殊的设定主要是针对应用程序开发人员,他们会将PowerShell嵌入到他们的应用程序中。
    • 这个设定值会忽略已经配置好的执行策略,应当仅在主机应用程序提供了自身的脚本安全层时才使用该选项。最终会告诉PowerShell的是“别担心,安全问题我已经全部搞定”。

微软强烈建议在执行脚本时使用RemoteSigned执行策略,并且仅在需要执行脚本的机器上采用该策略。

  • RemoteSigned策略在安全性和功能之间取得了较好的平衡;
  • AllSigned相对更严格,但是它要求所有脚本都需要被数字签名。

    数字代码签名

    数字代码签名,简称为代码签名,是指将一个密码签名应用到一个文本文件的过程。签名会显示在文件末端,并且类似下面的形式。
    image.png
    签名中包含了两部分重要信息:一是列出了对脚本签名的公司或者组织;二是包含了对脚本的加密副本,并且PowerShell可以解密该副本。

在创建一个数字签名之前,需要拥有一个代码签名的证书,这些证书也被称为第三类证书。这些证书均由商业CA签发,比如Cybertrust、GoDaddy、Thawte、VeriSign等公司。当然,如果可能的话,你也可以从公司内部的公钥基础设施(PKI)中获取到该证书。
正常情况下,第三类证书仅会签发给公司或者组织,而不会发给个人。当然,在公司内部可以签发给个人。
在签发证书之前,CA需要验证接收方的身份——证书类似一种数字识别卡,该卡上列出了持有者的姓名以及其他详细信息。比如,在签发证书给XYZ公司之前,CA需要验证XYZ公司的授权代表人提交了该请求。在整个安全体系中,验证过程是其中最重要的环节,你应当仅信任能出色完成验证申请证书的公司身份工作的CA。

应当在Windows的IE属性控制面板(也可以在组策略中配置)中配置信任关系。在该控制面板中,选择Content标签页,然后单击Publishers按钮。在弹出的对话框中,选择“受信任的根证书颁发机构”标签页。如图所示,可以看到计算机信任的CA列表。
image.png
当你信任一个CA之后,你也会信任该CA签发的所有证书。如果有人使用一个证书对恶意脚本进行签名,那么你可以通过该证书去查找该脚本的作者——这也就是为什么已签名的脚本相对于未签名的脚本更加值得“信任”。但是如果你信任一个无法很好验证身份的CA,那么一个恶意脚本的作者可能会获取一个虚假的证书,这样你就无法使用该CA的证书去做追踪。这也就是为什么选择一个受信任的CA是如此重要。

一旦获取了一个三级证书(通常CA会针对不同的操作系统以及不同的编程语言提供不同的证书),之后将该证书安装到本地计算机。安装之后,可以使用PowerShell的Set-AuthenticodeSignature Cmdlet将该数字签名应用到一段脚本。如果需要查看更详细的信息,可以在PowerShell中执行Help About_Signing命令。许多商业的脚本开发环境(PowerShell Studio、PowerShell Plus以及PowerGUI等)都可进行签名,甚至可以在你保存一段脚本时进行自动签名,这样使得签名过程更加透明。

签名实现原理

签名不仅会提供脚本作者的身份信息,也会确保在作者对脚本签名之后,不会被他人更改。实现原理如下。
1)脚本作者持有一个数字证书,该密钥包含两个密钥:一个公钥、一个私钥。
2)当对脚本进行签名时,该签名会被私钥加密。私钥仅能被脚本开发者访问,同时仅有公钥能对该脚本进行解密。在签名中会包含脚本的副本。
3)当PowerShell运行该脚本时,它会使用作者的公钥(包含在签名中)解密该签名。如果解密失败,则说明签名被篡改,那么该脚本就无法被运行。如果签名中的脚本副本与明文文本不吻合,那么该签名就会被识别为损坏,该脚本也无法被运行。

执行脚本处理流程

下图描述了当执行脚本时,PowerShell处理的整个流程。在该流程中,可以看到为什么AllSigned执行策略在某种意义上说更加安全:在该种执行策略下,仅有包含签名的脚本才能被运行,也就意味着,你总是能识别某段脚本的作者。如果需要执行某段脚本,那么就会要求对该脚本进行签名。当然,如果你修改了该脚本,也就需要对该脚本重新签名。
image.png

其他安全措施

PowerShell包含另外两种总是一直有效的重要安全设置。一般情况下,它们应该保持默认值。
首先,Windows不会将PS1文件扩展名视为可执行文件类型。双击打开PS1文件,默认会使用记事本打开进行编辑,而不会被执行。该配置选项会保证即使PowerShell的执行策略允许执行该脚本时,用户也不会在不知晓的情况下运行某段脚本。
其次,在Shell中不能通过键入脚本名称执行该脚本。Shell不会在当前目录中搜索脚本,也就是说,如果有一个名为test.PS1的脚本,切换到该脚本路径下,键入test或者test.PS1都不会运行该脚本。

该安全功能的目的是为了防止称为“命令劫持”的攻击类型。在该攻击中,它会将一个脚本文件放入到一个文件夹中,然后将它命名为某些内置的命令名,比如Dir。在PowerShell中,如果在一个命令前面没有加上其路径——比如运行Dir命令,那么你很明确运行的这个命令的功能;但是如果运行的是.\Dir,那么就会运行一个名为Dir.PS1的脚本。

安全建议

微软建议针对需要运行脚本的计算机,将PowerShell的执行策略设置为RemoteSigned。当然,你也可以考虑设置为AllSigned或者Unrestricted。
AllSigned选项相对来说可能比较麻烦,但是如果采用了下面两条建议,那么该选项会变得更加方便。

  • 如果你没有一个内部的PKI可以提供免费的证书,那么也可以自己制作。
    • 运行Help About_Signing可以查询如何获取以及使用MakeCert.exe,该工具可以用来制作一个本地计算机信任的证书。如果仅需在本地计算机运行脚本,这种方式是较快免费获取一个证书的方式。
    • 根据你所使用的PowerShell版本,你还可以使用一个名称为New-SelfSignedCertificate的cmdlet,也能完成同样的工作。
  • 通过上面提及的编辑器去编辑一段脚本,这些编辑器在每次保存这些脚本时对脚本进行签名。通过这种方式,签名过程更加透明以及自动化,这样对用户来说更加方便。