2026.06.02 | youres | 26次围观
为什么要用PowerShell做安全头检测
在Linux服务器上,大家习惯用curl检查网站的Strict-Transport-Security、Content-Security-Policy、X-Frame-Options等安全响应头。但到了Windows环境,情况就变了:
- Windows自带的curl其实是
Invoke-WebRequest的别名,行为跟Linux curl完全不同 - PowerShell 5.x 的
Invoke-WebRequest输出格式跟curl截然不同,解析响应头很麻烦 - 批量检测多个域名时,curl脚本在Windows上经常遇到编码乱码问题
直接用PowerShell写检测脚本,不仅原生兼容Windows,还能把结果导出成Excel直接打开的CSV文件,运维效率提升一大截。
实战脚本一:基础版——单域名安全头检测
先上一个最基础的版本,适合手动排查单个域名:
# 检查单个域名的安全响应头
function Test-SecurityHeaders {
param([string])
try {
= Invoke-WebRequest -Uri -UseBasicParsing -TimeoutSec 10
= .Headers
= [PSCustomObject]@{
Url =
StatusCode = .StatusCode
HSTS = .'Strict-Transport-Security'
CSP = .'Content-Security-Policy'
XFrameOptions = .'X-Frame-Options'
XXSSProtection = .'X-XSS-Protection'
XContentTypeOptions = .'X-Content-Type-Options'
ReferrerPolicy = .'Referrer-Policy'
PermissionsPolicy = .'Permissions-Policy'
}
return
} catch {
Write-Warning "请求失败: - "
return
}
}
# 用法
Test-SecurityHeaders -Url 'https://www.youres.cn'
关键点说明:
-UseBasicParsing参数必须加,否则PowerShell会启动IE引擎解析HTML,在服务器上会报错.Headers是字典结构,直接用键名取值,不区分大小写- 超时设10秒,避免某个域名挂了把整个脚本卡死
实战脚本二:批量版——并行检测多个域名
单个域名不够用,实际运维中要一次性检查几十个域名。用ForEach-Object -Parallel(PowerShell 7+)可以大幅提升速度:
# 批量检测多个域名的安全头(PowerShell 7+ 并行版)
= @(
'https://www.youres.cn',
'https://blog.youres.cn',
'https://api.youres.cn'
)
= | ForEach-Object -Parallel {
=
try {
= Invoke-WebRequest -Uri -UseBasicParsing -TimeoutSec 10
[PSCustomObject]@{
Url =
StatusCode = .StatusCode
HSTS = .Headers.'Strict-Transport-Security'
CSP = .Headers.'Content-Security-Policy'
XFrameOptions = .Headers.'X-Frame-Options'
XXSSProtection = .Headers.'X-XSS-Protection'
XContentTypeOptions = .Headers.'X-Content-Type-Options'
ReferrerPolicy = .Headers.'Referrer-Policy'
PermissionsPolicy = .Headers.'Permissions-Policy'
CheckTime = (Get-Date).ToString('yyyy-MM-dd HH:mm:ss')
}
} catch {
[PSCustomObject]@{
Url =
StatusCode = 'ERROR'
HSTS = ''
CSP = ''
XFrameOptions = ''
XXSSProtection = ''
XContentTypeOptions = ''
ReferrerPolicy = ''
PermissionsPolicy = ''
CheckTime = (Get-Date).ToString('yyyy-MM-dd HH:mm:ss')
}
}
} -ThrottleLimit 10
| Format-Table -AutoSize
这个版本的核心优势:
-ThrottleLimit 10:最多同时跑10个请求,比串行快5-8倍- 异常捕获:某个域名挂了不影响其他域名的检测结果
- PowerShell 5.x用户可以用
Invoke-Parallel模块或Start-Job实现并行,只是代码更啰嗦
实战脚本三:CSV报告版——直接生成Excel可打开的巡检报告
巡检完要出报告,最实用的做法是将结果导出为CSV文件。这里有个坑:PowerShell 5.x的Export-Csv默认是UTF-8无BOM,Excel打开中文直接乱码。正确做法:
# 导出CSV报告(兼容Excel打开中文)
= Get-Content 'C:\scripts\domains.txt'
= foreach ( in ) {
try {
= Invoke-WebRequest -Uri -UseBasicParsing -TimeoutSec 10
[PSCustomObject]@{
Url =
StatusCode = .StatusCode
HSTS = .Headers.'Strict-Transport-Security'
CSP = .Headers.'Content-Security-Policy'
XFrameOptions = .Headers.'X-Frame-Options'
XXSSProtection = .Headers.'X-XSS-Protection'
XContentTypeOptions = .Headers.'X-Content-Type-Options'
ReferrerPolicy = .Headers.'Referrer-Policy'
PermissionsPolicy = .Headers.'Permissions-Policy'
CheckTime = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
}
} catch {
[PSCustomObject]@{
Url =
StatusCode = 'ERROR'
HSTS = ''; CSP = ''; XFrameOptions = ''
XXSSProtection = ''; XContentTypeOptions = ''
ReferrerPolicy = ''; PermissionsPolicy = ''
CheckTime = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
}
}
}
# PowerShell 5.x 用UTF-8 BOM,Excel才能正常打开中文
= 'C:\scripts\security-header-report.csv'
| Export-Csv -Path -Encoding UTF8 -NoTypeInformation
# PowerShell 7 用默认UTF-8无BOM即可,Excel 2016+能正确识别
# | Export-Csv -Path -NoTypeInformation
关于编码的说明(这个坑踩过好几次):
- PowerShell 5.x:
Export-Csv -Encoding UTF8输出的是UTF-8 BOM,Excel能直接打开,中文正常 - PowerShell 7:默认输出UTF-8无BOM,Excel 2016及以上版本也能识别,不需要BOM
- 如果Excel打开还是乱码,用
Notepad++转成ANSI(即GBK)是最快的解决办法
安全头评分规则(Security Headers标准)
检测出结果后,怎么判断是不是合格?参考Security Headers的评分标准:
| 安全头 | 推荐值 | 扣分项 |
|---|---|---|
| Strict-Transport-Security | max-age=31536000; includeSubDomains | 未配置或max-age<1年 |
| Content-Security-Policy | 明确指定允许的域名,不用unsafe-inline | 未配置或用通配符* |
| X-Frame-Options | DENY 或 SAMEORIGIN | 未配置 |
| X-Content-Type-Options | nosniff | 未配置 |
| Referrer-Policy | strict-origin-when-cross-origin | 未配置或unsafe-url |
| Permissions-Policy | 明确禁用不需要的API | 未配置 |
与curl方案对比:为什么选PowerShell
| 对比项 | curl(Linux) | PowerShell(Windows) |
|---|---|---|
| 安装依赖 | 一般已预装 | Windows自带,无需安装 |
| 批量并行 | 需要xargs -P | 一行-Parallel搞定 |
| CSV导出 | 需要手动格式化 | Export-Csv原生支持 |
| 中文编码 | 需要注意locale设置 | Encoding参数直接控制 |
| 与Windows任务计划集成 | 需要Cygwin或WSL | 原生支持,直接加计划任务 |
进阶:配合钉钉机器人做告警推送
脚本检测到安全头缺失时,可以自动推送到钉钉群。把下面的函数加进脚本即可:
function Send-DingTalkAlert {
param([string])
= 'https://oapi.dingtalk.com/robot/send?access_token=你的token'
= @{ msgtype = 'text'; text = @{ content = } } | ConvertTo-Json -Depth 3
Invoke-RestMethod -Uri -Method POST -Body -ContentType 'application/json'
}
# 在检测结果里判断,缺失重要安全头就告警
foreach ( in ) {
if (-not .HSTS) {
Send-DingTalkAlert -Text "告警: 缺失 HSTS 安全头!"
}
}
总结
用PowerShell做安全头批量检测,最大的优势是原生兼容Windows、并行简单、CSV报告开箱即用。三个脚本从单域名到批量并行再到CSV报告,覆盖了从手动排查到自动化巡检的完整路径。配合任务计划程序和钉钉告警,可以搭建一套完整的网站安全监控体系。
下一步可以扩展的方向:加入HSTS max-age的分阶段配置策略,以及用curl交叉验证PowerShell检测结果,确保监控数据的准确性。
版权声明
本文仅代表个人观点。
本文系AI辅助作者原创,未经许可,转载请保留原文链接。

发表评论