@php
$filteredDisks = collect($reportData['disk_info'] ?? [])->reject(
fn($d) => str_starts_with($d['filesystem'] ?? '', '/dev/loop') || str_starts_with($d['mounted_on'] ?? '', '/snap/')
)->values();
$rootDisk = null;
foreach ($filteredDisks as $disk) {
if (($disk['mounted_on'] ?? '') === '/') { $rootDisk = $disk; break; }
}
$ssh = $reportData['ssh_config'] ?? [];
$pwd = $reportData['password_policy'] ?? [];
$as = $reportData['apache_security'] ?? [];
$ws = $reportData['web_service'] ?? [];
$hdr = $ws['http_headers'] ?? [];
$tls = $ws['ssl_tls'] ?? [];
$sslDays = isset($ws['ssl_cert_days_left']) ? intval($ws['ssl_cert_days_left']) : null;
$tlsGrade = null;
if (!empty($tls)) {
$g = 'A';
if ($sslDays !== null && $sslDays <= 0) { $g = 'F'; }
elseif ($tls['weak_cipher'] ?? false) { $g = 'C'; }
elseif ($tls['sslv3'] ?? false) { $g = 'C'; }
elseif (($tls['tls10'] ?? false) || ($tls['tls11'] ?? false)) { $g = 'B'; }
elseif (($tls['tls13'] ?? false) && ($tls['forward_secrecy'] ?? false) && !empty($hdr['hsts'])) { $g = 'A+'; }
$tlsGrade = $g;
}
$gradeColor = match($tlsGrade) {
'A+' => '#00c853', 'A' => '#43a047', 'B' => '#f9a825', 'C' => '#ef6c00', 'F' => '#c62828', default => '#9e9e9e'
};
if (!function_exists('ev')) {
function ev($raw, $pattern) { return preg_match($pattern, $raw ?? '', $m) ? $m[1] : ($raw ?: 'N/A'); }
}
@endphp
{{ $host->name }} - 主機維護報告
主機維護安全檢查報告
主機:{{ $host->name }} ・ IP:{{ $reportData['ip'] ?? 'N/A' }} ・ OS:{{ $host->os_type === 'windows' ? 'Windows' : 'Linux' }} ・ 報告時間:{{ $reportDate }}
1. 基本系統資訊
| 作業系統 | {{ $reportData['os_release']['PRETTY_NAME'] ?? ($reportData['os'] ?? 'N/A') }} |
| 核心版本 | {{ $reportData['kernel_version'] ?? 'N/A' }} |
| 主機名稱 | {{ $reportData['hostname'] ?? 'N/A' }} |
| IP 位址 | {{ $reportData['ip'] ?? 'N/A' }} |
| 時區 | {{ $reportData['timezone'] ?? 'N/A' }} |
| 開機時間 | {{ $reportData['boot_time'] ?? 'N/A' }} |
2. 硬體資訊
| CPU 型號 | {{ $reportData['cpu_model'] ?? 'N/A' }} |
| CPU 數量 | {{ $reportData['cpu_count'] ?? 'N/A' }} 核心 |
| 記憶體 | @if(isset($reportData['memory']))總容量 {{ $reportData['memory']['total_gb'] ?? '?' }} GB,已用 {{ $reportData['memory']['used_gb'] ?? '?' }} GB,可用 {{ $reportData['memory']['free_gb'] ?? '?' }} GB({{ $reportData['memory']['percent'] ?? '?' }}%)@else N/A @endif |
@foreach($filteredDisks as $disk)
| 磁碟 {{ $disk['mounted_on'] ?? '?' }} |
{{ $disk['filesystem'] ?? '' }} 總量 {{ $disk['size'] ?? '?' }},已用 {{ $disk['used'] ?? '?' }}({{ $disk['percent'] ?? '?' }}),可用 {{ $disk['avail'] ?? '?' }} |
@endforeach
3. 網路與服務資訊
| Web 服務 | {{ $ws['type'] ?? ev($reportData['apache_version'] ?? '', '/Apache\/([\d\.]+)/') }} |
| PHP | {{ $reportData['php_version'] ?? 'N/A' }} |
| MySQL | {{ ev($reportData['mysql_version'] ?? '', '/([\d\.]+)/') }} |
| OpenSSL | {{ $reportData['openssl_version'] ?? 'N/A' }} |
| OpenSSH | {{ $reportData['openssh_version'] ?? 'N/A' }} |
| Python | {{ $reportData['python_version'] ?? 'N/A' }} |
| GCC | {{ $reportData['gcc_version'] ?? 'N/A' }} |
| NTP 校時 | {!! (($reportData['ntp_status'] ?? '') === 'synchronized' || ($reportData['ntp_status'] ?? '') === 'active') ? '✔ 已同步' : '✘ ' . ($reportData['ntp_status'] ?? 'N/A') . '' !!}@if(!empty($reportData['ntp_servers']))({{ implode(', ', $reportData['ntp_servers']) }})@endif |
4. 帳號管理
| 特權帳號 | {{ !empty($reportData['privileged_accounts']) ? implode(', ', $reportData['privileged_accounts']) : 'N/A' }} |
5. 掃毒狀態
| 掃毒軟體 | {!! !empty($reportData['antivirus_installed']) ? '✔ 已安裝' : '✘ 未安裝' !!} |
| 版本 | {{ $reportData['antivirus_version'] ?? 'N/A' }} |
6. 防火牆設定
| 類型 | {{ strtoupper($reportData['firewall_type'] ?? 'N/A') }} |
| 狀態 | {!! ($reportData['firewall_status'] ?? '') === 'active' ? '✔ 已啟用' : '✘ ' . ($reportData['firewall_status'] ?? 'N/A') . '' !!} |
7. SSH 安全設定
| SSH Port | {{ $ssh['port'] ?? '22' }} |
| Root 登入 | @if(($ssh['permit_root_login'] ?? '') === 'no')✔ 已禁止@elseif(($ssh['permit_root_login'] ?? '') === 'prohibit-password')僅允許金鑰@else{{ $ssh['permit_root_login'] ?? 'unknown' }}@endif |
| 密碼認證 | @if(($ssh['password_auth'] ?? '') === 'no')✔ 已關閉@else{{ $ssh['password_auth'] ?? 'unknown' }}@endif |
| 最大嘗試次數 | {{ $ssh['max_auth_tries'] ?? 'unknown' }} |
8. 密碼政策
| 最長有效天數 | {{ $pwd['max_days'] ?? 'N/A' }} 天 |
| 最短更改間隔 | {{ $pwd['min_days'] ?? 'N/A' }} 天 |
| 最短長度 | {{ $pwd['min_length'] ?? ($pwd['pam_minlen'] ?? 'N/A') }} |
| 密碼複雜度 | {!! !empty($pwd['pam_pwquality']) ? '✔ 已啟用 (pam_pwquality)' : '✘ 未設定' !!} |
9. fail2ban 入侵防護
| 狀態 | {!! ($reportData['fail2ban_status'] ?? '') === 'active' ? '✔ 已啟用' : '✘ ' . ($reportData['fail2ban_status'] ?? 'N/A') . '' !!} |
@if(!empty($reportData['fail2ban_jails']))| 防護規則 | {{ $reportData['fail2ban_jails'] }} |
@endif
10. 系統更新狀態
| 上次更新 | {{ $reportData['last_update'] ?? 'N/A' }} |
| 待更新套件 | {!! ($reportData['pending_updates'] ?? 0) == 0 ? '✔ 已是最新' : '' . $reportData['pending_updates'] . ' 個待更新' !!} |
| 安全更新 | {!! ($reportData['security_updates'] ?? 0) == 0 ? '✔ 無待處理安全更新' : '' . $reportData['security_updates'] . ' 個安全更新待處理' !!} |
@if(!empty($as))
11. Apache 安全設定
| ServerTokens | {!! strtolower($as['server_tokens'] ?? '') === 'prod' ? '✔ Prod(隱藏版本)' : '' . ($as['server_tokens'] ?? 'unknown') . '' !!} |
| ServerSignature | {!! strtolower($as['server_signature'] ?? '') === 'off' ? '✔ Off' : '' . ($as['server_signature'] ?? 'unknown') . '' !!} |
| TraceEnable | {!! strtolower($as['trace_enable'] ?? '') === 'off' ? '✔ Off' : '' . ($as['trace_enable'] ?? 'unknown') . '' !!} |
@endif
@if(!empty($hdr))
11b. HTTP 資安標頭
| Header | 狀態 | 內容 |
@php
$hdrs = [
'x_frame_options' => ['X-Frame-Options', true],
'x_content_type' => ['X-Content-Type-Options', true],
'x_xss_protection' => ['X-XSS-Protection', false],
'content_security_policy' => ['Content-Security-Policy', true],
'hsts' => ['Strict-Transport-Security', true],
'referrer_policy' => ['Referrer-Policy', false],
'permissions_policy' => ['Permissions-Policy', false],
];
@endphp
@foreach($hdrs as $key => [$label, $required])
| {{ $label }} |
{!! !empty($hdr[$key]) ? '✔ 已設定' : ($required ? '✘ 未設定' : '✘ 未設定') !!} |
{{ !empty($hdr[$key]) ? Str::limit($hdr[$key], 100) : '' }} |
@endforeach
@endif
12. 存取控制機制(MAC)
| 類型 | {{ $reportData['mac_type'] ?? 'N/A' }} |
| 狀態 | {!! in_array(strtolower($reportData['mac_status'] ?? ''), ['enabled','enforcing']) ? '✔ ' . $reportData['mac_status'] . '' : '' . ($reportData['mac_status'] ?? 'N/A') . '' !!} |
13. Log 管理設定
| Logrotate(180 天) | {!! !empty($reportData['log_rotate_180days']) ? '✔ 已設定' : '✘ 未設定' !!} {{ $reportData['log_rotate_detail'] ?? '' }} |
| Apache Logrotate | {!! !empty($reportData['apache_logrotate_180days']) ? '✔ 已設定' : '✘ 未設定' !!} {{ $reportData['apache_logrotate_detail'] ?? '' }} |
14. 螢幕保護設定
@php
$timeout = $reportData['screensaver_timeout'] ?? '';
if(preg_match('/uint32\s+(\d+)/', $timeout, $m)) { $s=intval($m[1]); $timeout = $s . ' 秒(約 ' . round($s/60,1) . ' 分鐘)'; }
@endphp
| 啟用狀態 | {!! !empty($reportData['screensaver_configured']) ? '✔ 已設定' : '✘ 未設定' !!} |
| 等待時間 | {{ $timeout ?: 'N/A' }} |
@if(!empty($reportData['accounts_detail']))
15. 帳號安全檢查
| 帳號 | Sudo | Shell | 群組 | 最後更改 | 密碼到期 | 帳號到期 | 最大間隔 |
@foreach($reportData['accounts_detail'] as $acct)
@php $c = $acct['chage'] ?? []; @endphp
| {{ $acct['user'] }} |
{!! !empty($acct['is_sudo']) ? 'sudo' : '-' !!} |
{{ basename($c['shell'] ?? '') ?: '-' }} |
{{ $acct['groups'] ?? '-' }} |
{{ $c['last_change'] ?? 'N/A' }} |
{!! ($c['pw_expires'] ?? 'never') === 'never' ? 'never' : $c['pw_expires'] !!} |
{!! ($c['acct_expires'] ?? 'never') === 'never' ? 'never' : $c['acct_expires'] !!} |
{{ $c['max_days'] ?? 'N/A' }} |
@endforeach
@endif
@if(!empty($reportData['last_logins']))
16. 最近登入紀錄
@if(!empty($reportData['failed_login_count']))
失敗登入次數:{{ $reportData['failed_login_count'] }} 次
@endif
{{ $reportData['last_logins'] }}
@endif
@if(!empty($reportData['listening_ports_parsed']))
17. 對外開放 Port 清單
| 協定 | Port | 服務 | 監聽位址 |
@foreach($reportData['listening_ports_parsed'] as $p)
| {{ $p['protocol'] ?? '' }} | {{ $p['port'] ?? '' }} | {{ $p['service'] ?? '-' }} | {{ $p['address'] ?? '' }} |
@endforeach
@endif
@if(!empty($reportData['cron_jobs']))
18. 系統排程
| 來源 | 排程內容 |
@foreach($reportData['cron_jobs'] as $cj)
{{ $cj['source'] }} | {{ $cj['job'] ?? $cj['command'] ?? '' }} |
@endforeach
@endif
@if(!empty($reportData['apache_sites_certificates']['exists']))
19. 子站 SSL 憑證資訊
| 站台 | 憑證檔案 | 到期日 |
@foreach($reportData['apache_sites_certificates']['details'] ?? [] as $site)
| {{ $site['name'] ?? 'N/A' }} | {{ $site['certificate_file'] ?? 'N/A' }} | {{ $site['certificate_expiry'] ?? 'N/A' }} |
@endforeach
@endif
20. SSL/TLS 安全分析(Agent 本機)
@if(empty($tls))
Agent 尚未回報 SSL/TLS 資料,或此主機無 Web 服務。
@else
| TLS 等級 | {{ $tlsGrade }} |
| 憑證剩餘天數 | {!! $sslDays !== null ? ($sslDays <= 0 ? '已過期' : ($sslDays <= 30 ? '' . $sslDays . ' 天' : '' . $sslDays . ' 天')) : 'N/A' !!} |
| 憑證位元數 | {{ $tls['cert_bits'] ?? 'N/A' }} |
| 簽章演算法 | {{ $tls['cert_sig'] ?? 'N/A' }} |
| 發行者 | {{ $tls['cert_issuer'] ?? 'N/A' }} |
| Forward Secrecy | {!! ($tls['forward_secrecy'] ?? false) ? '✔ 支援' : '✘ 不支援' !!} |
| 弱加密 | {!! ($tls['weak_cipher'] ?? false) ? '✘ 偵測到弱加密' : '✔ 未偵測到弱加密' !!} |
TLS 協議支援
@foreach([['SSLv3','sslv3',true],['TLS 1.0','tls10',true],['TLS 1.1','tls11',true],['TLS 1.2','tls12',false],['TLS 1.3','tls13',false]] as [$label,$key,$dangerous])
| {{ $label }} |
@endforeach
@foreach([['SSLv3','sslv3',true],['TLS 1.0','tls10',true],['TLS 1.1','tls11',true],['TLS 1.2','tls12',false],['TLS 1.3','tls13',false]] as [$label,$key,$dangerous])
|
@if($tls[$key] ?? false)
{!! $dangerous ? '✔ 支援' : '✔ 支援' !!}
@else
{!! $dangerous ? '✘ 停用' : '✘ 停用' !!}
@endif
|
@endforeach
@endif
@if(!empty($sslReport) && empty($sslReport['error']))
@php
$ssl = $sslReport; $cert = $ssl['certificate'] ?? []; $daysLeft = $ssl['days_left'] ?? null;
$gc = match($ssl['grade'] ?? 'F') { 'A+','A' => '#198754', 'B' => '#0d6efd', 'C' => '#fd7e14', default => '#dc3545' };
@endphp
21. SSL Labs 外部評測
| 評等 | {{ $ssl['grade'] ?? 'N/A' }}({{ $ssl['score'] ?? 0 }}/100 分) |
| 憑證主體 | {{ $cert['subject'] ?? 'N/A' }} |
| 有效期限 | {{ $cert['not_before'] ?? '' }} ~ {{ $cert['not_after'] ?? '' }}@if($daysLeft !== null)(剩餘 {{ $daysLeft }} 天)@endif |
| Cipher | {{ $ssl['cipher'] ?? 'N/A' }} |
| HTTP/2 | {{ !empty($ssl['http2']) ? '✔ 支援' : '✘ 不支援' }} |
@endif
@if(!empty($host->av_last_scan))
@php
$av = $host->av_last_scan;
$avStatus = $av['status'] ?? 'unknown';
$avColor = $avStatus === 'clean' ? '#27ae60' : ($avStatus === 'infected' ? '#e74c3c' : '#95a5a6');
$avLabel = $avStatus === 'clean' ? '乾淨' : ($avStatus === 'infected' ? '發現威脅' : '錯誤');
$duration = $av['duration_seconds'] ?? null;
$durationStr = $duration !== null
? ($duration >= 3600
? sprintf('%d 時 %d 分 %d 秒', intdiv($duration,3600), intdiv($duration%3600,60), $duration%60)
: ($duration >= 60
? sprintf('%d 分 %d 秒', intdiv($duration,60), $duration%60)
: $duration . ' 秒'))
: null;
@endphp
22. 掃毒結果(ClamAV)
| 掃描狀態 | {{ $avLabel }} |
| 開始時間 | {{ $av['started_at'] ?? $av['scanned_at'] ?? 'N/A' }} |
| 結束時間 | {{ $av['finished_at'] ?? 'N/A' }} |
@if($durationStr)| 掃描耗時 | {{ $durationStr }} |
@endif
| 掃描路徑 | {{ implode('、', $av['paths'] ?? []) }} |
| 掃描引擎 | {{ $av['engine'] ?? 'N/A' }} |
| 掃描檔案數 | {{ number_format($av['files_scanned'] ?? 0) }} |
| 掃描目錄數 | {{ number_format($av['dirs_scanned'] ?? 0) }} |
| 發現威脅 | {{ $av['infected'] ?? 0 }} 個 |
@if(!empty($av['threats']))
威脅清單
| 檔案路徑 | 病毒名稱 |
@foreach($av['threats'] as $t)
{{ $t['file'] ?? '' }} | {{ $t['virus'] ?? '' }} |
@endforeach
@else
✔ 未發現任何威脅。
@endif
@endif
@php $backups = collect($reportData['backup'] ?? []); @endphp
@if($backups->isNotEmpty())
23. 備份狀態
| 類型 | 腳本 | 排程 | 備份目錄 | 最後備份時間 | 24h 檔案 | 目錄大小 | 狀態 |
@foreach($backups as $bk)
@php
$bkHours = $bk['last_backup_hours'] ?? -1;
if (!($bk['dir_found'] ?? false)) { $bkStatus = '未找到目錄'; $bkClass = 'fail'; }
elseif ($bkHours < 0) { $bkStatus = '未偵測到備份'; $bkClass = 'warn'; }
elseif ($bkHours <= 25) { $bkStatus = '正常'; $bkClass = 'pass'; }
else { $bkStatus = intval($bkHours/24) . ' 天前'; $bkClass = 'fail'; }
@endphp
| {{ $bk['type'] ?? '' }} |
{!! ($bk['script_found'] ?? false) ? '✔' : '✘' !!} |
{!! ($bk['in_cron'] ?? false) ? '✔' : '✘' !!} |
{{ $bk['dir_path'] ?? '—' }} |
{{ $bk['last_backup'] ?? '—' }} |
{{ $bk['files_24h'] ?? 0 }} |
{{ $bk['size'] ?? '—' }} |
{{ $bkStatus }} |
@endforeach
@endif
@php $li = $reportData['log_integrity'] ?? null; @endphp
@if($li)
24. Log 完整性檢查
| 檢查檔案數 |
正常 |
新增 |
疑似異動 |
檢查時間 |
| {{ $li['checked'] ?? 0 }} |
{{ $li['clean'] ?? 0 }} |
{{ $li['new_files'] ?? 0 }} |
{{ $li['tampered'] ?? 0 }} |
{{ $li['checked_at'] ?? '—' }} |
@if(!empty($li['categories']))
各類別統計
| 類別 | 檢查 | 正常 | 新增 | 異動 |
@foreach($li['categories'] as $cat)
| {{ $cat['name'] ?? '—' }} |
{{ $cat['checked'] ?? 0 }} |
{{ $cat['clean'] ?? 0 }} |
{{ ($cat['new_files'] ?? 0) ?: '—' }} |
{{ ($cat['tampered'] ?? 0) > 0 ? $cat['tampered'] : '—' }} |
@endforeach
@endif
@if(!empty($li['tampered_files']))
疑似異動的 Log 檔案
@foreach($li['tampered_files'] as $tf)
{{ $tf }} |
@endforeach
若為正常輪替造成,可刪除 /opt/host-agent/.log_hashes 重建基準。
@endif
@endif
@if(!empty($sbomData))
@php
$sbomTypes = [
'apt' => ['label' => 'APT 套件', 'pkgs' => $sbomData['apt'] ?? []],
'pip' => ['label' => 'Python (pip)', 'pkgs' => $sbomData['pip'] ?? []],
'npm' => ['label' => 'Node.js (npm)', 'pkgs' => $sbomData['npm'] ?? []],
'composer' => ['label' => 'PHP (Composer)', 'pkgs' => $sbomData['composer'] ?? []],
'winget' => ['label' => 'Windows (winget)', 'pkgs' => $sbomData['winget'] ?? []],
];
$totalCount = array_sum(array_map(fn($t) => count($t['pkgs']), $sbomTypes));
@endphp
25. SBOM 軟體清單(Software Bill of Materials)
收集時間:{{ $sbomCollectedAt ?? 'N/A' }} 共 {{ $totalCount }} 個套件
@foreach($sbomTypes as $typeKey => $t)
@if(count($t['pkgs']) > 0)
{{ $t['label'] }}({{ count($t['pkgs']) }} 個)
| 名稱 | 版本 | 授權 |
@foreach($t['pkgs'] as $pkg)
| {{ $pkg['name'] ?? '' }} |
{{ $pkg['version'] ?? '' }} |
{{ $pkg['license'] ?? '' }} |
@endforeach
@endif
@endforeach
@endif