はまったりひらめいたり…とか…

Angularや.NETやAzureやその他色々。

Azure DevOpsのPipelineでOWASP ZAPを実行してみる

はじめに

2020年12月時点の情報で記事を作成しています。

参照される時期によっては、記事内で使用されているコマンド、画面キャプチャが使用できなくなっている可能性がありますのでご留意ください。

Azure PipelineでOWASP ZAPを実行したい

だいぶ前にGitHubActionsでOWASP ZAPのScanができるようになりました

例のごとくAzurePipelineでは使用できません。

Azure Pipeline上でOWASP ZAPのスキャンを使用してみましょう。

ZAP Dockerを使用する

OWASP ZAPがDockerファイルを提供しています。

Pipeline上でDockerコマンドが実行できるのでそれを使用してPipeline上で脆弱性チェックを行います。

と、いってもZAP Dockerのコマンド等の類の説明は山程あると思いますので省きます。

今回はDocker内で提供されているFullScanを使用しますが

細かい機能を使用したい場合はPowerShell経由でZAP APIを叩いて

Context作成→ContextにURL追加→Spider実行ないつもの流れを行えばいいと思います。

OWASP ZAP2.7でzap-API を使ってSpiderの実行 - 備忘録/にわかエンジニアが好きなように書く

WebAPIをPowerShellからテストする - Qiita

Azure Pipeline上で実行する

すでにPipeline上で実行する記事を書かれている方がいるのでそれを参考にしてみます。

How to run OWASP ZAP Security Tests Part of Azure DevOps CI/CD Pipeline

この記事ではReleaseパイプライン上で実行されているので、MultiStagePipeline上で実行できるようにいじってみます。

また、結果レポートはAzure Artifactsに格納されていますが、すこしアクセスしづらいのでBLOB上に格納してみます。

Pipeline構成

下記な構成のymlとなります

  1. SPAのWebApplicationをビルド
  2. Angularアプリケーションをビルドします
  3. WebAppsにデプロイ 1, デプロイ先のWebAppsの脆弱性調査+Report出力
trigger:
  branches:
    include:
    - master

stages:
- stage: build
  jobs:
  - job: build_job
    displayName: Build Angular
    pool:
      vmImage: ubuntu-latest
    steps:
    - task: npm@1
      displayName: npm ci
      inputs:
        command: custom
        customCommand: 'ci'
    - task: npm@1
      displayName: npm build
      inputs:
        command: custom
        customCommand: 'run build:ci'
    - task: ArchiveFiles@2
      displayName: 'Archive dist/pipeline-learn-front'
      inputs:
        rootFolderOrFile: 'dist/pipeline-learn-front'
        includeRootFolder: false
        archiveFile: '$(Build.ArtifactStagingDirectory)/drop.zip'
    - task: PublishBuildArtifacts@1
      displayName: 'Publish Artifact: drop'

- stage: deploy
  dependsOn: build
  jobs:
    - deployment: deploy_webapp
      displayName: Deploy WebApp
      environment: deploy
      strategy:
        runOnce:
          preDeploy:
            steps:
              - download: current
                artifact: drop
          deploy:
            steps:
              - task: AzureRmWebAppDeployment@4
                inputs:
                  ConnectionType: 'AzureRM'
                  azureSubscription: '***'
                  appType: 'webApp'
                  WebAppName: '***'
                  packageForLinux: '$(Pipeline.Workspace)/**/*.zip'

- stage: security_test
  dependsOn: deploy
  jobs:
  - job: security_test
    displayName: SecurityTest
    pool:
      vmImage: ubuntu-latest
    steps:
    - task: DockerInstaller@0
      inputs:
        dockerVersion: '17.09.0-ce'
    - task: Bash@3
      inputs:
        targetType: 'inline'
        script: |
          chmod -R 777  ./
          docker run --rm -v $(pwd):/zap/wrk/:rw -t owasp/zap2docker-stable zap-full-scan.py -t https://okawa-test-webapp.azurewebsites.net/ -j -g gen.conf -x OWASP-ZAP-Report.xml -r scan-report.html
          true
    - task: PowerShell@2
      inputs:
        targetType: 'inline'
        script: |
          $XslPath = "$($Env:SYSTEM_DEFAULTWORKINGDIRECTORY)/OWASPToNUnit3.xslt"
          $XslPath
          $XmlInputPath = "$($Env:SYSTEM_DEFAULTWORKINGDIRECTORY)/OWASP-ZAP-Report.xml"
          $XmlInputPath
          $XmlOutputPath = "$($Env:SYSTEM_DEFAULTWORKINGDIRECTORY)/Converted-OWASP-ZAP-Report.xml"
          $XmlOutputPath
          $XslTransform = New-Object System.Xml.Xsl.XslCompiledTransform
          $XslTransform.Load($XslPath)
          $XslTransform.Transform($XmlInputPath, $XmlOutputPath)
    - task: PublishTestResults@2
      inputs:
        testResultsFormat: 'NUnit'
        testResultsFiles: 'Converted-OWASP-ZAP-Report.xml'
        searchFolder: '$(System.DefaultWorkingDirectory)'
    - task: AzurePowerShell@5
      inputs:
        azureSubscription: '***'
        ScriptType: 'InlineScript'
        azurePowerShellVersion: latestVersion
        Inline: |
          $storage = Get-AzStorageAccount -ResourceGroupName "vse-sandbox" -Name "***"
          $ctx = $storage.Context
          $containerName = "zap-result"
          Set-AzStorageBlobContent -File "$($Env:SYSTEM_DEFAULTWORKINGDIRECTORY)/scan-report.html" -Container $containerName -Blob "scan-report.html" -Context $ctx

結果

AzureのCIレポートでテスト結果を確認できるように、レポート出力されたXMLファイルをNUnit形式に変換しています。

結果、下図のようにCIのレポートで発見された脆弱性のレポートを確認できるようになっている感じです。

f:id:TakasDev:20201230132000p:plain

HTMLで出力されたレポートを見たい場合はBLOBからですね。

f:id:TakasDev:20201230132611p:plain

Azure Artifactsに上げる場合のハマりどころ

今回はBLOBにあげてみましたが、参考サイトにある通りAzure Artifactsにあげようとした場合にハマったポイントがありました。

準備段階で、AzureArtifactsにaz artifacts universalを使用してArtifactsを作っているのですが

azコマンドからは403が出てしまいPublishできないといった現象がおきました。

vsts CLIを使用した場合にはエラーは発生しなかったので、azコマンドでエラーが発生した場合はvsts CLIを使用してみるといいかもしれません。

まとめ

今回は雑にCIに組み込めるか程度のレベルで試してみました。

AngularアプリのようなSPA構成のアプリの場合は単純なSpiderではなくAjaxスパイダーを使用したり

試行時間を決定しないと永遠に終わらなかったり…と考慮することは多そうなので

実際にしっかり運用するとなったら直接APIを叩いてガリガリ組んでいくしかないかなと思います。

と言っても、知らん間にガチ脆弱性チェックを行ってデータが壊れるのも色々嫌な感じですし

サーバーの設定レベルだけチェックするような現在の構成のほうが、自動実行するレベルとしては扱いやすいのかもしれないですね。