feat(dlp): add enforcement — USB write-block, print cancel, clipboard clear

Phase 2.5: when DLP policy rule has action="block", the collector
now actively prevents the action instead of just logging:

- USB: Set-Disk -IsReadOnly via Get-Partition/Get-Disk pipeline
- Print: Remove-CimInstance Win32_PrintJob for matching jobs
- Clipboard: Set-Clipboard -Value $null to clear sensitive content

Each enforcement adds enforced=true/false to incident telemetry.
Windows balloon notification shown to user on every block action.
Backward-compatible: existing action="alert" rules unchanged.

Co-Authored-By: Fashion Lisa <igor04091968@gmail.com>
This commit is contained in:
Devin AI
2026-05-03 20:21:39 +00:00
co-authored by Fashion Lisa
parent 36e4255ad9
commit 2bab84f9f9
4 changed files with 369 additions and 6 deletions
+117 -3
View File
@@ -215,6 +215,99 @@ function Capture-IncidentScreenshot {
}
}
# ---------------------------------------------------------------------------
# Enforcement functions (action = "block")
# ---------------------------------------------------------------------------
function Show-EnforcementNotification {
param(
[Parameter(Mandatory = $true)][string]$Title,
[Parameter(Mandatory = $true)][string]$Body
)
try {
Add-Type -AssemblyName System.Windows.Forms -ErrorAction SilentlyContinue
$icon = New-Object System.Windows.Forms.NotifyIcon
$icon.Icon = [System.Drawing.SystemIcons]::Warning
$icon.BalloonTipTitle = $Title
$icon.BalloonTipText = $Body
$icon.BalloonTipIcon = [System.Windows.Forms.ToolTipIcon]::Warning
$icon.Visible = $true
$icon.ShowBalloonTip(5000)
Start-Sleep -Milliseconds 200
$icon.Dispose()
}
catch {
Write-EndpointLog ("notification failed: {0}" -f $_.Exception.Message)
}
}
function Invoke-ClipboardEnforcement {
[OutputType([bool])]
param()
try {
Set-Clipboard -Value $null -ErrorAction Stop
Write-EndpointLog "enforcement: clipboard cleared"
return $true
}
catch {
Write-EndpointLog ("enforcement: clipboard clear failed: {0}" -f $_.Exception.Message)
return $false
}
}
function Invoke-UsbWriteBlockEnforcement {
[OutputType([bool])]
param(
[Parameter(Mandatory = $true)][string]$DriveLetter
)
try {
$partition = Get-Partition -DriveLetter ($DriveLetter.TrimEnd(':')) -ErrorAction Stop
$disk = Get-Disk -Number $partition.DiskNumber -ErrorAction Stop
if ($disk.BusType -ne 'USB') {
Write-EndpointLog ("enforcement: skip non-USB disk {0} bus={1}" -f $disk.Number, $disk.BusType)
return $false
}
if (-not $disk.IsReadOnly) {
Set-Disk -Number $disk.Number -IsReadOnly $true -ErrorAction Stop
Write-EndpointLog ("enforcement: USB disk {0} ({1}) set read-only" -f $disk.Number, $DriveLetter)
}
return $true
}
catch {
Write-EndpointLog ("enforcement: USB write-block failed drive={0}: {1}" -f $DriveLetter, $_.Exception.Message)
return $false
}
}
function Invoke-PrintJobEnforcement {
[OutputType([bool])]
param(
[Parameter(Mandatory = $true)][string]$PrinterName,
[string]$DocumentName,
[string]$Owner
)
$cancelled = $false
try {
$jobs = Get-CimInstance Win32_PrintJob -ErrorAction SilentlyContinue
foreach ($job in @($jobs)) {
$jobPrinter = [string]$job.Name
$jobOwner = [string]$job.Owner
$jobDoc = [string]$job.Document
$matchPrinter = ($jobPrinter -like "*$PrinterName*")
$matchOwner = (-not $Owner) -or ($jobOwner -like "*$Owner*") -or ($jobOwner -like "*$env:USERNAME*")
if ($matchPrinter -and $matchOwner) {
Remove-CimInstance -InputObject $job -ErrorAction Stop
Write-EndpointLog ("enforcement: print job cancelled id={0} printer={1} doc={2}" -f $job.JobId, $jobPrinter, $jobDoc)
$cancelled = $true
}
}
}
catch {
Write-EndpointLog ("enforcement: print cancel failed printer={0}: {1}" -f $PrinterName, $_.Exception.Message)
}
return $cancelled
}
function Get-StringHash {
param([AllowNull()][string]$Value)
if ($null -eq $Value) { return $null }
@@ -321,11 +414,18 @@ function Evaluate-ClipboardRules {
$severity = if ($rule.severity) { [string]$rule.severity } else { [string]$script:Policy.defaults.severity }
$message = if ($rule.message) { [string]$rule.message } else { "Clipboard rule matched: $ruleId" }
$enforced = $false
if ($action -eq 'block') {
$enforced = Invoke-ClipboardEnforcement
Show-EnforcementNotification -Title 'DLP: буфер обмена очищен' -Body $message
}
Send-DlpIncidentHeartbeat -RuleId $ruleId -Action $action -Severity $severity -Message $message -SignalType 'clipboard' -Data @{
clipboardHash = $ClipboardHash
clipboardLength = $ClipboardText.Length
enforced = $enforced
}
Write-EndpointLog ("incident clipboard rule={0} action={1} severity={2}" -f $ruleId, $action, $severity)
Write-EndpointLog ("incident clipboard rule={0} action={1} severity={2} enforced={3}" -f $ruleId, $action, $severity, $enforced)
}
}
@@ -349,11 +449,18 @@ function Evaluate-UsbRules {
$severity = if ($rule.severity) { [string]$rule.severity } else { [string]$script:Policy.defaults.severity }
$message = if ($rule.message) { [string]$rule.message } else { "USB rule matched: $ruleId" }
$enforced = $false
if ($action -eq 'block') {
$enforced = Invoke-UsbWriteBlockEnforcement -DriveLetter $DriveLetter
Show-EnforcementNotification -Title 'DLP: USB заблокирован для записи' -Body $message
}
Send-DlpIncidentHeartbeat -RuleId $ruleId -Action $action -Severity $severity -Message $message -SignalType 'usb_insert' -Data @{
driveLetter = $DriveLetter
volumeName = $VolumeName
enforced = $enforced
}
Write-EndpointLog ("incident usb rule={0} action={1} severity={2} drive={3}" -f $ruleId, $action, $severity, $DriveLetter)
Write-EndpointLog ("incident usb rule={0} action={1} severity={2} drive={3} enforced={4}" -f $ruleId, $action, $severity, $DriveLetter, $enforced)
}
}
@@ -387,12 +494,19 @@ function Evaluate-PrintRules {
$severity = if ($rule.severity) { [string]$rule.severity } else { [string]$script:Policy.defaults.severity }
$message = if ($rule.message) { [string]$rule.message } else { "Print rule matched: $ruleId" }
$enforced = $false
if ($action -eq 'block') {
$enforced = Invoke-PrintJobEnforcement -PrinterName $PrinterName -DocumentName $DocumentName -Owner $Owner
Show-EnforcementNotification -Title 'DLP: печать заблокирована' -Body $message
}
Send-DlpIncidentHeartbeat -RuleId $ruleId -Action $action -Severity $severity -Message $message -SignalType 'print_job' -Data @{
printerName = $PrinterName
documentName = $DocumentName
owner = $Owner
enforced = $enforced
}
Write-EndpointLog ("incident print rule={0} action={1} severity={2} printer={3}" -f $ruleId, $action, $severity, $PrinterName)
Write-EndpointLog ("incident print rule={0} action={1} severity={2} printer={3} enforced={4}" -f $ruleId, $action, $severity, $PrinterName, $enforced)
}
}