SAST- En DAST-implementatie Binnen De Nederlandse Baseline Voor Veilige Cloud

💼 Management Samenvatting

Statisch (SAST) en dynamisch (DAST) testen vormen het ruggengraatduo van veilige softwareontwikkeling. Zonder structurele inzet op deze tests blijven kwetsbaarheden pas zichtbaar na productie, wanneer herstel duur is en publieke dienstverlening al onder druk staat. Deze bijdrage beschrijft hoe overheden SAST en DAST integraal invoeren, meten en automatiseren binnen de Nederlandse Baseline voor Veilige Cloud.

Aanbeveling
DIRECT_AANPAKKEN
Risico zonder
High
Risk Score
8/10
Implementatie
380u (tech: 220u)
Van toepassing op:
Microsoft 365
Azure DevOps
GitHub Enterprise
Azure
Power Platform

BIO, AVG en NIS2 eisen aantoonbare beheersing van softwareketens. Tegelijkertijd neemt de druk op ontwikkelteams toe door versneld beleid en verouderde applicaties die naar de cloud migreren. Zonder expliciet kader voor testdiepte, scope en rapportage ontstaan versnipperde tools, onbetrouwbare dashboards en een vals gevoel van veiligheid. Hiermee dreigen audits te stranden en blijft het bestuur afhankelijk van losse kwaliteitsverklaringen.

PowerShell Modules Vereist
Primary API: Azure DevOps REST API, GitHub Advanced Security API, Microsoft Defender for Cloud Apps API
Connection: Invoke-RestMethod met service principals of PATs; in DebugMode worden uitsluitend sampledata gebruikt
Required Modules: Az.Accounts, Az.DevOps, Microsoft.Graph.Authentication

Implementatie

Dit artikel levert een governance- en uitvoeringsmodel waarmee CIO-offices, CISO’s en DevSecOps-teams SAST en DAST koppelen aan architectuurprincipes, CI/CD-processen en bewijslasten. We behandelen besluitvorming, procesontwerp, tooling, leveranciersafspraken en meetwaarden. Het gekoppelde PowerShell-script genereert lokaal een maturiteitsscore, simuleert scanresultaten en vertaalt bevindingen naar herstelacties zodat teams direct kunnen oefenen zonder productiegegevens.

Governance, scope en kwaliteitsnormen

Het fundament van een volwassen SAST- en DAST-programma ligt bij duidelijke governance. Publieke organisaties bepalen eerst wie verantwoordelijk is voor policy, tooling, rapportage en budget. Bestuurders leggen vast dat geen enkel softwareproject naar acceptatie gaat zonder aantoonbaar doorlopen SAST- en DAST-controles. Deze verplichting wordt opgenomen in projectstartarchitecturen, aanbestedingsdossiers en serviceafspraken met shared service centra. Daardoor is vooraf helder wie welke kwaliteitseis bewaakt en hoe escalaties verlopen wanneer teams willen afwijken.

Scopebepaling voorkomt discussies over uitzonderingen. Het programma onderscheidt bedrijfskritische toepassingen, kernregistraties en ondersteunende apps en definieert per klasse welke analysetools, rulesets en frequenties minimaal gelden. Voor bedrijfskritische ketens behoort broncode in elke commit tot de scope; ondersteunende apps kunnen volstaan met nightly scans. Voor low-code oplossingen in Power Platform worden statische validators ingezet die canvas-apps, Power Fx-formules en Dataverse-tabellen toetsen op data-exfiltratie of te brede machtigingen. Door deze segmentatie ontstaat focus, terwijl risicovolle systemen nooit buiten beeld raken.

Kwaliteitsnormen moeten aantoonbaar aansluiten bij BIO-paragrafen, AVG-artikel 32 en NIS2 artikel 21. Dat betekent dat regels niet beperkt blijven tot technische kwetsbaarheden, maar ook rekening houden met encryptiestandaarden, logging, privacy-by-design en integraties met identiteitsvoorzieningen. Architectuurboards valideren daarom dat SAST-regelsets de organisatiebrede cryptopolicy volgen en dat DAST-scripts scenario’s bevatten voor federatieve authenticatie, sessiebeheer en API-rate limiting. Zo ontstaat een directe koppeling tussen beleid en testinzet, wat auditors in staat stelt om steekproeven te herleiden naar formele besluiten.

Governance eindigt niet bij beleid. Er worden concrete meetwaarden vastgesteld zoals percentage repositories met verplichte SAST-checks, gemiddelde doorlooptijd van bevinding tot oplossing en het aantal releases dat door DAST wordt geblokkeerd wegens kritieke risico’s. Deze indicatoren worden opgenomen in het reguliere P&C-ritme, waardoor bestuurders kwartaalrapportages ontvangen die SAST/DAST-resultaten naast financiële en projectstatussen plaatsen. Door rapportages te combineren met lessons learned ontstaat een continue verbetercyclus die voorkomt dat testen wordt gezien als een technische randzaak.

Procesarchitectuur en geïntegreerde toolketen

Gebruik PowerShell-script sast-dast-implementation.ps1 (functie Invoke-SastDastAssessment) – Voert een lokale simulatie uit met sampledata, berekent nalevingsscores per scanfase en genereert direct een rapport met verbetervoorstellen..

Procesarchitectuur begint bij CI/CD. Elke pipeline bevat een standaard sjabloon waarin SAST na elke commit draait, gevolgd door policy-evaluaties die releasebranches blokkeren wanneer kritieke issues openstaan. Build agents worden hardenend zodat scanresultaten betrouwbaar blijven en credentials niet op straat belanden. Tegelijkertijd worden DAST-scans gekoppeld aan release candidates in representatieve testomgevingen met realistische configuraties voor identity providers, API-gateways en netwerksegmentatie. Door pipelines consistent op te bouwen kunnen teams snel zien waarom een release wordt tegengehouden en welke stappen nodig zijn om door te gaan.

Toolintegratie vereist strikte datakwaliteit. Alle scanuitkomsten worden centraal opgeslagen in een data lake of Defender for Cloud Apps-werkruimte, inclusief contextualisering: applicatie-eigenaar, dataclassificatie, BIO-proces en technische stack. Hierdoor kan de CISO-office trends volgen, bijvoorbeeld een toename van kwetsbaarheden in legacy .NET Framework-apps of terugkerende misconfiguraties in API’s. Ook leveranciers krijgen toegang tot hetzelfde portaal zodat consortiums in Rijks- of gemeentelijke ketens uniforme rapportages delen. Door deze gedeelde bron vervallen losse spreadsheets en kunnen auditors rechtstreeks op de centrale dataset aansluiten.

De toolketen omvat meer dan scanners. Secrets-detectie, dependency-checks, containerhardening en Infrastructure-as-Code validatie worden gelijktijdig uitgevoerd om supply-chainrisico’s te minimaliseren. Teams krijgen duidelijke runbooks waarin staat hoe zij foutmeldingen interpreteren, wanneer zij een false positive mogen markeren en hoe zij dat onderbouwen. Daarnaast voorziet het programma in geautomatiseerde feedback richting ontwikkelaars: bij elke mislukte pipeline wordt een Teams-notificatie verstuurd met context, verwijzingen naar architectuurprincipes en een link naar het PowerShell-rapport. Zo blijft de ontwikkelsnelheid hoog terwijl kwaliteitseisen zichtbaar blijven.

Om verstoring te voorkomen, voorziet het programma in gefaseerde implementatie. Nieuwe tools worden eerst uitgerold in een sandbox waar het script sampledata verifieert, logformaten uniformiseert en prestatie-impact meet. Vervolgens worden pipelines van laag-risicoprojecten gemigreerd, waarna bedrijfskritische systemen volgen. Elke fase sluit af met een operational readiness review waarin CISO, product owner en beheerorganisatie bevestigen dat monitoring, escalatie en herstelprocessen werken. Deze aanpak voorkomt big-bang migraties en geeft teams ruimte om lessons learned te verwerken voordat volgende fases starten.

Operationele borging en continue verbetering

Wanneer governance en processen staan, verschuift de aandacht naar dagelijkse uitvoering. SOC- en CSIRT-teams krijgen directe inzage in scanresultaten zodat zij afwijkingen kunnen koppelen aan incidenten en threat intelligence. Bevindingen met hoge prioriteit worden binnen 24 uur in het risicoregister geregistreerd en gekoppeld aan verantwoordelijken. Release trains mogen alleen door wanneer kritieke kwetsbaarheden binnen afgesproken termijnen zijn opgelost of wanneer expliciete bestuurlijke dispensaties zijn verleend. Dit maakt het onmogelijk om kwetsbaarheden te negeren zonder transparant besluit, wat essentieel is voor publieke verantwoording.

Training en ondersteuning vormen de tweede pijler van operationele borging. Ontwikkelaars volgen verplichte secure coding-trainingen met nadruk op OWASP Top 10, cloud-native architectuur en privacy-by-design. Testers leren DAST-scripts aanpassen aan ketens met DigiD, eHerkenning of PKIoverheid-certificaten. Contractmanagers en inkoopadviseurs krijgen workshops over het opnemen van SAST/DAST-eisen in raamovereenkomsten en het beoordelen van leveranciersrapportages. Deze combinatie zorgt ervoor dat juridische, organisatorische en technische rollen dezelfde taal spreken en bevindingen niet blijven hangen tussen disciplines.

Continue verbetering wordt aangestuurd via een verbeterbacklog waarin bevindingen, lessons learned en innovatievoorstellen samenkomen. Het PowerShell-script leest deze backlog uit de sampledata en geeft aan welke thema’s – bijvoorbeeld secrets management of API-authenticatie – structureel terugkeren. Het stuurt tevens herinneringen om root cause-analyses te voltooien en bewaakt of maatregelen daadwerkelijk effect hebben op scantrends. Hierdoor wordt voorkomen dat teams dezelfde kwetsbaarheden telkens opnieuw oplossen zonder de bronoorzaak aan te pakken.

Tot slot maakt het programma rapportage transparant richting bestuur, toezichthouders en burgers. Kwartaalrapportages bevatten trendanalyses, voorbeelduitkomsten en een toelichting op getroffen maatregelen. Bij majeure incidenten kan de organisatie snel aantonen welke scans draaiden, welke beslissingen zijn genomen en hoe lessons learned zijn verwerkt. Deze transparantie versterkt vertrouwen bij toezichthouders en toont aan dat de Nederlandse Baseline voor Veilige Cloud geen papieren werkelijkheid is, maar een werkend stelsel waarin veilige softwareontwikkeling dagelijks wordt bewezen.

Compliance & Frameworks

Automation

Gebruik het onderstaande PowerShell script om deze security control te monitoren en te implementeren. Het script bevat functies voor zowel monitoring (-Monitoring) als remediation (-Remediation).

PowerShell
<# .SYNOPSIS Simuleert SAST- en DAST-rapportages voor de Nederlandse Baseline voor Veilige Cloud. .DESCRIPTION Dit script hoort bij content/security/sast-dast-implementation.json. Het draait volledig op sampledata zodat teams lokaal kunnen testen in DebugMode zonder verbinding te maken met productie- of CI/CD-omgevingen. Het script kan een maturity-assessment uitvoeren of een gericht verbeterplan genereren en slaat resultaten op in een JSON-rapport. .NOTES Filename: sast-dast-implementation.ps1 Version: 1.0 Author: Nederlandse Baseline voor Veilige Cloud Created: 2025-11-27 Related JSON: content/security/sast-dast-implementation.json .LINK https://github.com/microsoft/m365-tenant-best-practise .EXAMPLE .\sast-dast-implementation.ps1 -Assessment -ScanScope Both -DebugMode Voert de simulatie uit met sampledata en toont nalevingsscores in de console. .EXAMPLE .\sast-dast-implementation.ps1 -Remediation -ScanScope DAST -WhatIf Genereert een verbeterplan voor DAST-processen en toont de acties zonder deze te persistenteren. #> #Requires -Version 5.1 [CmdletBinding(DefaultParameterSetName = 'Assessment')] param( [Parameter(ParameterSetName = 'Assessment')] [switch]$Assessment, [Parameter(ParameterSetName = 'Remediation')] [switch]$Remediation, [ValidateSet('SAST', 'DAST', 'Both')] [string]$ScanScope = 'Both', [switch]$DebugMode, [switch]$WhatIf, [string]$OutputPath = ".\artifacts\sast-dast-implementation-report.json" ) if (-not $Assessment -and -not $Remediation) { $Assessment = $true } $ErrorActionPreference = 'Stop' $VerbosePreference = 'Continue' function Show-SastDastBanner { Write-Host "`n==============================================" -ForegroundColor Cyan Write-Host " SAST & DAST Implementatie Evaluatie" -ForegroundColor Cyan Write-Host " Nederlandse Baseline voor Veilige Cloud " -ForegroundColor Cyan Write-Host "==============================================`n" -ForegroundColor Cyan } function Test-RequiredModules { [CmdletBinding()] param() if ($DebugMode) { Write-Verbose "DebugMode actief: modulecontroles worden overgeslagen." return } $modules = @('Az.Accounts', 'Az.DevOps', 'Microsoft.Graph.Authentication') foreach ($module in $modules) { if (-not (Get-Module -ListAvailable -Name $module)) { Write-Warning "Module $module ontbreekt. Installeer de module voordat u productie-omgevingen benadert." } } } function Get-SastDastSampleData { [CmdletBinding()] param() return @( [pscustomobject]@{ SystemName = 'SociaalDomein-API' Classification = 'Zeer Vertrouwelijk' Scope = 'Both' SastCoverage = 0.98 DastCoverage = 0.84 CriticalFindings = 1 HighFindings = 3 MediumFindings = 7 OpenFindings = 6 MeanRemediationDays = 11 LastScanHours = 20 PipelineBlocked = $true }, [pscustomobject]@{ SystemName = 'VergunningPortaal' Classification = 'Vertrouwelijk' Scope = 'Both' SastCoverage = 0.91 DastCoverage = 0.73 CriticalFindings = 0 HighFindings = 2 MediumFindings = 9 OpenFindings = 4 MeanRemediationDays = 16 LastScanHours = 54 PipelineBlocked = $false }, [pscustomobject]@{ SystemName = 'LowCode-Burgerzaken' Classification = 'Intern' Scope = 'SAST' SastCoverage = 0.86 DastCoverage = 0.0 CriticalFindings = 0 HighFindings = 1 MediumFindings = 4 OpenFindings = 2 MeanRemediationDays = 7 LastScanHours = 12 PipelineBlocked = $false } ) } function Get-SastDastFilteredData { [CmdletBinding()] param() $data = Get-SastDastSampleData switch ($ScanScope) { 'SAST' { return $data | Where-Object { $_.Scope -in @('SAST', 'Both') } } 'DAST' { return $data | Where-Object { $_.Scope -in @('DAST', 'Both') } } Default { return $data } } } function Invoke-SastDastScore { [CmdletBinding()] param() $systems = Get-SastDastFilteredData if (-not $systems) { throw "Er zijn geen systemen beschikbaar voor de gekozen scope '$ScanScope'." } $issues = New-Object System.Collections.Generic.List[string] $coverageScores = @() foreach ($system in $systems) { if ($ScanScope -ne 'DAST' -and $system.SastCoverage -lt 0.95) { $issues.Add("SAST-dekking onder 95% voor $($system.SystemName).") } if ($ScanScope -ne 'SAST' -and $system.DastCoverage -lt 0.8) { $issues.Add("DAST-dekking onder 80% voor $($system.SystemName).") } if ($system.CriticalFindings -gt 0 -or $system.HighFindings -gt 2) { $issues.Add("Open kritieke of hoge bevindingen in $($system.SystemName).") } if ($system.MeanRemediationDays -gt 14) { $issues.Add("Gemiddelde oplostijd boven 14 dagen voor $($system.SystemName).") } if ($system.LastScanHours -gt 48) { $issues.Add("Laatste scan ouder dan 48 uur voor $($system.SystemName).") } $coverageScores += if ($ScanScope -eq 'DAST') { $system.DastCoverage } elseif ($ScanScope -eq 'SAST') { $system.SastCoverage } else { ($system.SastCoverage + $system.DastCoverage) / 2 } } $avgCoverage = [math]::Round(($coverageScores | Measure-Object -Average).Average, 2) $penalty = [math]::Min(100, $issues.Count * 5 + ($systems.OpenFindings | Measure-Object -Sum).Sum) $score = [math]::Max(0, 100 - $penalty) return [pscustomobject]@{ ScriptName = 'sast-dast-implementation.ps1' Timestamp = Get-Date Scope = $ScanScope SystemsEvaluated = $systems.SystemName AverageCoverage = "{0:P0}" -f $avgCoverage OpenFindingsTotal = ($systems | Measure-Object -Property OpenFindings -Sum).Sum MeanRemediation = ($systems | Measure-Object -Property MeanRemediationDays -Average).Average PipelinesBlocked = ($systems | Where-Object { $_.PipelineBlocked }).Count Issues = $issues ComplianceScore = $score IsCompliant = ($issues.Count -eq 0) } } function Invoke-SastDastAssessment { [CmdletBinding()] param() $result = Invoke-SastDastScore Write-Host "Scope : $($result.Scope)" -ForegroundColor White Write-Host "Geëvalueerde systemen : $($result.SystemsEvaluated -join ', ')" -ForegroundColor White Write-Host "Gemiddelde dekking : $($result.AverageCoverage)" -ForegroundColor White Write-Host "Open bevindingen totaal : $($result.OpenFindingsTotal)" -ForegroundColor White $meanValue = "{0:N1}" -f $result.MeanRemediation Write-Host "Gemiddelde oplostijd (d) : $meanValue" -ForegroundColor White Write-Host "Geblokkeerde pipelines : $($result.PipelinesBlocked)" -ForegroundColor White Write-Host "Compliance-score : $($result.ComplianceScore)" -ForegroundColor Cyan if ($result.IsCompliant) { Write-Host "`nResultaat: alle normen zijn gehaald." -ForegroundColor Green } else { Write-Host "`nVerbeterpunten:" -ForegroundColor Yellow $result.Issues | Select-Object -Unique | ForEach-Object { Write-Host " - $_" -ForegroundColor Yellow } } return $result } function Invoke-SastDastRemediation { [CmdletBinding()] param() $result = Invoke-SastDastScore $actions = New-Object System.Collections.Generic.List[string] foreach ($issue in $result.Issues) { switch -Wildcard ($issue) { "*SAST-dekking*" { $actions.Add("Verplicht het vernieuwde pipeline-sjabloon zodat alle repositories minimaal 95% SAST-dekking halen.") } "*DAST-dekking*" { $actions.Add("Plan aanvullende DAST-scripts die federatieve authenticatie en API-rate limiting simuleren.") } "*kritieke*" { $actions.Add("Activeer releaseblokkades totdat kritieke bevindingen met root cause-analyses zijn afgerond.") } "*oplostijd*" { $actions.Add("Introduceer time-to-fix KPI's in de sprintplanning en stuur op afronding binnen 14 dagen.") } "*scan ouder*" { $actions.Add("Automatiseer her-scans binnen 24 uur via Azure DevOps schedules en monitor de uitvoering in Sentinel.") } } } if ($actions.Count -eq 0) { Write-Host "Geen aanvullende acties nodig." -ForegroundColor Green return $result } Write-Host "`nVoorgesteld verbeterplan:" -ForegroundColor Cyan foreach ($action in $actions | Select-Object -Unique) { if ($WhatIf) { Write-Host "WhatIf: $action" -ForegroundColor Yellow } else { Write-Host $action -ForegroundColor Gray } } return $result } function Save-SastDastReport { [CmdletBinding()] param( [Parameter(Mandatory)] [pscustomobject]$Data ) $directory = Split-Path -Parent $OutputPath if (-not (Test-Path $directory)) { New-Item -ItemType Directory -Path $directory -Force | Out-Null } $Data | ConvertTo-Json -Depth 4 | Out-File -FilePath $OutputPath -Encoding UTF8 Write-Host "`nRapport opgeslagen op $OutputPath" -ForegroundColor Green } Show-SastDastBanner Test-RequiredModules try { $result = if ($Remediation) { Invoke-SastDastRemediation } else { Invoke-SastDastAssessment } Save-SastDastReport -Data $result return $result } catch { Write-Error "Fout tijdens SAST/DAST-simulatie: $_" exit 1 } finally { Write-Host "`n==============================================" -ForegroundColor Cyan }

Risico zonder implementatie

Risico zonder implementatie
High: Zonder verplicht SAST/DAST-proces worden kwetsbaarheden pas ontdekt tijdens incidenten, falen BIO- en NIS2-audits en verliezen bestuurders het vertrouwen van burgers en toezichthouders.

Management Samenvatting

Veranker SAST en DAST bestuurlijk, automatiseer scans in iedere pipeline, gebruik het script voor maturitymetingen en zorg voor transparante rapportages zodat ontwikkelteams en bestuurders dezelfde werkelijkheid delen.