StackHawk Documentation StackHawk Logo HawkDocs

No results found

Try different keywords or check your spelling

Search documentation

Find guides, API references, and more

esc

Defect Dojo

Defect Dojo

Overview

StackHawk has contributed a custom parser to the Defect Dojo project. The parser is capable of importing webhook event JSON as findings into the Defect Dojo platform.

There are some example snippets below to assist you with your own webhook consuming application.

When you’re ready to set up your Defect Dojo integration, be sure to check out the guide to enable the webhook integration, and have your application’s webhook endpoint ready to go!

Features

  • HawkScan findings can be auto imported as Defect Dojo findings.
  • Updates to scan results (re-imports) can auto close findings in Defect Dojo.

Requirements

StackHawk:

  • You must have a StackHawk account.
  • Your StackHawk Organization must belong to a plan with The Webhook Integration enabled. Contact StackHawk Support to enable it.

Defect Dojo:

  • You must have login permissions to the Defect Dojo workspace you wish to set up this workflow for.
  • You must be on Defect Dojo version 2.8.0 or above.

API References

Defect Dojo API references will be provided via the hosted Defect Dojo demo application. Information about this demo site (including how to log in to it) is available on the official Defect Dojo README.

There are 2 important API operations provided by Defect Dojo that allow automatically importing scans via custom parsers.

To interact with the StackHawk parser, please specify the scan_type as StackHawk HawkScan for both operations.

Authenticating with Defect Dojo

You can find example documentation for authenticating to Defect Dojo on the demo site.

When you’re ready to get your own API key for the Defect Dojo API, you can find personalized instructions at <YOUR_DEFECT_DOJO_DOMAIN>/api/key-v2.

Guide

The Defect Dojo custom parser works on the webhook payload verbatim. No modifications are necessary. We strongly recommend saving the webhook payload contents as-is to a file for upload into Defect Dojo.

Downloading the Webhook from StackHawk

These examples will showcase an endpoint (/my-webhook) downloading the contents of the StackHawk webhook payload to stackhawk-webhook.json.

import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import java.io.File

@PostMapping("/my-webhook")
fun receiveStackHawkWebhook(@RequestBody webhook: String) {
    File("stackhawk-webhook.json")
            .bufferedWriter()
            .use { out -> out.write(webhook) }
}
const fs = require('fs');
const app = express();
app.use(bodyParser.urlencoded({ extended: true }));

app.post('/my-webhook', (request, response) => {
    request.pipe(fs.createWriteStream("stackhawk-webhook.json", {flags: 'a'}));

    response.sendStatus(200);
});
from flask import request

@app.route('/my-webhook', methods=['POST'])
def receiveStackHawkWebhook():
    with open("stackhawk-webhook.json") as fo:
        fo.write(request.json)

Importing Webhook to Defect Dojo

These examples will demonstrate calling the Defect Dojo API with stackhawk-webhook.json, downloaded in the above example. The filename parameter should be the reference to the stackhawk-webhook.json.

import org.springframework.core.io.ClassPathResource
import org.springframework.http.HttpHeaders
import org.springframework.http.MediaType
import org.springframework.http.client.MultipartBodyBuilder
import org.springframework.stereotype.Service
import org.springframework.web.reactive.function.BodyInserters
import org.springframework.web.reactive.function.client.WebClient
// You provide / declare this object.
import your.own.package.for.DefectDojoProperties

@Service
class DefectDojoService(
    private val webClient: WebClient,
    private val properties: DefectDojoProperties
) {

    fun uploadToDefectDojo(filename: String, isNewImport: Boolean) {
        val multipartBodyBuilder = MultipartBodyBuilder()

        multipartBodyBuilder.addTextValue("scan_type", "StackHawk HawkScan")

        multipartBodyBuilder.part("file", ClassPathResource(filename).file.readBytes())
            .header(HttpHeaders.CONTENT_DISPOSITION, "form-data; name=file; filename=$filename;")

        multipartBodyBuilder.addTextValue("product_name", "<YOUR_DEFECT_DOJO_PRODUCT_NAME>")
        multipartBodyBuilder.addTextValue("engagement_name", "<YOUR_DEFECT_DOJO_ENGAGEMENT_NAME>")

        // optional, used for `import-scan`
        multipartBodyBuilder.addTextValue("product_type_name", "<YOUR_DEFECT_DOJO_PRODUCT_TYPE_NAME>")

        // optional, used for `reimport-scan`
        multipartBodyBuilder.addTextValue("test_title", "<YOUR_DEFECT_DOJO_TEST_TITLE>")

        // Example available form options can be found @
        // https://demo.defectdojo.org/api/v2/oa3/swagger-ui/

        // determine if this is a new import or an existing one.
        val uri = if (isNewImport) {
            "/api/v2/import-scan/"
        } else {
            "/api/v2/reimport-scan/"
        }
        webClient.post()
            .uri(properties.domain + uri)
            .contentType(MediaType.MULTIPART_FORM_DATA)
            .header(HttpHeaders.AUTHORIZATION, "Token <YOUR_DEFECT_DOJO_API_KEY>")
            .body(BodyInserters.fromMultipartData(multipartBodyBuilder.build()))
            .retrieve()
    }

    private fun MultipartBodyBuilder.addTextValue(name: String, value: String) {
        part(name, value, MediaType.TEXT_PLAIN)
            .header(HttpHeaders.CONTENT_DISPOSITION, "form-data; name=$name;")
            .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN_VALUE)
    }
}
const fs = require('fs');

uploadToDefectDojo(filename, isNewImport) {
    const uri = isNewImport ? "/api/v2/import-scan/" : "/api/v2/reimport-scan/";
    const options = {
        method: "POST",
        url: defectDojoDomain + uri,
        port: 443,
        headers: {
            "Content-Type": "multipart/form-data",
            "Authorization": "Token <YOUR_DEFECT_DOJO_API_KEY>"
        },
        formData : {
            "file" : fs.createReadStream(filename),
            "scan_type": "StackHawk HawkScan",
            "product_name": "<YOUR_DEFECT_DOJO_PRODUCT_NAME>",
            "engagement_name": "<YOUR_DEFECT_DOJO_ENGAGEMENT_NAME>",

            // optional, used for `import-scan`
            "product_type_name": "<YOUR_DEFECT_DOJO_PRODUCT_TYPE_NAME>",

            // optional, used for `reimport-scan`
            "test_title": "<YOUR_DEFECT_DOJO_TEST_TITLE>"

            // Example available form options can be found @
            // https://demo.defectdojo.org/api/v2/oa3/swagger-ui/
        }
    };

    request(options, function (err, res, body) {
        if(err) console.log(err);
        console.log(body);
    });
}
import requests

def uploadToDefectDojo(filename, is_new_import):
    multipart_form_data = {
        'file': (filename, open(filename, 'rb')),
        'scan_type': (None, 'StackHawk HawkScan'),
        'product_name': (None, '<YOUR_DEFECT_DOJO_PRODUCT_NAME>'),
        'engagement_name': (None, '<YOUR_DEFECT_DOJO_ENGAGEMENT_NAME>'),

        # optional, used for `import-scan`
        'product_type_name': (None, '<YOUR_DEFECT_DOJO_PRODUCT_TYPE_NAME>'),

        # optional, used for `reimport-scan`
        'test_title': (None, '<YOUR_DEFECT_DOJO_TEST_TITLE>'),

        # Example available form options can be found @
        # https://demo.defectdojo.org/api/v2/oa3/swagger-ui/
    }

    uri = '/api/v2/import-scan/' if is_new_import else '/api/v2/reimport-scan/'
    response = requests.post(
        defect_dojo_domain + uri,
        files=multipart_form_data,
        headers={
            'Authorization': 'Token <YOUR_DEFECT_DOJO_API_KEY>',
        }
    )
    print(response.content)

Feedback

Have any suggestions, feature requests, or feedback to share? Contact StackHawk Support.

Your privacy settings

We use first and third party cookies to ensure that we give you the best experience on our website and in our products.