Powershell 脚本数字签名实现方法

脚本很容易被冒名顶替或者更改,因为它们是由纯文本构成的。数字签名为脚本提供了更高的安全性,因为它能确定脚本和脚本的编辑者的唯一性,并且不能被更改。作为脚本的发布者,你能确定你的脚本没有被恶意篡改。即使专家也无能为力,因为这种机制是基于复杂逻辑的。幸运的是,在实际应用中,你不需要深究这些细节,只需要掌握Powershell脚本签名的机制和过程。

准备一个合适的证书

因为不能使用传统的纸质签名给Powershell脚本进行签名,你需要另一个工具“证书”。证书就像一把私有并且安全的钥匙。证书是你的个人电子身份特征。这把私密的钥匙确保只有证书的拥有者使用证书进行脚本签名。

可以通过mmc添加管理单元查看证书,但是在Powershell中有专门查看证书的支持。可以通过虚拟驱动器cert:查看本机支持的证书。

创建自签名证书

创建一个自签名证书,需要用到microsoft的工具,makecert.exe 。这个工具不能单独下载,但是它包含在微软的.NET framework中,如果你的电脑上已经安装了Visual studio 那就方便多了。

开始->所有程序-Microsoft Visual Studio 2010->Visual Studio Tools->Visual Studio 命令提示(2010)

makecert.exe -pe -r -n "cn=MosserPowerShellTestCert" -eku 1.3.6.1.5.5.7.3.3 -ss "my"
Succeeded

这里要稍微注意 -eku 参数:1.3.6.1.5.5.7.3.3,不能是其它,否则证书的预期目的属性就不是代码签名了。
上面创建的证书会自动保存在CurrentUserMy 路径下面。可以在Powershell中查看:

PS E:> ls cert:CurrentUserMy | where {$_.subject -eq "CN=MosserPowerShellTestCert"}

  目录: Microsoft.PowerShell.SecurityCertificate::CurrentUserMy

Thumbprint                Subject
----------                -------
BA61AF0B8A856422AD9EF86104C8CEDB2583A21A CN=MosserPowerShellTestCert

验证代码签名证书

查看支持代码签名的证书
查看证书的签发者,代表,序列号,指纹。

## 查看预期目的为代码签名的证书:
$certs = @(Dir cert:CurrentUserMy -codeSigningCert)
"找到 {0} 个代码签名证书" -f $certs.count
# 找到 1 个代码签名证书

## 选择 刚才创建的证书
$certificate=ls cert:CurrentUserMy | where {$_.subject -eq "CN=MosserPowerShellTestCert"}

## 证书的代表
$certificate.subject
# CN=MosserPowerShellTestCert

## 证书的签发者
$certificate.issuer
# CN=MosserPowerShellTestCert

## 证书的序列号,指纹
$certificate | select SerialNumber,Thumbprint | fl *
# SerialNumber : C23F35EA85D9A5AB466C07A7C0469A78
# Thumbprint  : 586A4332F0528867DA6A0900FCF0938EDD277E22

声明一个证书受信任

你会发现,在你指定证书的类型,颁发者的名称等信息后,证书的原始数据(RawData)会自动生成。这样你不能假冒别人生成一个证书,别人也不能假冒你的名字生成一个证书。如果通过Powershell查看之前生成的证书是否受信任,答案为否。

PS E:> $certificate.Verify()
False

为什么我们刚才生成的证书不受信任呢?我们可以通过一个简单的步骤找到答案。在.NET 中有一个方法:DisplayCertificate()可以通过对话框显示证书,位于System.Security.dll中。这个dll默认没有引用,需要添加引用,之后显示证书对话框。

PS E:> [System.Reflection.Assembly]::LoadWithPartialName("System.Security")

GAC  Version    Location
---  -------    --------
True  v2.0.50727   C:windowsassemblyGAC_MSILSystem.Security2.0.0.0__b03f5f7f11d50a3aSys...

[System.Security.Cryptography.x509Certificates.X509Certificate2UI]::DisplayCertificate($certificate)

Powershell 查看证书 不受信任

对话框提示:此CA根证书不受信任,要启用信任,请将该证书安装到”受信任的根证书颁发机构“存储区。

所以接下来可以将该证书复制到受信任的存储区。可以通过certmgr.msc 手动操作,也可以通过Powershell自动化操作。

PS E:> $rootStore= New-Object system.security.cryptography.X509Certificates.x509Store("root","Curre
ntuser")
$rootStore.Open("ReadWrite")
$rootStore.Add($certificate)
$rootStore.Close()

在执行Add操作时,会有一个确认的对话框,确定即可。

接下来我们查看一下验证信息。

PS E:> $certificate.Verify()
True

给Powershell 脚本签名

给Powershell脚本进行数字签名只需要两步:找的一个受信任的代码签名证书,剩下的工作请交给:Set-AuthenticodeSignature吧。

PS E:> 'Write-Host "我的第一个签名脚本"' > firstSignScript.ps1
PS E:> $certificate=ls cert:CurrentUserMy | where {$_.subject -eq "CN=MosserPowerShellTestCert"}
PS E:> Set-AuthenticodeSignature .firstSignScript.ps1 $certificate

  目录: E:

SignerCertificate            Status Path
-----------------            ------ ----
586A4332F0528867DA6A0900FCF0938EDD277E22 Valid firstSignScript.ps1

PS E:> Get-Content .firstSignScript.ps1
Write-Host "我的第一个签名脚本"

# SIG # Begin signature block
# MIIEIQYJKoZIhvcNAQcCoIIEEjCCBA4CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUnxRdr+yE6sFotfvZjfn8k15W
# OtigggI0MIICMDCCAZ2gAwIBAgIQwj816oXZpatGbAenwEaaeDAJBgUrDgMCHQUA
# MCMxITAfBgNVBAMTGE1vc3NlclBvd2VyU2hlbGxUZXN0Q2VydDAeFw0xMjA2MTYx
# MzAyMjZaFw0zOTEyMzEyMzU5NTlaMCMxITAfBgNVBAMTGE1vc3NlclBvd2VyU2hl
# bGxUZXN0Q2VydDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAr/2eZ6iS3Zi4
# Q2RsXFPRmDynztxPwArZ6SK663R6X2Dfqwv+kuev4VbEHJ20Bvd9yLvCS4QgCCR6
# n0D+ELfBy6aRpst51dNKNGV74TZIBu1M5EKG2+didLrKTx3lwEC66Bl+QyFiOzcH
# ZhQcaZzgdx8m8EN10/B2cDg9Tm9ppQsCAwEAAaNtMGswEwYDVR0lBAwwCgYIKwYB
# BQUHAwMwVAYDVR0BBE0wS4AQjHzaaSg4KlNdyvIpJNjeiqElMCMxITAfBgNVBAMT
# GE1vc3NlclBvd2VyU2hlbGxUZXN0Q2VydIIQwj816oXZpatGbAenwEaaeDAJBgUr
# DgMCHQUAA4GBAFA3lvWcbA8mWndKdIOCzQUbC9/+1vIeQRGaH7L6U6OHZuV2IBw1
# EpLxz1/dyFEMNZmy9z+/YjfJi774UY1eTzOJnz0AYKGPpM0BK2ieGZzPDIlbkpv1
# ywrv5BtRt053MNHRYaZQP0v9Sp6pOB4h10tKnvh0DW882zRPeB4hkK+fMYIBVzCC
# AVMCAQEwNzAjMSEwHwYDVQQDExhNb3NzZXJQb3dlclNoZWxsVGVzdENlcnQCEMI/
# NeqF2aWrRmwHp8BGmngwCQYFKw4DAhoFAKB4MBgGCisGAQQBgjcCAQwxCjAIoAKA
# AKECgAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEO
# MAwGCisGAQQBgjcCARUwIwYJKoZIhvcNAQkEMRYEFMgyEZ64UFors3z9JGuKLVxh
# P2hLMA0GCSqGSIb3DQEBAQUABIGAMHFJHMVlauxKGIo2p9ieFBVp4Am6n533k89j
# 7pQXKOGmU/sG9d8PILifHLJZw7BU66+uZFvOSXlUxvqaPRAdeosc2BLDPf5Cu6o7
# 61BfSJc2H5dQCgbK/90OKmeJp4KJQRCk7HLEBvV23ddVSyl4CPplbUcTVmo92Zd1
# B/Moxro=
# SIG # End signature block

递归给所有脚本文件签名

给当前文件下的所有脚本签名

PS E:> Set-AuthenticodeSignature (ls *.ps1) $certificate

  目录: E:

SignerCertificate            Status Path
-----------------            ------ ----
586A4332F0528867DA6A0900FCF0938EDD277E22 Valid firstSignScript.ps1
586A4332F0528867DA6A0900FCF0938EDD277E22 Valid MyScript.ps1
586A4332F0528867DA6A0900FCF0938EDD277E22 Valid pipeline.ps1
586A4332F0528867DA6A0900FCF0938EDD277E22 Valid PSLib.ps1

如果你喜欢你甚至可以递归使用

Set-AuthenticodeSignature (Dir -recurse -include *.ps1) $certificate

使用对话框选择证书

如果机器上安装了代码签名的证书有许多,你可以通过friendName 或者证书的名称,证书的指纹,过滤一个证书供脚本签名。

 Dir cert:CurrentUserMy |
 where {$_.subject -eq "CN=MosserPowerShellTestCert"}

另一种方法是通过.NET中的内置的对话框进行选择。将查询到的证书传递给SelectFromCollection()方法,在在作此操作之前必须将证书放在一个特殊的集合中。

# 对话框文本:
$title = "可用的证书"
$text = "请选择用于代码签名的证书:"
# Find certificates:
$certificates = Dir cert: -recurse -codeSigningCert
# 加载 System.Security 类库
# 将证书存放在特殊的集合(X509Certificate2Collection)中:
[Reflection.Assembly]::LoadWithPartialName("System.Security")
$collection = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2Collection
$certificates | ForEach-Object { $collection.Add($_) }
# 显示选项:
$certificate =[System.Security.Cryptography.x509Certificates.X509Certificate2UI]::`
SelectFromCollection($collection, $title, $text, 0)
# 使用选择的证书进行数字签名
Set-AuthenticodeSignature -Certificate $certificate[0] -FilePath .firstSignScript.ps1

Powershel l对话框选择 证书

Powershell脚本签名验证

在脚本中签名到底能带来什么好处,那就是可以进行验证。可以手动验证,也可以自动验证。签名验证会告诉你脚本是否信任,或者是否包含了恶意篡改。

用户自行验证:手动验证,可以检查一个脚本是否包含签名代码,签名者是谁?该签名者是否受信任。
自动验证:如果你将Powershell的脚本执行策略设置为AllSigned. Powershell会在你尝试运行脚本时自动验证,代码和脚本签名是否一致。并且会询问签名者是否受信任。

手动验证

Get-AuthenticodeSignature命令可以验证签名。例如创建一个脚本,不进行签名,通过该命令进行验证。属性StatusMessage会告诉你签名验证的结果。

 "'未签名'" >notsign.ps1
$checkResult=Get-AuthenticodeSignature .notsign.ps1
$checkResult.Status
NotSigned
$checkResult.StatusMessage
文件 E:notsign.ps1 未经数字签名。系统将不执行该脚本。有关详细信息,请参阅 "get-help about_signing"
。
$checkResult.Status.GetType().fullName
System.Management.Automation.SignatureStatus

如果运行该未签名的脚本,也会收到错误提示信息,也就是StatusMessage中包含的信息。脚本的验证结果状态包括:

成员名称 描述
HashMismatch 文件的哈希码和存储的签名不匹配
Incompatible 无法验证签名,因为与当前操作系统不兼容
NotSigned 文件没有签名
NotSupportedFileFormat 指定的文件格式不支持的系统签名。这通常意味着系统不知道如何签名或验证文件的类型。
NotTrusted 证书的发布者在系统中不受信任.
UnknownError 文件签名无效
Valid 该文件有一个有效的签名。这意味着只有签名的语法上是合法的。这并不意味着信任。

自动验证

你不须要去验证脚本的签名,当你运行一个脚本时,Powershell会自动验证。即使验证过的脚本,如果有部分内容更新,自动验证也会给出警告。
在用户将脚本执行策略设置为AllSigned和RemoteSigned时,自动验证就会激活,如果将执行策略设置为AllSigned,所有的脚本都会验证。如果你选择RemoteSigned,从网络上下载的脚本执行会提示需要签名。

# 设置 ExecutionPolicy 为 AllSigned. 所有
# 脚本必须有正确的签名:
Set-ExecutionPolicy AllSigned
# 创建一个没有签名的脚本.
# 该脚本不会执行:
无法加载文件 E:unSigned.ps1。文件 E:unSigned.ps1 未经数字签名。系统将不执行该脚本。有关详细信息,
请参阅 "get-help about_signing"。。
所在位置 行:1 字符: 15
+ .unSigned.ps1 < <<<
  + CategoryInfo     : NotSpecified: (:) [], PSSecurityException
  + FullyQualifiedErrorId : RuntimeException

即使签名可以通过验证,也需要用户的批准,才能执行。
.firstSignScript.ps1

是否要运行来自此不可信发布者的软件?
文件 E:firstSignScript.ps1 由 CN=MosserPowerShellTestCert
发布,该文件对于您的系统是不可信的。请只运行来自可信发布者的脚本。
[V] 从不运行(V) [D] 不运行(D) [R] 运行一次(R) [A] 始终运行(A) [?] 帮助 (默认值为“D”): a
我的第一个签名脚本

#第二次执行,不会询问
我的第一个签名脚本

Windows PowerShell显示执行的脚本未进行数字签名。

设置一下可以运行未签名的脚本或者为你的脚本签名。

set-executionpolicy Bypass

到这里文章就结束了,需要的朋友可以参考一下。

(0)

相关推荐

  • Powershell 脚本数字签名实现方法

    脚本很容易被冒名顶替或者更改,因为它们是由纯文本构成的.数字签名为脚本提供了更高的安全性,因为它能确定脚本和脚本的编辑者的唯一性,并且不能被更改.作为脚本的发布者,你能确定你的脚本没有被恶意篡改.即使专家也无能为力,因为这种机制是基于复杂逻辑的.幸运的是,在实际应用中,你不需要深究这些细节,只需要掌握Powershell脚本签名的机制和过程. 准备一个合适的证书 因为不能使用传统的纸质签名给Powershell脚本进行签名,你需要另一个工具"证书".证书就像一把私有并且安全的钥匙.证书

  • 在cmd中直接运行PowerShell脚本文件的方法

    以前在cmd中执行powershell,我们都是这样: 复制代码 代码如下: PowerShell.exe -file a.ps1 现在想在cmd中这样执行: 复制代码 代码如下: a.ps1 此时需要将Powershell脚本的默认打开方式选择为Powershell.exe,可以鼠标右键操作. 也可以使用下面的cmd以管理员权限打开,然后运行命令: 复制代码 代码如下: ftype Microsoft.Powershellscript.1="%SystemRoot%\system32\wind

  • PowerShell 未经数字签名 系统将不执行该脚本

    一句话解决方法: 设置一下可以运行未签名的脚本或者为你的脚本签名. set-executionpolicy Bypass PowerShell因为在此系统中禁止执行脚本的解决方法 http://www.jb51.net/article/95022.htm Powershell 脚本数字签名实现方法

  • PowerShell 脚本中的密码保存的方法

    引言 笔者在<PowerShell 远程执行任务>一文中提到了在脚本中使用用户名和密码的基本方式: $Username = 'xxxx' $Password = 'yyyy' $Pass = ConvertTo-SecureString $Password -AsPlainText -Force $Cred = New-Object System.Management.Automation.PSCredential -ArgumentList $Username,$Pass 上面的代码仅仅是能

  • Powershell脚本的4种执行权限介绍

    Restricted--默认的设置, 不允许任何script运行 AllSigned--只能运行经过数字证书签名的script RemoteSigned--运行本地的script不需要数字签名,但是运行从网络上下载的script就必须要有数字签名 Unrestricted--允许所有的script运行 windows默认不允许任何脚本运行,你可以使用"Set-ExecutionPolicy"cmdlet来改变的你PowerShell环境.例如,你可以使用如下命令让PowerShell运

  • PowerShell脚本性能优化技巧总结

    最终优化 在你写脚本时,不要老是想着去优化,因为你的部分优化代码可能最终被丢弃.而且老是想着优化也会降低你的生产效率,因为和CPU的时间相比,脚本编写者的时间可能会更宝贵. 使用过滤参数 PowerShell可能会消耗很多资源,因为许多Cmdlet本身的设计就是用来提供数目很大的数据.所以,如果你使用的Cmdlet命令支持-Filter, -Include, 和 -Exclude这样的过滤条件,就尽量使用它们. 首先如果一条命令支持-Filter 过滤器参数,那就说明这里可能隐藏着一个对象访问A

  • 自动设置安卓手机wifi代理的PowerShell脚本

    在实际测试工作中,经常要将安卓手机通过wifi代理的形式连接到本机的fiddler或charles服务器代理进行抓包测试.最近一直在想,有没有什么方法可以自动设置安卓手机的wifi代理,曾经想通过修改安卓系统配置文件的方式来修改但是没有找到解决方案.最后决定针对自己的手机进行私人订制,缺点是只能针对固定机型进行设置,不过优点是脚本很好编写,可以很快的对自己平时使用的测试机进行定制(非Windows下的脚本编写过程类似). 利用adb命令编写PowerShell脚本 Windows下编写脚本用到了

  • PowerShell的基本使用方法

    目录 什么是powershell 1.   如何启动PowerShell 2.   如何运行程序.脚本和已有的软件 3.   运行PowerShell命令 4.   如何查找指定命令以及命令详情 5.   如何在外部调用PowerShell脚本 6.   如何获知最后执行命令的状态 7.   如何计算命令执行时间 8.   了解命令的别名 9.   如何操作使用管理控制台历史命令 10. 如何重定向输出 11. 如何记录PowerShell会话全文 12. 如何显示对象属性为列表或表格 13.

  • 利用python生成一个导出数据库的bat脚本文件的方法

    实例如下: # 环境: python3.x def getExportDbSql(db, index): # 获取导出一个数据库实例的sql语句 sql = 'mysqldump -u%s -p%s -h%s -P%d --default-character-set=utf8 --databases mu_ins_s%s > %s.s%d.mu_ins_%d.sql' %(db['user'], db['pwd'], db['host'], db['port'], index, db['serv

  • PowerShell脚本监控文件夹变化实例

    本文介绍使用PowerShell来监视一个指定的文件夹,包括新建文件.删除文件.重命名文件等操作均会被监控或监视.本文使用了System.IO.FileSystemWatcher这个.NET对象.首先,我们来看看程序: 复制代码 代码如下: # 定义要监控的文件夹,这个文件夹必须先存在. $folder = 'D:\test' # 定义每次监控的间隔时间,这时定义为1000毫秒,即1秒 $timeout = 1000 # 创建文件系统监视对象 $FileSystemWatcher = New-O

随机推荐