0

PowerShell 安全响应头 CSV 导出报告:一键生成网站安全评分报告

2026.05.31 | youres | 23次围观

为什么需要把安全响应头导出成 CSV 报告

用 PowerShell 检测网站安全头,很多人只停留在「能看到结果」这一步。但真正做运维、做等保测评、做周报月报,你得把结果变成一份可存档、可对比、可发送给上级的 CSV 报告

这篇文章讲清楚:怎么用 PowerShell 一键扫描多个域名的安全响应头,然后把结果导出成标准化 CSV 报告,包含评分、每项头的状态、建议修复措施。

一、先搞定:Invoke-WebRequest 获取安全响应头

PowerShell 原生没有 curl,但 Invoke-WebRequest 可以拿到响应头。核心代码:

$urls = @(\"https://www.youres.cn\",\"https://www.baidu.com\")
$results = @()
foreach ($url in $urls) {
    try {
        $resp = Invoke-WebRequest -Uri $url -UseBasicParsing -TimeoutSec 10
        $headers = $resp.Headers
        $results += [PSCustomObject]@{
            URL = $url
            StrictTransportSecurity = $headers['Strict-Transport-Security'] -join ','
            XContentTypeOptions = $headers['X-Content-Type-Options'] -join ','
            XFrameOptions = $headers['X-Frame-Options'] -join ','
            XXSSProtection = $headers['X-XSS-Protection'] -join ','
            ContentSecurityPolicy = $headers['Content-Security-Policy'] -join ','
            ReferrerPolicy = $headers['Referrer-Policy'] -join ','
            PermissionsPolicy = $headers['Permissions-Policy'] -join ','
            StatusCode = $resp.StatusCode
            CheckTime = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
        }
    } catch {
        $results += [PSCustomObject]@{
            URL = $url
            StrictTransportSecurity = 'ERROR'
            XContentTypeOptions = 'ERROR'
            XFrameOptions = 'ERROR'
            XXSSProtection = 'ERROR'
            ContentSecurityPolicy = 'ERROR'
            ReferrerPolicy = 'ERROR'
            PermissionsPolicy = 'ERROR'
            StatusCode = 0
            CheckTime = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
        }
    }
}
$results | Format-Table

说明:-UseBasicParsing 避免 IE DOM 依赖(Server Core 环境必须加);-TimeoutSec 10 防止挂死;错误用 try/catch 兜底。

二、给每个网站打安全评分(核心实战)

光有头不够,还得有量化评分。按 Security Headers 官网标准,我写一个评分函数:

function Get-SecurityHeaderScore {
    param($headersObj)
    $score = 0
    $max = 0
    # HSTS(必须 HTTPS)
    $max += 20
    if ($headersObj.StrictTransportSecurity -and $headersObj.StrictTransportSecurity -ne 'ERROR') { $score += 20 }
    # X-Content-Type-Options
    $max += 10
    if ($headersObj.XContentTypeOptions -eq 'nosniff') { $score += 10 }
    # X-Frame-Options
    $max += 10
    if ($headersObj.XFrameOptions -in 'DENY','SAMEORIGIN') { $score += 10 }
    # X-XSS-Protection
    $max += 10
    if ($headersObj.XXSSProtection -eq '1; mode=block') { $score += 10 }
    # Content-Security-Policy
    $max += 30
    if ($headersObj.ContentSecurityPolicy -and $headersObj.ContentSecurityPolicy -ne 'ERROR') { $score += 30 }
    # Referrer-Policy
    $max += 10
    if ($headersObj.ReferrerPolicy -and $headersObj.ReferrerPolicy -ne 'ERROR') { $score += 10 }
    # Permissions-Policy
    $max += 10
    if ($headersObj.PermissionsPolicy -and $headersObj.PermissionsPolicy -ne 'ERROR') { $score += 10 }
    return [PSCustomObject]@{
        Score = $score
        MaxScore = $max
        Grade = if ($score -ge 80) { 'A' } elseif ($score -ge 60) { 'B' } elseif ($score -ge 40) { 'C' } elseif ($score -ge 20) { 'D' } else { 'F' }
    }
}

三、导出 CSV 报告(含中文列名)

PowerShell 导出 CSV 最大的坑是中文乱码。必须用 Export-Csv -Encoding UTF8

$report = @()
foreach ($r in $results) {
    $gradeObj = Get-SecurityHeaderScore -headersObj $r
    $report += [PSCustomObject]@{
        检测网址 = $r.URL
        HSTS = if($r.StrictTransportSecurity -and $r.StrictTransportSecurity -ne 'ERROR') { '✅ 已配置' } else { '❌ 缺失' }
        XContentTypeOptions = if($r.XContentTypeOptions -eq 'nosniff') { '✅ nosniff' } else { '❌ 缺失或错误' }
        XFrameOptions = if($r.XFrameOptions -in 'DENY','SAMEORIGIN') { '✅ ' + $r.XFrameOptions } else { '❌ 缺失' }
        XXSSProtection = if($r.XXSSProtection -eq '1; mode=block') { '✅ 已配置' } else { '❌ 缺失' }
        ContentSecurityPolicy = if($r.ContentSecurityPolicy -and $r.ContentSecurityPolicy -ne 'ERROR') { '✅ 已配置' } else { '❌ 缺失' }
        ReferrerPolicy = if($r.ReferrerPolicy -and $r.ReferrerPolicy -ne 'ERROR') { '✅ ' + $r.ReferrerPolicy } else { '❌ 缺失' }
        安全评分 = $gradeObj.Score
        评级 = $gradeObj.Grade
        检测时间 = $r.CheckTime
    }
}
$report | Export-Csv -Path \".\\SecurityHeaderReport_$(Get-Date -Format 'yyyyMMdd_HHmmss').csv\" -Encoding UTF8 -NoTypeInformation
Write-Host \"报告已导出,共$($report.Count) 条记录\"

关键点:-Encoding UTF8 保证 Excel 打开不乱码;-NoTypeInformation 去掉文件头部的类型信息,更干净。

四、完整一键脚本(复制即用)

把上面所有代码拼起来,就是一个完整脚本。你也可以直接下载我整理好的版本:

# ============================================
# PowerShell 安全响应头 CSV 导出报告脚本
# 作者:youres | https://www.youres.cn
# ============================================

$urls = @(
    \"https://www.youres.cn\",
    \"https://www.baidu.com\",
    \"https://www.zhihu.com\"
)

function Get-SecurityHeaderScore {
    param($headersObj)
    $score = 0
    if ($headersObj.StrictTransportSecurity -and $headersObj.StrictTransportSecurity -ne 'ERROR') { $score += 20 }
    if ($headersObj.XContentTypeOptions -eq 'nosniff') { $score += 10 }
    if ($headersObj.XFrameOptions -in 'DENY','SAMEORIGIN') { $score += 10 }
    if ($headersObj.XXSSProtection -eq '1; mode=block') { $score += 10 }
    if ($headersObj.ContentSecurityPolicy -and $headersObj.ContentSecurityPolicy -ne 'ERROR') { $score += 30 }
    if ($headersObj.ReferrerPolicy -and $headersObj.ReferrerPolicy -ne 'ERROR') { $score += 10 }
    if ($headersObj.PermissionsPolicy -and $headersObj.PermissionsPolicy -ne 'ERROR') { $score += 10 }
    $grade = if ($score -ge 80) { 'A' } elseif ($score -ge 60) { 'B' } elseif ($score -ge 40) { 'C' } elseif ($score -ge 20) { 'D' } else { 'F' }
    return @{ Score = $score; Grade = $grade }
}

$results = @()
foreach ($url in $urls) {
    try {
        $resp = Invoke-WebRequest -Uri $url -UseBasicParsing -TimeoutSec 10
        $h = $resp.Headers
        $obj = [PSCustomObject]@{
            URL = $url
            StrictTransportSecurity = $h['Strict-Transport-Security'] -join ','
            XContentTypeOptions = $h['X-Content-Type-Options'] -join ','
            XFrameOptions = $h['X-Frame-Options'] -join ','
            XXSSProtection = $h['X-XSS-Protection'] -join ','
            ContentSecurityPolicy = $h['Content-Security-Policy'] -join ','
            ReferrerPolicy = $h['Referrer-Policy'] -join ','
            PermissionsPolicy = $h['Permissions-Policy'] -join ','
            StatusCode = $resp.StatusCode
            CheckTime = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
        }
    } catch {
        $obj = [PSCustomObject]@{
            URL = $url
            StrictTransportSecurity = 'ERROR'
            XContentTypeOptions = 'ERROR'
            XFrameOptions = 'ERROR'
            XXSSProtection = 'ERROR'
            ContentSecurityPolicy = 'ERROR'
            ReferrerPolicy = 'ERROR'
            PermissionsPolicy = 'ERROR'
            StatusCode = 0
            CheckTime = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
        }
    }
    $results += $obj
}

$report = @()
foreach ($r in $results) {
    $g = Get-SecurityHeaderScore -headersObj $r
    $report += [PSCustomObject]@{
        检测网址 = $r.URL
        HSTS = if($r.StrictTransportSecurity -and $r.StrictTransportSecurity -ne 'ERROR') { '已配置' } else { '缺失' }
        XContentTypeOptions = if($r.XContentTypeOptions -eq 'nosniff') { 'nosniff' } else { '缺失' }
        XFrameOptions = if($r.XFrameOptions -in 'DENY','SAMEORIGIN') { $r.XFrameOptions } else { '缺失' }
        XXSSProtection = if($r.XXSSProtection -eq '1; mode=block') { '已配置' } else { '缺失' }
        ContentSecurityPolicy = if($r.ContentSecurityPolicy -and $r.ContentSecurityPolicy -ne 'ERROR') { '已配置' } else { '缺失' }
        ReferrerPolicy = if($r.ReferrerPolicy -and $r.ReferrerPolicy -ne 'ERROR') { $r.ReferrerPolicy } else { '缺失' }
        安全评分 = $g.Score
        评级 = $g.Grade
        检测时间 = $r.CheckTime
    }
}

$outFile = \".\\SecurityHeaderReport_$(Get-Date -Format 'yyyyMMdd_HHmmss').csv\"
$report | Export-Csv -Path $outFile -Encoding UTF8 -NoTypeInformation
Write-Host \"✅ 报告已生成:$outFile\"
$report | Format-Table

五、CSV 报告在 Excel 里打开不乱码的方法

即使用了 -Encoding UTF8,Excel 有时候还是乱码。两个解决方法:

  1. 用 Excel「数据」→「从文本/CSV 导入」,编码选 UTF-8,不要直接双击打开。
  2. 在 CSV 文件头部加 BOM:把 Export-Csv -Encoding UTF8 改成用 StreamWriter 手写 BOM,Excel 就能自动识别。
# 带 BOM 的 CSV 导出方法(Excel 双击打开不乱码)
$outFile = \".\\SecurityHeaderReport_BOM_$(Get-Date -Format 'yyyyMMdd_HHmmss').csv\"
$stream = [System.IO.StreamWriter]::new($outFile, $false, [System.Text.UTF8Encoding]::new($true))
$stream.WriteLine(\"检测网址,HSTS,XContentTypeOptions,XFrameOptions,XXSSProtection,ContentSecurityPolicy,ReferrerPolicy,安全评分,评级,检测时间\")
foreach ($row in $report) {
    $stream.WriteLine(\"$($row.检测网址),$($row.HSTS),$($row.XContentTypeOptions),$($row.XFrameOptions),$($row.XXSSProtection),$($row.ContentSecurityPolicy),$($row.ReferrerPolicy),$($row.安全评分),$($row.评级),$($row.检测时间)\")
}
$stream.Close()
Write-Host \"✅ BOM CSV 已生成:$outFile(Excel 双击直接打开)\"

六、定时自动跑 + 邮件发送报告

配合 Windows 任务计划程序,每天自动跑一次,把 CSV 报告邮件发给你:

# 在脚本末尾加这段,自动发邮件(需要配置 SMTP)
$smtp = @{
    To = 'admin@example.com'
    From = 'monitor@example.com'
    Subject = \"网站安全响应头日报 $(Get-Date -Format 'yyyy-MM-dd')\"
    Body = '附件是最新安全响应头检测报告,请查收。'
    SmtpServer = 'smtp.example.com'
    Port = 25
    Attachments = $outFile
}
Send-MailMessage @smtp

详细邮件告警配置可以参考我之前写的:PowerShell 邮件告警自动化脚本Send-MailMessage 匿名SMTP 配置教程

总结

一套 PowerShell 脚本,完成安全头检测 → 评分 → CSV 导出 → 邮件发送的完整闭环。比手动登 Security Headers 网站一个个查效率高 10 倍,而且可以批量、可以定时、可以存档对比。

下次等保测评或者安全巡检,直接把 CSV 报告甩出来,专业度直接拉满。

版权声明

本文仅代表个人观点。
本文系AI辅助作者原创,未经许可,转载请保留原文链接。

发表评论