Files
Powershell/cybersecurity/Network Reputation Service/script-nrs.ps1

522 lines
21 KiB
PowerShell

# Script d'Audit Firewall - Network Reputation Service
# Auteur: Hubert Cornet
# Date: 03/09/2025
# Version: 1.0
Clear-Host
# Configuration globale
$ErrorActionPreference = "Continue"
$WarningPreference = "SilentlyContinue"
### Functions ###
## Function Write-ColorOutput
Function Write-ColorOutput {
Param(
[string]$Text,
[string]$Color = "White"
)
Try {
Write-Host $Text -ForegroundColor $Color
}
Catch {
Write-Host $Text
}
}
## Function Prerequisites
Function Prerequisites {
Write-ColorOutput "`n=== Vérification des prérequis ===" "Cyan"
# Vérification du fichier JSON
$JsonFile = Join-Path $PSScriptRoot "file-nrs.json"
If(-not (Test-Path $JsonFile)) {
Write-ColorOutput "ERREUR: Le fichier 'file-nrs.json' n'existe pas!" "Red"
Write-ColorOutput "Veuillez télécharger ou créer le fichier depuis:" "Yellow"
Write-ColorOutput "https://github.com/your-repo/file-nrs.json" "Blue"
Write-ColorOutput "Le fichier doit être placé dans le même dossier que ce script." "Yellow"
Return $false
}
Write-ColorOutput "✓ Fichier 'file-nrs.json' trouvé" "Green"
# Vérification/Installation des modules requis
$RequiredModules = @('PSWriteHTML', 'PSWriteColor')
Foreach ($Module in $RequiredModules) {
If(-not (Get-Module -ListAvailable -Name $Module)) {
Write-ColorOutput "Installation du module $Module..." "Yellow"
Try {
Install-Module -Name $Module -Force -Scope CurrentUser -AllowClobber
Write-ColorOutput "✓ Module $Module installé" "Green"
}
Catch {
Write-ColorOutput "ERREUR: Impossible d'installer le module $Module : $($_.Exception.Message)" "Red"
Return $false
}
}
Else {
Write-ColorOutput "✓ Module $Module disponible" "Green"
}
Import-Module $Module -Force
}
return $true
}
## Function Check-Categories
Function Check-Categories {
Param(
[array]$Categories,
[string]$ProxyUrl = "",
[System.Management.Automation.PSCredential]$ProxyCredential = $null,
[int]$TimeoutSeconds = 10
)
$AllResults = @()
$CategoryCount = 0
$BlockKeywors = @("site bloqué", "access denied", "filtrage web", "Access Denied", "Site Blocked") # Définir les mots-clés des page des blocage
Foreach ($Category in $Categories.Categorie) {
$CategoryCount++
Show-ProgressBar -Current $CategoryCount -Total $Categories.Categorie.Count -Activity "Test des catégories" -Status "Catégorie: $($category.Categorie.nom)"
Write-ColorOutput "`n=== Test de la catégorie: $($Category.nom) ===" "Cyan"
#Write-ColorOutput "Description: $($category.description)" "Gray"
$CategoryResults = @()
$UrlCount = 0
Foreach ($UrlObj in $Category.urls) {
$UrlCount++
Show-ProgressBar -Current $UrlCount -Total $Category.urls.Count -Activity "Test des URLs de '$($Category.nom)'" -Status $UrlObj.url
Write-ColorOutput "Test de: $($UrlObj.url)" "Yellow"
#$Result = Get-UrlStatus -Url $UrlObj.url -ProxyUrl $ProxyUrl -ProxyCredential $ProxyCredential -TimeoutSeconds $TimeoutSeconds -BlockPageKeywords $BlockPageKeywords
$Result = Get-UrlStatus $UrlObj.url $UrlObj.expected_action $BlockPageKeywords
$TestResult = [PSCustomObject]@{
Category = $category.nom
CategoryId = $category.id
Url = $urlObj.url
Reputation = $urlObj.reputation
ExpectedAction = $urlObj.expected_action
Status = $result.ActualResult
StatusCode = $result.StatusCode
ResponseTime = $result.ResponseTime
Error = $result.Details
Score = $result.Score
IsCorrect = (($TestResult.Status -eq "Bloqué" -and $UrlObj.expected_action -eq "block") -or ($TestResult.Status -eq "Autorisé" -and $UrlObj.expected_action -eq "allow"))
}
$StatusColor = If($testResult.IsCorrect) { "Green" } Else { "Red" }
Write-ColorOutput " → Résultat: $($TestResult.Status) | Attendu: $($TestResult.ExpectedAction) | Correct: $($TestResult.IsCorrect)" $statusColor
$categoryResults += $testResult
$allResults += $testResult
}
$CategoryScore = Calculate-CategoryScore -Results $categoryResults
$CategoryGrade = Convert-ScoreToGrade -Score $categoryScore
Write-ColorOutput "Score de la catégorie '$($Category.nom)': $categoryScore% (Note: $CategoryGrade)" "Magenta"
}
Write-Progress -Activity "Test des catégories" -Completed
Write-Progress -Activity "Test des URLs" -Completed
return $allResults
}
## Function Show-ProgressBar
Function Show-ProgressBar {
Param(
[int]$Current,
[int]$Total,
[string]$Activity,
[string]$Status = ""
)
$Percent = [math]::Round(($Current / $Total) * 100, 1)
Write-Progress -Activity $Activity -Status "$Status ($Current/$Total)" -PercentComplete $Percent
}
## FunctionCalculate-CategoryScore
Function Calculate-CategoryScore {
Param(
[array]$Results
)
$TotalUrls = $Results.Count
$CorrectResults = 0
Foreach ($Result in $Results) {
$IsBlocked = $Result.Status -eq "Bloqué"
$ShouldBeBlocked = $result.ExpectedAction -eq "block"
If(($IsBlocked -and $ShouldBeBlocked) -or (-not $IsBlocked -and -not $ShouldBeBlocked)) {
$CorrectResults++
}
}
If($TotalUrls -eq 0) {
Return 0
}
Return [math]::Round(($CorrectResults / $TotalUrls) * 100, 2)
}
## Function Convert-ScoreToGrade
Function Convert-ScoreToGrade {
Param([double]$Score)
switch ($Score) {
{$_ -ge 95} { return 'A+' }
{$_ -ge 90} { return 'A' }
{$_ -ge 85} { return 'B+' }
{$_ -ge 80} { return 'B' }
{$_ -ge 75} { return 'C+' }
{$_ -ge 70} { return 'C' }
{$_ -ge 65} { return 'D+' }
{$_ -ge 60} { return 'D' }
{$_ -ge 55} { return 'E+' }
{$_ -ge 50} { return 'E' }
{$_ -ge 45} { return 'F+' }
default { return 'F' }
}
}
## Function Get-UrlStatus
Function Get-UrlStatus {
Param(
[string]$Url,
[string]$ExpectedAction, # 'allow' ou 'block'
[string[]]$BlockPageKeywords, # Exemple: @("Access Denied", "Site Blocked")
[string]$ProxyAddress = $null,
[string]$ProxyUseAuthentication = $null,
[int]$Timeout = 10
)
$Result = [PSCustomObject]@{
Url = $Url
Expected = $ExpectedAction
ActualResult = "Indéterminé" # Ce qui s'est réellement passé (Bloqué/Autorisé)
TestStatus = "Échec" # Le statut du test (Conforme/Non Conforme)
Score = $Null
StatusCode = ""
Details = ""
ResponseTime = ""
}
# Préparation des paramètres pour Invoke-WebRequest (Splatting)
$IWRParams = @{
Uri = $Url
UseBasicParsing = $True
TimeoutSec = $Timeout
ErrorAction = 'Stop'
}
$Response = $Null
# Ajout des paramètres du proxy s'ils sont fournis
If (-not [string]::IsNullOrEmpty($ProxyAddress)) {
$IWRParams.Add('Proxy', $ProxyAddress)
If ($ProxyUseAuthentication) {
# Demande les identifiants de manière sécurisée et les ajoute à la commande
$Creds = Get-Credential -Message "Veuillez saisir les identifiants pour le proxy $ProxyAddress"
$IWRParams.Add('ProxyCredential', $Creds)
}
}
# -- Exécution du test --
Try {
# Exécution de la requête en utilisant les paramètres définis dans la hashtable
$Response = Invoke-WebRequest @IWRParams
# On vérifie si la réponse contient des mots-clés de la page de blocage
$KeywordFound = $False
Foreach ($Keyword in $BlockPageKeywords) {
If ($Response.Content -match $Keyword) {
$KeywordFound = $True
break
}
}
If ($KeywordFound) {
$Result.ActualResult = "Bloqué"
# $Result.Score = 1
$Result.Details = "Page de blocage détectée."
$Result.StatusCode = $Response.StatusCode
}
Else {
$Result.ActualResult = "Autorisé"
# $Result.Score = 0
$Result.Details = "Le site a été atteint sans blocage."
$Result.StatusCode = $Response.StatusCode
}
}
Catch [System.Net.WebException] {
If ($_.Exception.Status -eq 'Timeout') {
$Result.ActualResult = "Bloqué (Timeout)"
# $Result.Score = 1
$Result.Details = "La requête a expiré, indiquant un blocage probable par le pare-feu ou le proxy."
$Result.StatusCode = $Response.StatusCode
$Result.ResponseTime = "$Timeout"
}
# Elseif ($_.Exception.Response) {
# $Result.Status = "Bloqué (Erreur HTTP)"
# $Result.Score = 1
# $Result.Details = "Réponse HTTP non-200 reçue : $($_.Exception.Response.StatusCode)"
# }
Else {
# On considère les autres erreurs réseau comme un blocage aussi
$Result.ActualResult = "Erreur de Connexion"
$Result.Details = "Impossible de joindre le serveur : $($_.Exception.Status)"
$Result.StatusCode = $Response.StatusCode
}
}
Catch {
$Result.ActualResult = "Erreur Script"
$Result.Details = "Erreur inattendue: $($_.Exception.Message)"
#$Result.StatusCode = 0 <= A trouver
#$Result.ResponseTime = 0 <= A trouver
# Un test en erreur ne doit pas donner de point
return $result
}
# Le test est réussi si l'action attendue correspond au résultat réel.
If (($Result.Expected -eq 'block' -and $Result.ActualResult -eq 'Bloqué') -or ($Result.Expected -eq 'allow' -and $Result.ActualResult -eq 'Autorisé')) {
$Result.TestStatus = "Conforme"
$Result.Score = 1 # Le test est un succès !
$Result.Details += " (Résultat conforme à l'attendu)"
}
Else {
$Result.TestStatus = "Non Conforme"
$Result.Score = 0 # Le test est un échec !
$Result.Details += " (Résultat NON CONFORME; Attendu: $($Result.Expected); Obtenu: $($Result.ActualResult))"
}
Return $Result
}
## Function Generate-HtmlReport
Function Generate-HtmlReport {
Param(
[array]$Results,
[string]$OutputPath
)
Write-ColorOutput "Génération du rapport HTML..." "Yellow"
# Calcul des scores
$Categories = $Results | Group-Object Category
$CategoryScores = @()
Foreach ($Cat in $Categories) {
$Score = Calculate-CategoryScore -Results $Cat.Group
$Grade = Convert-ScoreToGrade -Score $Score
$CategoryScores += [PSCustomObject]@{
Category = $cat.Name
Score = $score
Grade = $grade
Color = $GradeColors[$grade]
TotalUrls = $cat.Group.Count
CorrectResults = ($cat.Group | Where-Object IsCorrect).Count
}
}
# Score global
$globalScore = Calculate-CategoryScore -Results $Results
$globalGrade = Convert-ScoreToGrade -Score $globalScore
# Création du rapport HTML
New-HTML -TitleText "Audit Firewall - Network Reputation Service" -Online -FilePath $OutputPath {
New-HTMLHeader {
New-HTMLText -Text "Audit Firewall - Network Reputation Service" -FontSize 28 -FontWeight bold -Color Blue -Alignment center
New-HTMLText -Text "Rapport généré le $(Get-Date -Format 'dd/MM/yyyy à HH:mm')" -FontSize 14 -Color Gray -Alignment center
}
New-HTMLSection -HeaderText "Résumé Exécutif" -BackgroundColor LightBlue {
New-HTMLPanel {
New-HTMLText -Text "Score Global: $globalScore% - Note: $globalGrade" -FontSize 24 -FontWeight bold -Color $GradeColors[$globalGrade]
New-HTMLText -Text "Total des URLs testées: $($Results.Count)" -FontSize 16
New-HTMLText -Text "URLs correctement filtrées: $(($Results | Where-Object IsCorrect).Count)" -FontSize 16
New-HTMLText -Text "Taux de réussite: $([math]::Round((($Results | Where-Object IsCorrect).Count / $Results.Count) * 100, 2))%" -FontSize 16
}
}
New-HTMLSection -HeaderText "Scores par Catégorie" -BackgroundColor LightGray {
New-HTMLTable -DataTable $categoryScores -HideFooter {
New-HTMLTableHeader -Names "Category", "Score", "Grade", "TotalUrls", "CorrectResults" -Title "Scores par Catégorie"
New-HTMLTableCondition -Name 'Grade' -ComparisonType string -Operator eq -Value 'A+' -BackgroundColor '#28a745' -Color White
New-HTMLTableCondition -Name 'Grade' -ComparisonType string -Operator eq -Value 'A' -BackgroundColor '#52b83a' -Color White
New-HTMLTableCondition -Name 'Grade' -ComparisonType string -Operator eq -Value 'B+' -BackgroundColor '#7ac92e' -Color White
New-HTMLTableCondition -Name 'Grade' -ComparisonType string -Operator eq -Value 'B' -BackgroundColor '#a3da23' -Color Black
New-HTMLTableCondition -Name 'Grade' -ComparisonType string -Operator eq -Value 'C+' -BackgroundColor '#cceb17' -Color Black
New-HTMLTableCondition -Name 'Grade' -ComparisonType string -Operator eq -Value 'C' -BackgroundColor '#f5f90c' -Color Black
New-HTMLTableCondition -Name 'Grade' -ComparisonType string -Operator eq -Value 'D+' -BackgroundColor '#f7d808' -Color Black
New-HTMLTableCondition -Name 'Grade' -ComparisonType string -Operator eq -Value 'D' -BackgroundColor '#f9b604' -Color Black
New-HTMLTableCondition -Name 'Grade' -ComparisonType string -Operator eq -Value 'E+' -BackgroundColor '#fb9500' -Color White
New-HTMLTableCondition -Name 'Grade' -ComparisonType string -Operator eq -Value 'E' -BackgroundColor '#fd7300' -Color White
New-HTMLTableCondition -Name 'Grade' -ComparisonType string -Operator eq -Value 'F+' -BackgroundColor '#ff5100' -Color White
New-HTMLTableCondition -Name 'Grade' -ComparisonType string -Operator eq -Value 'F' -BackgroundColor '#dc3545' -Color White
}
}
New-HTMLSection -HeaderText "Détail des Tests par Catégorie" -BackgroundColor White {
foreach ($category in $categories) {
$catScore = ($categoryScores | Where-Object Category -eq $category.Name).Score
$catGrade = ($categoryScores | Where-Object Category -eq $category.Name).Grade
New-HTMLSection -HeaderText "$($category.Name) - Score: $catScore% ($catGrade)" -BackgroundColor LightYellow -Collapsible {
$detailedResults = $category.Group | Select-Object Url, Reputation, ExpectedAction, Status, IsCorrect, Error
New-HTMLTable -DataTable $detailedResults -HideFooter {
New-HTMLTableCondition -Name 'IsCorrect' -ComparisonType string -Operator eq -Value 'True' -BackgroundColor '#d4edda' -Color '#155724'
New-HTMLTableCondition -Name 'IsCorrect' -ComparisonType string -Operator eq -Value 'False' -BackgroundColor '#f8d7da' -Color '#721c24'
}
}
}
}
New-HTMLSection -HeaderText "Barème de Notation" -BackgroundColor LightGreen -Collapsible {
$gradingScale = @(
[PSCustomObject]@{Grade='A+'; Score='95-100%'; Interpretation='Excellent / Parfait'}
[PSCustomObject]@{Grade='A'; Score='90-95%'; Interpretation='Très bon niveau de filtrage'}
[PSCustomObject]@{Grade='B+'; Score='85-90%'; Interpretation='Très bon'}
[PSCustomObject]@{Grade='B'; Score='80-85%'; Interpretation='Bon, mais quelques ajustements nécessaires'}
[PSCustomObject]@{Grade='C+'; Score='75-80%'; Interpretation='Assez bon'}
[PSCustomObject]@{Grade='C'; Score='70-75%'; Interpretation='Moyen, lacunes importantes'}
[PSCustomObject]@{Grade='D+'; Score='65-70%'; Interpretation='Passable'}
[PSCustomObject]@{Grade='D'; Score='60-65%'; Interpretation='Faible, filtrage inefficace'}
[PSCustomObject]@{Grade='E+'; Score='55-60%'; Interpretation='Très faible'}
[PSCustomObject]@{Grade='E'; Score='50-55%'; Interpretation='Insuffisant'}
[PSCustomObject]@{Grade='F+'; Score='45-50%'; Interpretation='Critique'}
[PSCustomObject]@{Grade='F'; Score='0-45%'; Interpretation='Très faible, action immédiate requise'}
)
New-HTMLTable -DataTable $gradingScale -HideFooter
}
}
Write-ColorOutput "✓ Rapport généré: $OutputPath" "Green"
}
## Function Main
Function Main {
Write-ColorOutput @"
AUDIT FIREWALL - NETWORK REPUTATION SERVICE
Version 1.0
"@ "Cyan"
# Vérification des prérequis
If(-not (Prerequisites)) {
Write-ColorOutput "ERREUR: Les prérequis ne sont pas satisfaits. Arrêt du script." "Red"
Return
}
# Chargement du fichier JSON
Try {
$JsonFile = Join-Path $PSScriptRoot "file-nrs.json"
$Categories = Get-Content $JsonFile -Raw -Encoding UTF8 | ConvertFrom-Json
Write-ColorOutput "✓ Fichier JSON chargé avec $($Categories.categorie.Count) catégories" "Green"
}
Catch {
Write-ColorOutput "ERREUR: Impossible de charger le fichier JSON: $($_.Exception.Message)" "Red"
Return
}
# Création du dossier de sortie
$ReportDate = Get-Date -Format "dddd dd MMMM yyyy-HH mm"
$ReportsDir = Join-Path $PSScriptRoot "Rapports"
$OutputDir = Join-Path $ReportsDir $ReportDate
If (-not (Test-Path $ReportsDir)) {
New-Item -ItemType Directory -Path $ReportsDir -Force | Out-Null
}
If (-not (Test-Path $OutputDir)) {
New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null
}
Write-ColorOutput "`n Dossier de sortie: $outputDir" "Yellow"
# Début des tests
Write-ColorOutput "`n=== DÉBUT DES TESTS ===" "Green"
$StartTime = Get-Date
$AllResults = Check-Categories -Categories $Categories -ProxyUrl $ProxyUrl -ProxyCredential $ProxyCredential -TimeoutSeconds $TimeoutSeconds -BlockPageKeywords $BlockKeywors
$EndTime = Get-Date
$Duration = $EndTime - $StartTime
Write-ColorOutput "`n=== RÉSULTATS FINAUX ===" "Green"
Write-ColorOutput "`n Temps total d'exécution: $($duration.ToString('hh\:mm\:ss'))" "Yellow"
Write-ColorOutput "`n Total des URLs testées: $($allResults.Count)" "Yellow"
# Calcul du score global
$GlobalScore = Calculate-CategoryScore -Results $AllResults
$GlobalGrade = Convert-ScoreToGrade -Score $GlobalScore
Write-ColorOutput "`n `n Score global: $GlobalScore% - Note: $GlobalGrade" "Magenta"
# Génération du rapport HTML
$ReportPath = Join-Path $OutputDir "Audit_Firewall_Report.html"
Generate-HtmlReport -Results $AllResults -OutputPath $ReportPath
# Sauvegarde des résultats en JSON
$JsonResultsPath = Join-Path $outputDir "Results.json"
$AllResults | ConvertTo-Json -Depth 10 | Out-File -FilePath $JsonResultsPath -Encoding UTF8
Write-ColorOutput "✓ Résultats sauvegardés: $JsonResultsPath" "Green"
Write-ColorOutput "`n=== AUDIT TERMINÉ ===" "Green"
Write-ColorOutput "Rapport disponible à: $ReportPath" "Cyan"
# Ouverture automatique du rapport
If (Get-Command "Start-Process" -ErrorAction SilentlyContinue) {
$OpenReport = Read-Host "Voulez-vous ouvrir le rapport maintenant? (O/N)"
If ($OpenReport -eq "O" -or $OpenReport -eq "o" -or $OpenReport -eq "Y" -or $OpenReport -eq "y") {
Start-Process $ReportPath
}
}
}
### Main
Clear-Host
# Exécution du script principal
Try {
Main
}
Catch {
Write-ColorOutput "ERREUR FATALE: $($_.Exception.Message)" "Red"
Write-ColorOutput "Stack Trace: $($_.ScriptStackTrace)" "Red"
}