tests/Test-Assessment.25413.ps1
|
<#
.SYNOPSIS Sensitive data exfiltration through file transfers is prevented by network content filtering policies. .DESCRIPTION Verifies that file policies are configured in Global Secure Access and enforced through filtering profiles. The test passes if file policies exist and are enforced either through the Baseline Profile or through Security Profiles assigned to Conditional Access policies. #> function Test-Assessment-25413 { [ZtTest( Category = 'Global Secure Access', ImplementationCost = 'High', MinimumLicense = ('Entra_Premium_Internet_Access'), Pillar = 'Network', RiskLevel = 'High', SfiPillar = 'Protect networks', TenantType = ('Workforce'), TestId = 25413, Title = 'Sensitive data exfiltration through file transfers is prevented by network content filtering policies', UserImpact = 'Medium' )] [CmdletBinding()] param() # Define constants [int]$BASELINE_PROFILE_PRIORITY = 65000 #region Data Collection Write-PSFMessage '🟦 Start' -Tag Test -Level VeryVerbose $activity = 'Checking file policy configuration for data exfiltration prevention' Write-ZtProgress -Activity $activity -Status 'Querying file policies' # Step 1: Get file policies (undocumented endpoint - handle errors gracefully) $filePolicies = $null $errorMsg = $null try { $filePolicies = Invoke-ZtGraphRequest -RelativeUri 'networkAccess/filePolicies' -ApiVersion beta } catch { $errorMsg = $_.Exception.Message Write-PSFMessage $_.Exception.Message -Tag Test -Level Error } # Step 2: Get filtering profiles with linked policies Write-ZtProgress -Activity $activity -Status 'Querying filtering profiles and linked policies' $filteringProfiles = $null try { $filteringProfiles = Invoke-ZtGraphRequest -RelativeUri 'networkAccess/filteringProfiles' -QueryParameters @{ '$select' = 'id,name,description,state,version,priority' '$expand' = 'policies($select=id,state;$expand=policy($select=id,name,version))' } -ApiVersion beta } catch { if ($null -eq $errorMsg) { $errorMsg = $_.Exception.Message } Write-PSFMessage $_.Exception.Message -Tag Test -Level Error } # Step 3: Get all Conditional Access policies Write-ZtProgress -Activity $activity -Status 'Querying Conditional Access policies' $allCAPolicies = Get-ZtConditionalAccessPolicy # Collect all linked profiles $allLinkedProfiles = @() foreach ($filePolicy in $filePolicies) { $linkedProfiles = Find-ZtProfilesLinkedToPolicy -PolicyId $filePolicy.id -FilteringProfiles $filteringProfiles -CAPolicies $allCAPolicies -BaselinePriority $BASELINE_PROFILE_PRIORITY -PolicyLinkType 'filePolicyLink' -PolicyRules $filePolicy foreach ($profileLink in $linkedProfiles) { $allLinkedProfiles += [PSCustomObject]@{ ProfileId = $profileLink.ProfileId ProfileName = $profileLink.ProfileName ProfileType = $profileLink.ProfileType ProfileState = $profileLink.ProfileState ProfilePriority = $profileLink.ProfilePriority PolicyLinkState = $profileLink.PolicyLinkState PassesCriteria = $profileLink.PassesCriteria CAPolicy = $profileLink.CAPolicy } } } #endregion Data Collection #region Assessment Logic # Handle API errors early if ($errorMsg) { $passed = $false $testResultMarkdown = "❌ Unable to query Global Secure Access API endpoints. This may indicate the feature is not available in your tenant or the API has changed. Error: $errorMsg" } # Pass if any profile passes criteria (enabled baseline OR enabled security profile with CA) elseif (($allLinkedProfiles | Where-Object { $_.PassesCriteria -and $_.ProfileState -eq 'enabled' -and $_.PolicyLinkState -eq 'enabled' }).Count -gt 0) { $passed = $true $testResultMarkdown = @" ✅ File policies are configured and actively enforced through a filtering profile, protecting against data exfiltration through unmonitored file transfers. %TestResult% "@ } elseif ($null -eq $filePolicies -or $filePolicies.Count -eq 0) { $passed = $false $testResultMarkdown = "❌ No file policy is configured. File transfers are unmonitored and the organization is exposed to data exfiltration risk.`n`n%TestResult%" } else { $passed = $false $testResultMarkdown = "❌ File policies are either not configured or not linked to an active filtering profile, leaving file transfers unmonitored and exposing the organization to data exfiltration risk.`n`n%TestResult%" } #endregion Assessment Logic #region Report Generation $mdInfo = '' # Table 1: File Policy Configuration if ($filePolicies -and $filePolicies.Count -gt 0) { $table1Title = 'File Policy Configuration' $table1Link = 'https://entra.microsoft.com/#view/Microsoft_Azure_Network_Access/SecurityFiltering.ReactView' $table1Template = @' ## [{0}]({1}) | File Policy Name | Default Action | | :--------------- | :------------- | {2} '@ $table1Rows = '' foreach ($fp in $filePolicies) { $fpName = Get-SafeMarkdown -Text $fp.name $defaultAction = if ($fp.settings.defaultAction) { $fp.settings.defaultAction } else { 'N/A' } $fpLink = "https://entra.microsoft.com/#view/Microsoft_Azure_Network_Access/EditFilePolicyMenuBlade.MenuView/~/basics/policyId/$($fp.id)" $table1Rows += "| [$fpName]($fpLink) | $defaultAction |`n" } $mdInfo += $table1Template -f $table1Title, $table1Link, $table1Rows } # Table 2: Filtering Profile Linkage (unified - baseline and security profiles) if ($allLinkedProfiles.Count -gt 0) { $table2Title = 'Filtering Profile Linkage' $table2Link = 'https://entra.microsoft.com/#view/Microsoft_Azure_Network_Access/SecurityProfiles.ReactView' $table2Template = @' ## [{0}]({1}) | Linked Profile Name | Profile State | Policy Link State | | :------------------ | :------------ | :---------------- | {2} '@ $table2Rows = '' foreach ($profile in ($allLinkedProfiles | Sort-Object -Property ProfilePriority)) { $profileLink = "https://entra.microsoft.com/#view/Microsoft_Azure_Network_Access/EditProfileMenuBlade.MenuView/~/basics/profileId/$($profile.ProfileId)" $profileName = Get-SafeMarkdown -Text $profile.ProfileName $table2Rows += "| [$profileName]($profileLink) | $($profile.ProfileState) | $($profile.PolicyLinkState) |`n" } $mdInfo += $table2Template -f $table2Title, $table2Link, $table2Rows } # Table 3: Conditional Access Enforcement $caPoliciesForReport = @($allLinkedProfiles.CAPolicy | Where-Object { $null -ne $_ } | Sort-Object -Property Id -Unique) if ($caPoliciesForReport.Count -gt 0) { $table3Title = 'Conditional Access Enforcement' $table3Link = 'https://entra.microsoft.com/#view/Microsoft_AAD_ConditionalAccess/ConditionalAccessBlade/~/Policies' $table3Template = @' ## [{0}]({1}) | CA Policy Name | CA Policy State | | :------------- | :-------------- | {2} '@ $table3Rows = '' foreach ($ca in ($caPoliciesForReport | Sort-Object -Property DisplayName)) { $caLink = "https://entra.microsoft.com/#view/Microsoft_AAD_ConditionalAccess/PolicyBlade/policyId/$($ca.Id)" $caName = Get-SafeMarkdown -Text $ca.DisplayName $table3Rows += "| [$caName]($caLink) | $($ca.State) |`n" } $mdInfo += $table3Template -f $table3Title, $table3Link, $table3Rows } $testResultMarkdown = $testResultMarkdown -replace '%TestResult%', $mdInfo #endregion Report Generation $params = @{ TestId = '25413' Status = $passed Result = $testResultMarkdown } Add-ZtTestResultDetail @params } |