WinRM(Windows Remote Management)是Windows服务器内置的远程管理协议,基于WS-Management协议栈,默认使用5985(HTTP)和5986(HTTPS)端口。很多管理员为了方便远程运维直接开启WinRM却不做安全加固,这相当于把服务器的后门敞开。正确的做法是:强制使用HTTPS传输、配置基于证书的身份验证、限制访问IP范围、启用Kerberos认证、设置合理的会话超时,并且把WinRM服务绑定到非标准端口上。下面我把每一步的具体操作和背后的安全逻辑全部讲透。
一、WinRM到底是什么,为什么它容易被攻击
WinRM本质上是一个基于SOAP协议的Web服务,它允许管理员通过PowerShell Remoting、WinRS命令或者任何兼容WS-Man的客户端远程执行命令。和RDP不同,WinRM不提供图形界面,但它的权限可以非常高——如果你用域管理员身份连接,等于拥有了整台服务器的控制权。攻击者一旦拿到WinRM的访问权限,可以横向移动、执行恶意脚本、窃取数据。近年来大量勒索病毒和APT攻击都利用了WinRM的弱配置作为突破口,比如默认启用HTTP明文传输、使用弱密码、没有IP限制等。
二、第一步:检查当前WinRM配置状态
在动手加固之前,先看看你的服务器现在是什么状态。打开PowerShell(以管理员身份运行),执行以下命令:
winrm enumerate winrm/config/listener winrm get winrm/config winrm enumerate winrm/config/service
重点看三个东西:Listener是否绑定了HTTP、Service的AllowUnencrypted是不是true、Auth的认证方式是什么。如果你看到HTTP监听器存在且AllowUnencrypted为true,说明你的服务器正在裸奔。
三、核心加固:强制HTTPS并配置SSL证书
这是最关键的一步。HTTP传输意味着所有命令和凭据都是明文的,任何人在网络路径上都能抓包。必须切换到HTTPS。操作分两种情况:
如果你有企业CA或者已经购买了SSL证书,直接导入证书并绑定:
# 导入证书到本地计算机的个人证书存储
Import-Certificate -FilePath "C:\certs\server.cer" -CertStoreLocation Cert:\LocalMachine\My
# 获取证书的Thumbprint
$cert = Get-ChildItem Cert:\LocalMachine\My | Where-Object {$_.Subject -like "*yourserver*"}
# 删除HTTP监听器
winrm delete winrm/config/Listener?Address=*+Transport=HTTP
# 创建HTTPS监听器
winrm create winrm/config/Listener?Address=*+Transport=HTTPS @{Hostname="yourserver.domain.com"; CertificateThumbprint=$cert.Thumbprint}如果你没有正式证书,可以用自签名证书应急,但生产环境强烈建议用企业CA签发的证书:
# 创建自签名证书 New-SelfSignedCertificate -DnsName "yourserver.domain.com","yourserver" -CertStoreLocation "Cert:\LocalMachine\My" -NotAfter (Get-Date).AddYears(2) # 后续步骤同上
四、配置基于证书的身份验证,禁用Basic认证
默认情况下WinRM可能允许Basic认证,这意味着用户名密码以Base64编码传输,虽然HTTPS下有加密,但Basic认证本身是弱认证方式。应该配置为使用证书进行客户端身份验证:
# 设置服务认证方式为证书
winrm set winrm/config/service/auth @{Certificate="true"}
# 或者更精细地配置
winrm set winrm/config/service @{AllowUnencrypted="false"; Basic="false"}同时,在客户端连接时也要指定使用证书:
# 客户端连接示例 $sessionOption = New-PSSessionOption -SkipCACheck -SkipCNCheck Enter-PSSession -ComputerName "yourserver.domain.com" -UseSSL -CertificateThumbprint "CLIENT_CERT_THUMBPRINT" -SessionOption $sessionOption
五、限制访问IP范围,不要对全网开放
WinRM默认监听所有网络接口(0.0.0.0),这意味着任何能到达该端口的机器都能尝试连接。必须限制只允许特定管理IP或跳板机访问:
# 查看当前监听器的IP绑定
winrm enumerate winrm/config/Listener
# 修改监听器只绑定到特定IP或管理网段
winrm set winrm/config/Listener?Address=*+Transport=HTTPS @{Address="10.0.1.100"}更好的做法是在Windows防火墙层面做限制:
# 只允许管理网段访问5986端口 New-NetFirewallRule -DisplayName "WinRM HTTPS" -Direction Inbound -Protocol TCP -LocalPort 5986 -RemoteAddress "10.0.1.0/24" -Action Allow # 删除原有的全网开放规则 Remove-NetFirewallRule -DisplayName "Windows Remote Management (HTTP-In)" -ErrorAction SilentlyContinue
如果你的管理网络是通过跳板机的,那就只开放跳板机IP。这一条能挡住绝大多数自动化扫描攻击。
六、启用Kerberos认证,提升身份验证强度
在域环境中,WinRM支持Kerberos认证,这比NTLM和Basic都安全得多。确保以下配置正确:
# 确认Kerberos已启用
winrm get winrm/config/service/auth
# 如果需要,显式设置
winrm set winrm/config/service/auth @{Kerberos="true"; Negotiate="true"}Kerberos的好处是不传输密码、支持双向认证、票据有有效期。但前提是你的服务器和客户端都在同一个域或者有信任关系,并且SPN(Service Principal Name)配置正确。如果SPN缺失,Kerberos会回退到NTLM,那就失去意义了。检查SPN:
setspn -L yourserver
如果没有HTTP相关的SPN,需要手动添加:
setspn -S HTTP/yourserver.domain.com yourserver setspn -S HTTP/yourserver yourserver
七、配置会话超时和资源限制,防止资源耗尽攻击
WinRM允许管理员设置最大会话数、空闲超时时间、最大内存等。这些参数不仅是性能优化,更是安全防护。恶意用户可以创建大量会话来耗尽服务器资源:
# 查看当前Shell配置
winrm get winrm/config/winrs
# 设置最大并发Shell数
winrm set winrm/config/winrs @{MaxShellsPerUser="5"}
# 设置空闲超时(毫秒),比如30分钟无操作自动断开
winrm set winrm/config/winrs @{IdleTimeout="1800000"}
# 设置最大内存每Shell(单位KB)
winrm set winrm/config/winrs @{MaxMemoryPerShellMB="512"}八、更改默认端口,增加攻击成本
5985和5986是众所周知的默认端口,自动化扫描工具第一时间就会探测。虽然改端口不能替代其他安全措施,但能有效减少被扫描和暴力破解的概率:
# 修改HTTPS监听端口为自定义端口,比如8443
winrm set winrm/config/Listener?Address=*+Transport=HTTPS @{Port="8443"}
# 同时更新防火墙规则
Set-NetFirewallRule -DisplayName "WinRM HTTPS" -LocalPort 8443注意:改端口后,客户端连接也要指定端口:
Enter-PSSession -ComputerName "yourserver.domain.com" -Port 8443 -UseSSL
九、开启审计日志,做到可追溯
Windows事件日志可以记录WinRM的连接和操作。开启相关审计策略:
# 通过组策略或本地策略开启 auditpol /set /subcategory:"Other Logon/Logoff Events" /success:enable /failure:enable auditpol /set /subcategory:"Logon" /success:enable /failure:enable
在事件查看器中,关注事件ID 4624(成功登录)、4625(登录失败)、4648(使用显式凭据登录)等。如果你看到大量来自未知IP的4625事件,说明有人在暴力破解你的WinRM。
十、定期检查和自动化巡检
安全配置不是一次性的事情。建议写一个定期巡检脚本,每周自动检查WinRM状态:
# WinRM安全巡检脚本示例
$listeners = winrm enumerate winrm/config/Listener
$service = winrm get winrm/config/service
$winrs = winrm get winrm/config/winrs
$issues = @()
if ($listeners | Select-String -Pattern "HTTP" -Quiet) {
$issues += "警告:发现HTTP监听器未删除"
}
if ($service.AllowUnencrypted -eq "true") {
$issues += "警告:允许未加密传输"
}
if ($service.Basic -eq "true") {
$issues += "警告:Basic认证未禁用"
}
if ($issues.Count -eq 0) {
Write-Host "WinRM安全检查通过" -ForegroundColor Green
} else {
$issues | ForEach-Object { Write-Host $_ -ForegroundColor Red }
}十一、常见误区和补充建议
很多人以为开启了HTTPS就万事大吉,实际上如果证书是自签名的且客户端跳过了验证,中间人攻击依然可行。另外,不要在WinRM中使用本地管理员账户直接连接,应该通过跳板机+受限账户的方式操作。如果条件允许,考虑使用JEA(Just Enough Administration)来限制远程会话只能执行特定命令,而不是给一个完整的Shell。
还有一点容易被忽略:WinRM和PowerShell Remoting是绑定的,加固WinRM的同时也要确保PowerShell的执行策略和脚本日志是开启的。执行策略设为RemoteSigned或AllSigned,同时开启脚本块日志:
# 开启PowerShell脚本块日志 Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging" -Name "EnableScriptBlockLogging" -Value 1 # 开启模块日志 Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ModuleLogging" -Name "EnableModuleLogging" -Value 1
总结一下,WinRM安全配置的核心逻辑就是:加密传输、强身份认证、最小权限、访问控制、审计追踪。这五个维度缺一不可。不要图省事只做其中一两项,真正的安全是体系化的。按照上面的步骤一步步来,你的Windows服务器远程管理安全性会提升一个量级。
