# Script d'Audit Firewall - Network Reputation Service # Auteur: Hubert Cornet # Date: 03/09/2025 # Version: 1.2 Clear-Host # Configuration globale $ErrorActionPreference = "Continue" $WarningPreference = "SilentlyContinue" # Couleurs pour les grades $GradeColors = @{ 'A+' = '#28a745' 'A' = '#52b83a' 'B+' = '#7ac92e' 'B' = '#a3da23' 'C+' = '#cceb17' 'C' = '#f5f90c' 'D+' = '#f7d808' 'D' = '#f9b604' 'E+' = '#fb9500' 'E' = '#fd7300' 'F+' = '#ff5100' 'F' = '#dc3545' } ### Functions ### ## Function Write-ColorOutput : pour afficher du texte en couleur Function Write-ColorOutput { Param( [string]$Text, [string]$Color = "White" ) Try{ Write-Host $Text -ForegroundColor $Color } Catch { Write-Host $Text } } ## Function Prerequisites : vérifie les prérequis 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://gitea.tips-of-mine.com/Tips-Of-Mine/Powershell/src/branch/main/cybersecurity/Network%20Reputation%20Service/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 : pour tester les catégories et URLs 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 -Id 1 -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 "`nDescription: $($Category.description)" "Gray" $CategoryResults = @() $UrlCount = 0 Foreach($UrlObj in $Category.urls) { $UrlCount++ Show-ProgressBar -Id 2 -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 -Id 1 -Activity "Test des catégories" -Completed Write-Progress -Id 2 -Activity "Test des URLs" -Completed return $AllResults } ## Function Show-ProgressBar : affiche une barre de progression Function Show-ProgressBar { Param( [int]$Current, [int]$Total, [int]$Id, [string]$Activity, [string]$Status = "" ) $Percent = [math]::Round(($Current / $Total) * 100, 1) Write-Progress -Id $Id -Activity $Activity -Status "$Status ($Current/$Total)" -PercentComplete $Percent } ## FunctionCalculate-CategoryScore : calcule le score d'une catégorie 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 : convertit un score en une note 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 : teste une URL et détermine si elle est bloquée ou autorisée 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.Details = "Page de blocage détectée." $Result.StatusCode = $Response.StatusCode } Else { $Result.ActualResult = "Autorisé" $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.Details = "La requête a expiré, indiquant un blocage probable par le pare-feu ou le proxy." $Result.StatusCode = $Response.StatusCode $Result.ResponseTime = "$Timeout" } 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)" # 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 : génère le rapport HTML 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 Results = $Cat.Group } } # Score global $GlobalScore = Calculate-CategoryScore -Results $Results $GlobalGrade = Convert-ScoreToGrade -Score $GlobalScore $GlobalColor = $GradeColors[$GlobalGrade] # Génération du HTML $HtmlContent = @" Audit Firewall - Network Reputation Service

🛡️ Audit Firewall - Network Reputation Service

Rapport généré le $(Get-Date -Format 'dd/MM/yyyy à HH:mm')

📊 Résumé Exécutif

$globalGrade
$globalScore%
Score Global
📋 Total des URLs testées : $($Results.Count)
✅ URLs correctement filtrées : $(($Results | Where-Object IsCorrect).Count)
🎯 Taux de réussite : $([math]::Round((($Results | Where-Object IsCorrect).Count / $Results.Count) * 100, 2))%
📅 Date du test : $(Get-Date -Format 'dd/MM/yyyy HH:mm')

📈 Scores par Catégorie

"@ # Ajout des lignes du tableau Foreach($CatScore in $CategoryScores) { $HtmlContent += @" "@ } $HtmlContent += @"
Catégorie Score (%) Note URLs Totales Résultats Corrects
$($catScore.Category) $($catScore.Score)% $($catScore.Grade) $($catScore.TotalUrls) $($catScore.CorrectResults)

🔍 Détail des Tests par Catégorie

"@ # Ajout des catégories $CategoryIndex = 0 Foreach($CatScore in $CategoryScores) { $CategoryIndex++ $HtmlContent += @"
$($CatScore.Category)
$($CatScore.Grade) - $($CatScore.Score)%
"@ # Ajout des résultats de chaque URL Foreach($Result in $CatScore.Results) { $RowClass = if($Result.IsCorrect) { "correct" } else { "incorrect" } $CorrectText = if($Result.IsCorrect) { "✅ Oui" } else { "❌ Non" } $HtmlContent += @" "@ } $HtmlContent += @"
URL Réputation Action Attendue Statut Correct
$($result.Url.Substring(0, [Math]::Min(30, $Result.Url.Length)))$(if($Result.Url.Length -gt 30){"..."}) $($Result.Reputation) $($Result.ExpectedAction) $($Result.Status) $CorrectText
"@ } $HtmlContent += @"

📏 Barème de Notation

"@ # Ajout du barème de notation $gradingScale = @( @{Grade='A+'; Score='95-100%'; Interpretation='Excellent / Parfait'; Color='#28a745'} @{Grade='A'; Score='90-95%'; Interpretation='Très bon niveau de filtrage'; Color='#52b83a'} @{Grade='B+'; Score='85-90%'; Interpretation='Très bon'; Color='#7ac92e'} @{Grade='B'; Score='80-85%'; Interpretation='Bon, quelques ajustements nécessaires'; Color='#a3da23'} @{Grade='C+'; Score='75-80%'; Interpretation='Assez bon'; Color='#cceb17'} @{Grade='C'; Score='70-75%'; Interpretation='Moyen, lacunes importantes'; Color='#f5f90c'} @{Grade='D+'; Score='65-70%'; Interpretation='Passable'; Color='#f7d808'} @{Grade='D'; Score='60-65%'; Interpretation='Faible, filtrage inefficace'; Color='#f9b604'} @{Grade='E+'; Score='55-60%'; Interpretation='Très faible'; Color='#fb9500'} @{Grade='E'; Score='50-55%'; Interpretation='Insuffisant'; Color='#fd7300'} @{Grade='F+'; Score='45-50%'; Interpretation='Critique'; Color='#ff5100'} @{Grade='F'; Score='0-45%'; Interpretation='Très faible, action immédiate requise'; Color='#dc3545'} ) Foreach($GradeInfo in $GradingScale) { $HtmlContent += @"
$($GradeInfo.Grade)
$($GradeInfo.Score)
$($GradeInfo.Interpretation)
"@ } $HtmlContent += @"
"@ # Écriture du fichier HTML Try{ $HtmlContent | Out-File -FilePath $OutputPath -Encoding UTF8 Write-ColorOutput "✓ Rapport généré: $OutputPath" "Green" } Catch { Write-ColorOutput "ERREUR: Impossible de générer le rapport: $($_.Exception.Message)" "Red" } } ## Function Main : fonction principale 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 "`n Rapport disponible à: $ReportPath" "Cyan" # Ouverture automatique du rapport If(Get-Command "Start-Process" -ErrorAction SilentlyContinue) { $OpenReport = Read-Host "`n 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" }