Opciones débiles en políticas anti-phishing
Compara tus políticas anti-phishing, de Safe Links y de Safe Attachments con el nivel Standard de Microsoft y señala cada opción por debajo.
Ejemplo en México
Constructora en León, 85 personas
Tras un intento de fraude con una factura de proveedor suplantado, la dirección pide revisar cómo está configurada la protección del correo.
.\get-politicas-antiphishing.ps1 -RutaCsv .\politicas.csvObtiene las opciones por debajo de Standard y activa la protección contra suplantación para sus principales proveedores.
Cómo implementarlo
- Instala el módulo si no lo tienes: Install-Module ExchangeOnlineManagement -Scope CurrentUser.
- Corre el script e inicia sesión con una cuenta con el rol Lector de seguridad.
- Revisa en el CSV primero las filas con Riesgo Alto.
- Corrige esas opciones en el portal de Microsoft Defender o activa la directiva preestablecida Standard.
Ver el código completo de get-politicas-antiphishing.ps1
<#
.SYNOPSIS
¿Qué opciones de mis políticas anti-phishing, Safe Links y Safe Attachments están débiles?
.DESCRIPTION
Compara cada política con el nivel Standard que Microsoft recomienda y lista las opciones por
debajo. Las opciones que el cmdlet no devuelve se omiten, y si tu licencia no incluye Safe Links
o Safe Attachments, el reporte lo indica en vez de fallar.
Solo lectura: no cambia nada en el tenant.
.PARAMETER RutaCsv
Ruta del CSV de salida. Si se omite, solo se muestra en pantalla.
.EXAMPLE
.\get-politicas-antiphishing.ps1 -RutaCsv .\politicas.csv
.NOTES
Permisos: Ninguno de Graph; usa roles de Exchange Online (ExchangeOnlineManagement)
Rol mínimo: Lector de seguridad
Licencia: Anti-phishing básico en todo buzón en la nube. Safe Links, Safe Attachments y protección contra suplantación requieren Microsoft Defender for Office 365 Plan 1 o superior (Plan 1 viene en Microsoft 365 Business Premium)
Licencia del código: MIT. Se entrega TAL CUAL, sin garantía. Pruébalo primero en un tenant de pruebas.
#>
[CmdletBinding()]
param(
[string]$RutaCsv
)
$ErrorActionPreference = 'Stop'
if (-not (Get-Command Connect-ExchangeOnline -ErrorAction SilentlyContinue)) {
throw 'Falta el módulo. Instálalo con: Install-Module ExchangeOnlineManagement -Scope CurrentUser'
}
Connect-ExchangeOnline -ShowBanner:$false
# Debil lista los valores por debajo de Standard en "Recommended settings for EOP and Defender for Office 365".
function Regla($opcion, $debil, $recomendado, $riesgo, $efecto) {
@{ Opcion = $opcion; Debil = $debil; Recomendado = $recomendado; Riesgo = $riesgo; Efecto = $efecto }
}
$revisiones = @(
@{
Tipo = 'Anti-phishing'
Cmdlet = 'Get-AntiPhishPolicy'
Reglas = @(
Regla 'Enabled' @($false) 'True' 'Alto' 'La política está apagada.'
Regla 'EnableSpoofIntelligence' @($false) 'True' 'Alto' 'No se detecta la suplantación de remitentes.'
Regla 'HonorDmarcPolicy' @($false) 'True' 'Medio' 'No se respeta la política DMARC del dominio que envía.'
Regla 'EnableFirstContactSafetyTips' @($false) 'True' 'Bajo' 'No se avisa al recibir correo de un remitente nuevo.'
Regla 'EnableUnauthenticatedSender' @($false) 'True' 'Bajo' 'No se marca al remitente sin autenticar.'
Regla 'EnableViaTag' @($false) 'True' 'Bajo' 'No se muestra la etiqueta "via".'
Regla 'PhishThresholdLevel' @(1, 2) '3 o más' 'Medio' 'El umbral de phishing es menos agresivo que el recomendado.'
Regla 'EnableTargetedUserProtection' @($false) 'True, con lista de usuarios' 'Alto' 'No se protege a usuarios clave de la suplantación.'
Regla 'EnableOrganizationDomainsProtection' @($false) 'True' 'Alto' 'No se protegen tus dominios de la suplantación.'
Regla 'EnableTargetedDomainsProtection' @($false) 'True, con lista de dominios' 'Medio' 'No se protegen dominios de socios o proveedores.'
Regla 'EnableMailboxIntelligence' @($false) 'True' 'Medio' 'La inteligencia de buzón está apagada.'
Regla 'EnableMailboxIntelligenceProtection' @($false) 'True' 'Medio' 'La inteligencia de buzón no actúa contra la suplantación.'
Regla 'TargetedUserProtectionAction' @('NoAction') 'Quarantine' 'Alto' 'La suplantación de usuarios se detecta, pero no se actúa.'
Regla 'TargetedDomainProtectionAction' @('NoAction') 'Quarantine' 'Alto' 'La suplantación de dominios se detecta, pero no se actúa.'
Regla 'MailboxIntelligenceProtectionAction' @('NoAction') 'MoveToJmf' 'Medio' 'Lo que detecta la inteligencia de buzón no recibe acción.'
Regla 'EnableSimilarUsersSafetyTips' @($false) 'True' 'Bajo' 'No se avisa de usuarios parecidos.'
Regla 'EnableSimilarDomainsSafetyTips' @($false) 'True' 'Bajo' 'No se avisa de dominios parecidos.'
Regla 'EnableUnusualCharactersSafetyTips' @($false) 'True' 'Bajo' 'No se avisa de caracteres inusuales en el remitente.'
)
}
@{
Tipo = 'Safe Links'
Cmdlet = 'Get-SafeLinksPolicy'
Reglas = @(
Regla 'EnableSafeLinksForEmail' @($false) 'True' 'Alto' 'Safe Links no revisa las ligas del correo.'
Regla 'EnableSafeLinksForTeams' @($false) 'True' 'Medio' 'Safe Links no revisa las ligas de Microsoft Teams.'
Regla 'EnableSafeLinksForOffice' @($false) 'True' 'Medio' 'Safe Links no revisa las ligas en aplicaciones de Office.'
Regla 'EnableForInternalSenders' @($false) 'True' 'Medio' 'No se revisan las ligas del correo interno: una cuenta tomada las puede repartir.'
Regla 'ScanUrls' @($false) 'True' 'Alto' 'No se analizan en tiempo real las ligas sospechosas.'
Regla 'DeliverMessageAfterScan' @($false) 'True' 'Medio' 'El correo se entrega antes de terminar de analizar sus ligas.'
Regla 'DisableUrlRewrite' @($true) 'False' 'Medio' 'Las ligas no se reescriben, así que dependen solo de la revisión por API.'
Regla 'TrackClicks' @($false) 'True' 'Medio' 'No se registran los clics, y pierdes la evidencia para investigar.'
Regla 'AllowClickThrough' @($true) 'False' 'Alto' 'El usuario puede seguir a la liga original aunque Safe Links lo advierta.'
)
}
@{
Tipo = 'Safe Attachments'
Cmdlet = 'Get-SafeAttachmentPolicy'
Reglas = @(
Regla 'Enable' @($false) 'True' 'Alto' 'La política no analiza adjuntos.'
Regla 'Action' @('Allow') 'Block' 'Alto' 'Los adjuntos con malware se entregan: el modo Monitor solo observa.'
)
}
)
$filas = try {
foreach ($revision in $revisiones) {
if (-not (Get-Command $revision.Cmdlet -ErrorAction SilentlyContinue)) {
[pscustomobject]@{ Tipo = $revision.Tipo; Politica = '-'; Opcion = '-'; ValorActual = '-'; Recomendado = '-'; Riesgo = '-'; Hallazgo = "No disponible: $($revision.Cmdlet) no existe en tu sesión. Revisa la licencia o el rol." }
continue
}
foreach ($politica in & $revision.Cmdlet) {
$debiles = @(foreach ($regla in $revision.Reglas) {
$valor = $politica.($regla.Opcion)
# Null significa que tu licencia o la versión del cmdlet no expone esa opción.
if ($null -eq $valor -or $valor -notin $regla.Debil) { continue }
[pscustomobject]@{ Tipo = $revision.Tipo; Politica = $politica.Name; Opcion = $regla.Opcion; ValorActual = "$valor"; Recomendado = $regla.Recomendado; Riesgo = $regla.Riesgo; Hallazgo = $regla.Efecto }
})
if ($debiles) { $debiles } else {
[pscustomobject]@{ Tipo = $revision.Tipo; Politica = $politica.Name; Opcion = '-'; ValorActual = '-'; Recomendado = '-'; Riesgo = '-'; Hallazgo = 'Sin debilidades frente a Standard' }
}
}
}
} finally {
Disconnect-ExchangeOnline -Confirm:$false
}
$hallazgos = @($filas | Where-Object Opcion -NE '-')
Write-Host "Opciones débiles: $($hallazgos.Count). Riesgo alto: $(@($hallazgos | Where-Object Riesgo -EQ 'Alto').Count)"
if ($RutaCsv) {
# UTF-8 con BOM para que Excel en español muestre bien los acentos.
$filas | Export-Csv -Path $RutaCsv -NoTypeInformation -Encoding utf8BOM
Write-Host "CSV guardado en $RutaCsv"
} else {
$filas | Format-Table -AutoSize
}