第9天:PowerShell 安全、代码签名与企业部署
🔒 核心理念 :"绝不信任未经验证的脚本" + "绝不明文存储凭据"
🧪 环境要求 :Windows 10/11 或 Windows Server(需 .NET 和 PowerShell 5.1+)
💡 推荐工具 :PowerShell 7.2+(支持
Microsoft.PowerShell.SecretManagement)
一、执行策略(ExecutionPolicy)------ 你真的理解它吗?
❌ 常见误解
"设置
Set-ExecutionPolicy RemoteSigned就安全了。"
✅ 真相
- ExecutionPolicy 不是安全边界 ,而是防误执行机制
- 用户可随时绕过:
powershell -ExecutionPolicy Bypass -File script.ps1 - 真正的安全靠代码签名 + AppLocker / WDAC
🔧 查看与设置(需管理员)
cs
# 查看当前策略
Get-ExecutionPolicy -List
# 推荐企业策略:AllSigned(所有脚本必须签名)
Set-ExecutionPolicy -ExecutionPolicy AllSigned -Scope LocalMachine
📌 最佳实践:
- 开发机:
RemoteSigned- 生产服务器:
AllSigned+ 部署签名脚本
二、脚本数字签名(Authenticode)------ 证明"我是我"
步骤1:创建自签名证书(仅用于测试)
cs
# 生成代码签名证书(有效期1年)
$cert = New-SelfSignedCertificate `
-Subject "CN=MyAutomationScript" `
-Type CodeSigningCert `
-CertStoreLocation "Cert:\CurrentUser\My" `
-NotAfter (Get-Date).AddYears(1)
$cert.Thumbprint # 记下指纹,如:A1B2C3...
步骤2:签署脚本
cs
# 创建测试脚本
"Write-Host 'This is a signed script!'" | Set-Content -Path .\SignedScript.ps1
# 签名
Set-AuthenticodeSignature -FilePath .\SignedScript.ps1 -Certificate $cert
步骤3:验证签名
cs
Get-AuthenticodeSignature -FilePath .\SignedScript.ps1 | Format-List *
✅ 输出应包含:
csStatus : Valid StatusMessage : 签名有效。
⚠️ 注意
- 自签名证书不受信任,需手动导入到"受信任的根证书颁发机构"
- 企业应使用 内部 PKI(如 Active Directory CS) 或 公共 CA(如 DigiCert)
三、凭据安全存储 ------ 永远不要写 $password = "123456"
方案1:临时输入(交互式)
cs
$cred = Get-Credential -UserName "admin@contoso.com" -Message "请输入凭据"
# $cred.Password 是 SecureString,无法直接读取明文
方2:加密存储到文件(仅当前用户可用)
cs
# 保存凭据(加密)
$cred = Get-Credential
$cred | Export-Clixml -Path "$env:USERPROFILE\admin.cred"
# 读取凭据(仅同一用户、同一机器)
$cred = Import-Clixml -Path "$env:USERPROFILE\admin.cred"
🔐 原理:使用 DPAPI(Data Protection API) 加密,绑定当前用户+机器
四、现代方案:SecretManagement 模块(微软官方推荐)
✅ 支持 Vault 插件(Azure Key Vault、HashiCorp Vault、本地 SecretStore 等)
✅ 统一接口:
Get-Secret,Set-Secret,Get-SecretInfo
步骤1:安装模块
cs
Install-Module Microsoft.PowerShell.SecretManagement -Force
Install-Module Microsoft.PowerShell.SecretStore -Force # 本地存储后端
步骤2:注册本地 SecretStore(首次需配置)
cs
Register-SecretVault -Name LocalSecretStore -ModuleName Microsoft.PowerShell.SecretStore -DefaultVault
# 首次会提示设置密码(用于加密本地存储)
步骤3:存取密钥
cs
# 存储密码(SecureString)
Set-Secret -Name "DBPassword" -Secret ("MySuperSecret123" | ConvertTo-SecureString -AsPlainText -Force)
# 获取密码(返回 SecureString)
$securePass = Get-Secret -Name "DBPassword" -AsSecureString
# 转为明文(仅调试时使用!)
$plainText = [Runtime.InteropServices.Marshal]::PtrToStringAuto(
[Runtime.InteropServices.Marshal]::SecureStringToBSTR($securePass)
)
🌐 企业扩展 :替换
SecretStore为Az.KeyVault模块,无缝对接 Azure Key Vault。
五、启用脚本块日志(Script Block Logging)------ 审计恶意脚本
💡 功能:记录所有执行的 PowerShell 脚本内容到 Windows 事件日志
启用方法(需管理员,通过组策略或注册表)
方法A:使用 PowerShell 设置(临时)
cs
# 启用脚本块日志
New-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging" `
-Name "EnableScriptBlockLogging" -Value 1 -PropertyType DWORD -Force
方法B:查看日志
cs
# 查询最近10条 PowerShell 脚本执行记录
Get-WinEvent -LogName "Microsoft-Windows-PowerShell/Operational" |
Where-Object Id -eq 4104 |
Select-Object TimeCreated, @{Name="Script"; Expression={$_.Properties[2].Value}} |
Select-Object -First 10
🕵️ 用途 :安全团队可检测
Invoke-Mimikatz、DownloadString等可疑行为
六、综合实战:安全自动化脚本模板
cs
# secure-deployment.ps1
<#
.SYNOPSIS
安全连接远程服务器并重启服务(无硬编码密码)
#>
param([string]$ComputerName = "SRV01")
# 1. 从 SecretManagement 获取凭据
try {
$cred = Get-Secret -Name "AdminCredential" -AsPSCredential -ErrorAction Stop
} catch {
Write-Error "❌ 未找到凭据,请先运行: Set-Secret -Name AdminCredential -Secret (Get-Credential)"
exit 1
}
# 2. 远程执行(使用签名脚本 + AllSigned 策略)
$script = {
Restart-Service -Name "Spooler" -PassThru
}
try {
Invoke-Command -ComputerName $ComputerName -Credential $cred -ScriptBlock $script
Write-Host "✅ 服务已重启" -ForegroundColor Green
} catch {
Write-Error "远程执行失败: $($_.Exception.Message)"
}
✅ 部署流程:
- 管理员运行一次
Set-Secret -Name AdminCredential -Secret (Get-Credential)- 签名脚本:
Set-AuthenticodeSignature -FilePath .\secure-deployment.ps1 -Certificate $cert- 在
AllSigned策略下安全运行
七、今日重点总结
| 安全领域 | 推荐做法 | 避免做法 |
| 脚本来源 | 使用 AllSigned + 代码签名 | Bypass 执行策略 |
| 凭据存储 | SecretManagement / DPAPI 加密文件 | 明文写在脚本中 |
| 远程执行 | $PSCredential + Invoke-Command | -Username + -Password 字符串 |
| 审计追踪 | 启用 Script Block Logging | 无日志记录 |
|---|
课后作业
- 创建自签名证书并签署一个脚本 ,验证其在
AllSigned策略下可运行。 - 使用
SecretManagement存储一个数据库连接字符串(作为SecureString),并在脚本中读取。 - 启用 Script Block Logging ,运行一个简单脚本(如
Get-Process),在事件查看器中找到对应的日志条目。
💡 提示:作业2中,连接字符串可用
ConvertTo-SecureString -AsPlainText临时换。