Windows服务器运维中,PowerShell远程会话(PSRemoting)是管理员日常管理的核心手段,但默认配置下的认证机制存在明显安全隐患。简单来说,PSRemoting默认使用Kerberos或NTLM进行身份验证,如果服务器暴露在公网或内网边界,攻击者可以通过暴力破解、哈希传递(Pass-the-Hash)、票据伪造(Pass-the-Ticket)等手段获取远程执行权限。加固的核心思路就三条:限制谁能连、怎么连、连上后能干什么。下面我把每一步的具体操作和原理全部讲透。

一、PowerShell远程会话的工作原理与风险点

PowerShell远程会话本质上是通过WinRM(Windows Remote Management)服务实现的。WinRM默认监听5985(HTTP)和5986(HTTPS)端口,客户端通过Enter-PSSession或Invoke-Command发起连接。整个流程中,认证发生在建立会话的第一步,使用的是Windows内置的凭据验证机制。

风险点主要集中在以下几个方面:第一,默认允许所有管理员组成员远程连接,权限粒度过粗;第二,如果使用HTTP而非HTTPS,凭据在传输过程中可能被截获;第三,NTLM认证协议本身存在中继攻击风险;第四,会话建立后默认继承管理员权限,缺乏最小权限约束;第五,日志记录不完善,事后难以溯源。

二、强制启用HTTPS传输并配置证书

第一步也是最基础的一步,把WinRM的传输层从HTTP切换到HTTPS。HTTP明文传输凭据在任何抓包工具面前都是透明的,这是最不能容忍的漏洞。

# 在目标服务器上执行,创建HTTPS监听器
winrm create winrm/config/Listener?Address=*+Transport=HTTPS @{Hostname="server.domain.com"; CertificateThumbprint="你的证书指纹"}

# 如果还没有自签名证书,先创建一个
New-SelfSignedCertificate -DnsName "server.domain.com" -CertStoreLocation "Cert:\LocalMachine\My"

# 确认HTTPS监听器已生效
winrm enumerate winrm/config/Listener

如果是域环境,建议通过组策略统一部署企业CA签发的证书,自签名证书在大规模管理中维护成本高且不便于信任链管理。配置完成后,客户端连接时需要指定-UseSSL参数,或者在信任策略中将目标服务器加入TrustedHosts列表。

三、配置网络级访问控制——防火墙与IP白名单

不要让WinRM端口对所有IP开放。通过Windows防火墙精确限制哪些IP可以访问5986端口,这是网络层最直接的防护。

# 只允许特定管理网段访问WinRM HTTPS端口
New-NetFirewallRule -DisplayName "Allow WinRM HTTPS from Admin Subnet" `
  -Direction Inbound -Protocol TCP -LocalPort 5986 `
  -RemoteAddress 10.10.1.0/24 -Action Allow

# 删除默认允许所有的规则(如果存在)
Get-NetFirewallRule -DisplayName "Windows Remote Management (HTTP-In)" | Remove-NetFirewallRule

如果服务器位于DMZ区或云环境,建议配合安全组策略,只开放跳板机或堡垒机的IP。同时关闭5985端口的HTTP监听,避免降级攻击。对于不需要PSRemoting的服务器,直接禁用WinRM服务是最干净的做法。

四、细化用户授权——谁能远程执行PowerShell

默认情况下,所有本地管理员都能使用PSRemoting。但实际运维中,很多服务器只需要特定账号或特定运维人员访问。通过配置PSSessionConfiguration可以实现精细控制。

# 查看当前所有会话配置
Get-PSSessionConfiguration

# 创建一个受限的端点,只允许特定安全组的成员使用
Register-PSSessionConfiguration -Name "RestrictedEndpoint" `
  -StartupScript "C:\Scripts\RestrictedStartup.ps1" `
  -RunAsCredential "DOMAIN\svc_psremoting" `
  -ShowSecurityDescriptorUI

# 修改访问权限,只授予特定用户组
$sd = Get-PSSessionConfiguration -Name "RestrictedEndpoint" | 
       Select-Object -ExpandProperty SecurityDescriptorSddl
$sd = $sd -replace 'O:BAG:BAD:\(A;;GA;;;BA\)', 'O:BAG:BAD:(A;;GA;;;S-1-5-21-xxx-xxx-xxx-1001)'
Set-PSSessionConfiguration -Name "RestrictedEndpoint" -SecurityDescriptorSddl $sd

更推荐的做法是使用Just Enough Administration(JEA)功能。JEA允许你定义一个角色能力文件(Role Capability File),精确规定连接者可以执行哪些命令、访问哪些路径、使用哪些参数。这是微软官方推荐的最小权限远程管理方案。

# 创建JEA角色能力文件示例
@{
    VisibleCmdlets = 'Get-Service', 'Restart-Service', 'Get-EventLog'
    VisibleFunctions = 'Get-MyCustomInfo'
    VisibleExternalCommands = 'C:\Tools\approved_tool.exe'
    RoleCapabilities = @('ServerManager', 'EventLogReader')
}

五、启用Kerberos强认证并禁用NTLM回退

NTLM协议在现代安全体系中已经不够用了,它容易受到中继攻击和哈希传递攻击。应强制WinRM使用Kerberos认证,并在可能的情况下禁用NTLM。

# 查看当前认证方式
winrm get winrm/config/service/auth

# 配置为仅使用Kerberos
winrm set winrm/config/service/auth @{Kerberos="true"}

# 在组策略中禁用NTLM(需要域控配合)
# 计算机配置 -> Windows设置 -> 安全设置 -> 本地策略 -> 安全选项
# "网络安全: 将NTLM身份验证限制为仅用于NTLMv2" 设为启用
# "网络安全: 限制NTLM: 传入NTLM流量" 设为"拒绝所有"

需要注意的是,Kerberos要求客户端和服务器都在同一个域或者存在域信任关系。如果是工作组环境,Kerberos不可用,此时至少要确保使用NTLMv2并配合IPsec加密传输。

六、会话级别的安全加固——超时、断连与权限降级

即使认证通过了,会话本身也需要约束。长时间挂起的会话是安全隐患,尤其是在共享终端或跳板机场景下。

# 设置会话空闲超时(单位:毫秒),例如10分钟无操作自动断开
Set-Item WSMan:\localhost\Shell\IdleTimeout -Value 600000

# 设置最大会话数限制
Set-Item WSMan:\localhost\Shell\MaxConcurrentUsers -Value 5

# 配置最大会话内存限制(防止资源耗尽攻击)
Set-Item WSMan:\localhost\Shell\MaxMemoryPerShellMB -Value 1024

另外,强烈建议使用受保护的用户(Protected Users)安全组来管理PSRemoting账号。Windows的Protected Users组会自动阻止NTLM认证、强制使用AES加密、阻止票据委托,从账户层面堵住一大类攻击路径。

七、全面开启审计日志——让每一次连接都有迹可循

没有日志的安全策略等于没有策略。WinRM本身支持操作日志记录,但默认可能未开启或记录不完整。

# 开启WinRM操作日志
wevtutil sl Microsoft-Windows-WinRM/Operational /e:true

# 配置日志最大大小(默认20MB太小)
Set-Item WSMan:\localhost\Service\MaxLogSize -Value 104857600

# 查看最近的WinRM连接事件
Get-WinEvent -LogName "Microsoft-Windows-WinRM/Operational" -MaxEvents 50 | 
  Format-List TimeCreated, Id, Message

在域控上,还需要开启"审核登录事件"和"审核特殊登录"策略,记录每一次使用PSRemoting的凭据验证行为。建议将WinRM日志转发到集中式日志平台(如ELK或Splunk),实现实时告警和长期留存。

八、结合Credential Guard和设备防护

如果服务器支持Windows Server 2016以上版本,应启用Credential Guard功能。它利用虚拟化安全技术将凭据隔离在内存的受保护区域,即使攻击者获取了系统权限也无法提取明文密码或哈希值。这从根本上降低了凭据泄露后的横向移动风险。

同时,确保运维终端本身也是安全的。管理员的工作站如果被感染,攻击者可以直接窃取已建立的PSRemoting会话令牌。因此,运维终端应启用BitLocker加密、禁用不必要的远程桌面、安装EDR产品,形成端到端的防护链。

九、定期巡检与自动化合规检查

安全加固不是一次性工作。建议编写定期巡检脚本,自动检查WinRM配置是否偏离基线。

# 自动化合规检查脚本示例
$checks = @()

# 检查1: 是否使用HTTPS
$listener = winrm enumerate winrm/config/Listener
if ($listener -notmatch "Transport=HTTPS") {
    $checks += "FAIL: HTTPS未启用"
}

# 检查2: 防火墙规则是否限制了IP
$fwRule = Get-NetFirewallRule -DisplayName "*WinRM*" -ErrorAction SilentlyContinue
if ($fwRule.RemoteAddress -contains "Any") {
    $checks += "FAIL: 防火墙规则允许任意IP"
}

# 检查3: 审计日志是否开启
$log = Get-WinEvent -ListLog "Microsoft-Windows-WinRM/Operational" -ErrorAction SilentlyContinue
if (-not $log) {
    $checks += "FAIL: WinRM操作日志未开启"
}

$checks | ForEach-Object { Write-Host $_ }

将此脚本纳入定时任务,每周执行一次,发现偏差立即告警。配合配置管理工具(如DSC或Ansible)可以实现批量修复。

十、总结:分层防御才是正解

PowerShell远程会话认证加固不是某一个设置就能解决的,它需要从传输层加密、网络访问控制、用户权限细化、认证协议升级、会话生命周期管理、审计日志、终端安全、持续巡检等多个层面同时发力。任何单一环节的缺失都可能成为攻击者的突破口。对于企业级运维团队来说,把上述措施形成标准化配置模板,纳入服务器上线基线,才是真正可落地、可持续的安全实践。