bend_puzzle/scripts/harden-windows-host.ps1
33333-33333 9d70afb4cc
Some checks failed
BEND FIELD CI / release (push) Has been cancelled
BEND FIELD CI / production-bridge (push) Has been cancelled
t
2026-08-01 22:31:04 +09:00

89 lines
3.6 KiB
PowerShell

[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$ApacheConfig,
[Parameter(Mandatory = $true)]
[string]$PhpIni,
[switch]$Apply,
[switch]$SkipApacheSyntaxCheck
)
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
function Resolve-ConfigFile([string]$Value, [string]$Label) {
$resolved = (Resolve-Path -LiteralPath $Value -ErrorAction Stop).Path
if (-not (Test-Path -LiteralPath $resolved -PathType Leaf)) {
throw "$Label is not a file: $resolved"
}
return $resolved
}
function Replace-ManagedBlock([string]$Text, [string]$Begin, [string]$End, [string]$Block) {
$normalized = $Text -replace "`r`n?", "`n"
$pattern = '(?ms)(?:^|\n)' + [regex]::Escape($Begin) + '.*?' + [regex]::Escape($End) + '(?:\n|$)'
$without = [regex]::Replace($normalized, $pattern, "`n").TrimEnd("`n")
if ($without.Length -eq 0) { return "$Block`n" }
return "$without`n`n$Block`n"
}
function Write-Utf8NoBom([string]$File, [string]$Text) {
[System.IO.File]::WriteAllText($File, $Text, [System.Text.UTF8Encoding]::new($false))
}
$apacheFile = Resolve-ConfigFile $ApacheConfig 'Apache configuration'
$phpFile = Resolve-ConfigFile $PhpIni 'PHP configuration'
$apacheBegin = '# BEGIN LINKFIELD HOST HARDENING'
$apacheEnd = '# END LINKFIELD HOST HARDENING'
$phpBegin = '; BEGIN LINKFIELD HOST HARDENING'
$phpEnd = '; END LINKFIELD HOST HARDENING'
$apacheBlock = "$apacheBegin`nServerTokens Prod`nServerSignature Off`n$apacheEnd"
$phpBlock = "$phpBegin`nexpose_php = Off`n$phpEnd"
$apacheOriginal = [System.IO.File]::ReadAllText($apacheFile)
$phpOriginal = [System.IO.File]::ReadAllText($phpFile)
$apacheUpdated = Replace-ManagedBlock $apacheOriginal $apacheBegin $apacheEnd $apacheBlock
$phpUpdated = Replace-ManagedBlock $phpOriginal $phpBegin $phpEnd $phpBlock
$apacheAlreadySafe = $apacheUpdated -eq ($apacheOriginal -replace "`r`n?", "`n")
$phpAlreadySafe = $phpUpdated -eq ($phpOriginal -replace "`r`n?", "`n")
Write-Output "Apache config: $apacheFile"
Write-Output "PHP config: $phpFile"
Write-Output "Apache ServerTokens/ServerSignature: $(if ($apacheAlreadySafe) {'already managed'} else {'change required'})"
Write-Output "PHP expose_php: $(if ($phpAlreadySafe) {'already managed'} else {'change required'})"
if (-not $Apply) {
Write-Output 'Dry run only. Re-run with -Apply to create backups and write the managed settings.'
exit 0
}
$stamp = Get-Date -Format 'yyyyMMdd-HHmmss'
$apacheBackup = "$apacheFile.linkfield-backup-$stamp"
$phpBackup = "$phpFile.linkfield-backup-$stamp"
Copy-Item -LiteralPath $apacheFile -Destination $apacheBackup -Force
Copy-Item -LiteralPath $phpFile -Destination $phpBackup -Force
try {
Write-Utf8NoBom $apacheFile $apacheUpdated
Write-Utf8NoBom $phpFile $phpUpdated
if (-not $SkipApacheSyntaxCheck) {
$apacheRoot = Split-Path -Parent (Split-Path -Parent $apacheFile)
$httpd = Join-Path $apacheRoot 'bin\httpd.exe'
if (-not (Test-Path -LiteralPath $httpd -PathType Leaf)) {
throw "Apache syntax checker was not found at $httpd. Re-run with -SkipApacheSyntaxCheck only after locating another way to run httpd -t."
}
& $httpd -t -f $apacheFile
if ($LASTEXITCODE -ne 0) { throw "Apache rejected the updated configuration (exit $LASTEXITCODE)." }
}
} catch {
Copy-Item -LiteralPath $apacheBackup -Destination $apacheFile -Force
Copy-Item -LiteralPath $phpBackup -Destination $phpFile -Force
throw "Host hardening failed; both original files were restored. $($_.Exception.Message)"
}
Write-Output "Applied LinkField host hardening. Backups:"
Write-Output " $apacheBackup"
Write-Output " $phpBackup"
Write-Output 'Restart Apache, then run: npm run smoke:public -- https://2012r2.nishi.boats/~333/link-field/'