Skip to content
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions docs/content/en/connecting_your_tools/parsers/file/nowsecure.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
title: "NowSecure"
toc_hide: true
---
This parser imports the Now Secure app analysis resutls using `json` output.

### Sample analysis Data
Sample NowSecure result files can be found [here](https://github.com/DefectDojo/django-DefectDojo/tree/master/unittests/scans/nowsecure).

### Using your own data

```sh
# https://support.nowsecure.com/hc/en-us/articles/7499657262093-Creating-a-NowSecure-Platform-API-Bearer-Token
API_TOKEN=""
# Can be obteained from the Webui
APP_REF=""
# Sample CURL request (beware of the pipe to jq!)
curl 'https://api.nowsecure.com/graphql' -H 'Accept-Language: en-US,en;q=0.9' -H 'Connection: keep-alive' -H 'Origin: https://app.nowsecure.com' -H 'Referer: https://app.nowsecure.com/' -H 'Sec-Fetch-Dest: empty' -H 'Sec-Fetch-Mode: cors' -H 'Sec-Fetch-Site: same-site' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36' -H 'accept: */*' -H "authorization: Bearer ${API_TOKEN}" -H 'client-source: platform' -H 'content-type: application/json' -H 'sec-ch-ua: "Not;A=Brand";v="99", "Google Chrome";v="139", "Chromium";v="139"' -H 'sec-ch-ua-mobile: ?0' -H 'sec-ch-ua-platform: "macOS"' --data-raw "{\"operationName\":\"getAssessment\",\"variables\":{\"canViewPolicies\":true,\"ref\":\"${app_ref}\",\"policyVersionRef\":null,\"catalog\":null},\"query\":\"query getAssessment(\$ref: UUID\u0021, \$canViewPolicies: Boolean = false, \$policyVersionRef: UUID, \$catalog: ComplianceReportCatalog) {\\n auto {\\n assessment(ref: \$ref, policyVersionRef: \$policyVersionRef) {\\n ...assessment\\n __typename\\n }\\n __typename\\n }\\n}\\n\\nfragment assessment on AutoAssessment {\\n ...assessmentWithoutReport\\n report {\\n ...report\\n __typename\\n }\\n baseReport {\\n findings(hidden: true, indeterminate: true) {\\n checkId\\n affected\\n cvss\\n findingStatus\\n __typename\\n }\\n __typename\\n }\\n __typename\\n}\\n\\nfragment assessmentWithoutReport on AutoAssessment {\\n ref\\n applicationRef\\n platformType\\n packageKey\\n packageVersion\\n taskId\\n title\\n iconURL\\n isAppstoreDownload\\n createdAt\\n createdBy {\\n ref\\n email\\n name\\n __typename\\n }\\n buildRef\\n buildVersion\\n upload {\\n ref\\n createdAt\\n digest\\n __typename\\n }\\n analysisConfigLevel\\n type\\n analysisJobType\\n staticScore\\n score\\n favorite\\n assessmentError {\\n code\\n title\\n description\\n options\\n __typename\\n }\\n isDebugMode\\n hasPreviousAssessmentForComparison\\n policy @include(if: \$canViewPolicies) {\\n ...litePolicy\\n __typename\\n }\\n policyVersion @include(if: \$canViewPolicies) {\\n ref\\n policyRef\\n version\\n policyCategories {\\n policyCategory\\n label\\n description\\n color\\n __typename\\n }\\n __typename\\n }\\n analysis {\\n isAuthenticated\\n isCancelled\\n isComplete\\n isRunning\\n status\\n mappedStatus\\n errorCode\\n error {\\n code\\n message\\n __typename\\n }\\n artifacts(artifactType: HAR) {\\n assessmentRef\\n ref\\n artifactType\\n tags\\n displayName\\n byteSize\\n filename\\n contentType\\n url\\n __typename\\n }\\n screenshots {\\n ref\\n url\\n analysisPass\\n __typename\\n }\\n task {\\n static {\\n ...analysisJob\\n __typename\\n }\\n dynamic {\\n ...analysisJob\\n __typename\\n }\\n __typename\\n }\\n __typename\\n }\\n build {\\n ref\\n digest\\n version\\n __typename\\n }\\n group {\\n ref\\n __typename\\n }\\n __typename\\n}\\n\\nfragment analysisJob on AnalysisJob {\\n id\\n status\\n modifiedAt\\n isRunning\\n isComplete\\n __typename\\n}\\n\\nfragment litePolicy on Policy {\\n ref\\n name\\n createdBy\\n createdAt\\n updatedAt\\n archivedAt\\n targetType\\n isDefault\\n isNSManaged\\n latestVersion {\\n ref\\n version\\n trackedVersion\\n trackedVersionRef\\n __typename\\n }\\n targets {\\n ref\\n type\\n __typename\\n }\\n enabled\\n trackedPolicy {\\n ref\\n name\\n latestVersion {\\n ref\\n version\\n __typename\\n }\\n __typename\\n }\\n __typename\\n}\\n\\nfragment report on AssessmentReport {\\n createdAt\\n findings(hidden: true, indeterminate: true) {\\n ...reportFinding\\n __typename\\n }\\n __typename\\n}\\n\\nfragment reportFinding on Finding {\\n affected\\n checkId\\n uniqueVulnerabilityId\\n check {\\n ...findingCheck\\n __typename\\n }\\n userChanges {\\n date\\n user {\\n name\\n __typename\\n }\\n __typename\\n }\\n cvss\\n cvssVector\\n findingStatus\\n decision\\n decisionInfo {\\n note\\n reason\\n wasInherited\\n __typename\\n }\\n evidenceDecision\\n hidden\\n impactType\\n severity\\n note\\n adjustments\\n shortRemediation\\n title\\n hasContext\\n hasCodeLocations\\n canHaveActionableEvidence\\n hasActionedEvidence\\n policyCategory @include(if: \$canViewPolicies) {\\n policyCategory\\n color\\n label\\n __typename\\n }\\n policyFindingOverrides {\\n checkId\\n cvss\\n cvssVector\\n hidden\\n impactType\\n __typename\\n }\\n complianceReportRelations(catalog: \$catalog) {\\n catalog\\n groupId\\n controlId\\n version\\n __typename\\n }\\n __typename\\n}\\n\\nfragment findingCheck on FindingCheck {\\n id\\n analysisType\\n title\\n description\\n shortDescription\\n platformType\\n category\\n categories\\n legacyFindingKey\\n isNew\\n deprecated\\n context {\\n view\\n title\\n fields {\\n key\\n format\\n title\\n description\\n __typename\\n }\\n children {\\n view\\n title\\n fields {\\n key\\n format\\n title\\n description\\n __typename\\n }\\n __typename\\n }\\n __typename\\n }\\n issue {\\n cvss\\n cvssVector\\n title\\n description\\n recommendation\\n passingContent\\n category\\n severity\\n warn\\n impactSummary\\n regulations {\\n type\\n label\\n links {\\n title\\n url\\n __typename\\n }\\n __typename\\n }\\n stepsToReproduce\\n codeSamples {\\n platform\\n syntax\\n caption\\n block\\n __typename\\n }\\n guidanceLinks {\\n platform\\n caption\\n url\\n __typename\\n }\\n __typename\\n }\\n compliance {\\n regulation {\\n description\\n __typename\\n }\\n notes {\\n description\\n __typename\\n }\\n activity {\\n tss {\\n description\\n __typename\\n }\\n guidance {\\n description\\n __typename\\n }\\n tests {\\n description\\n __typename\\n }\\n __typename\\n }\\n nowSecureGuidance {\\n description\\n __typename\\n }\\n __typename\\n }\\n __typename\\n}\\n\"}" | jq
```

### Default Deduplication Hashcode Fields
By default, DefectDojo identifies duplicate Findings using these [hashcode fields](https://docs.defectdojo.com/en/working_with_findings/finding_deduplication/about_deduplication/):

- title
- description
21 changes: 21 additions & 0 deletions dojo/fixtures/test_type.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,26 @@
},
"model": "dojo.test_type",
"pk": 7
},
{
"fields": {
"name": "NowSecure"
},
"model": "dojo.test_type",
"pk": 8
},
{
"fields": {
"name": "NowSecure"
},
"model": "dojo.test_type",
"pk": 9
},
{
"fields": {
"name": "NowSecure"
},
"model": "dojo.test_type",
"pk": 10
}
]
Empty file.
105 changes: 105 additions & 0 deletions dojo/tools/nowsecure/parser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import hashlib
import json
from urllib.parse import urlparse
from dojo.models import Endpoint, Finding
import re

class NowSecureParser(object):
"""
Importing findings from NowSecure app analysis.
"""

def get_scan_types(self):
return ["NowSecure Scan"]

def get_label_for_scan_types(self, scan_type):
return "NowSecure Scan"

def get_description_for_scan_types(self, scan_type):
return "NowSecure report file can be imported in JSON format (option --json)."

def get_findings(self, file, test):
data = json.load(file)

dupes = dict()
for content in data['data']['auto']['assessment']['report']['findings']:
Comment thread
30vh1 marked this conversation as resolved.
Outdated
if content['affected']:
if content['check']['issue']:
title = content['check']['issue']['title']
for regulation in content['check']['issue']['regulations']:
if regulation['type'] == "cwe":
cwe = regulation['links'][0]['title']
description = content['check']['issue']['description']
severity = content['check']['issue']['severity'].capitalize()
cvssv3 = content['check']['issue']['cvssVector']
cvssv3_score = content['check']['issue']['cvss']
Comment thread
30vh1 marked this conversation as resolved.
Outdated
mitigation = content['check']['issue']['recommendation']
Comment thread
30vh1 marked this conversation as resolved.
Outdated
impact = content['check']['issue']['impactSummary']
url = f"https://app.nowsecure.com/app/{data['data']['auto']['assessment']['applicationRef']}/assessment/{data['data']['auto']['assessment']['ref']}?viewObservationsBy=categories&viewFindingsBy=policyCategory#{content['checkId']}"
steps_to_reproduce = (content['check']['issue']['stepsToReproduce'] or '''''')
if content['check']['issue']['codeSamples']:
code_samples = ''''''
for code_sample in content['check']['issue']['codeSamples']:
code_samples += f'''**{code_sample['platform']}**: {code_sample['caption']}\n```{code_sample['syntax']}\n{code_sample['block']}\n```\n'''
if code_samples:
steps_to_reproduce += code_samples
references = ''''''
if content['check']['issue']['guidanceLinks']:
references+="### Guidance Links\n"
for reference in content['check']['issue']['guidanceLinks']:
references+=f'''* [{reference['caption']}]({reference['url']})\n'''

cwe = None
if content['check']['issue']['regulations']:
references+="### Regulations\n"
for regulation in content['check']['issue']['regulations']:
if regulation['type'] == 'cwe':
cwe = regulation['links'][0]['title']
for link in regulation['links']:
references+=f"* **{regulation['label']}**: [{link['title']}]({link['url']})\n"
cve = None
cve_pattern = r'CVE-\d{4}-\d{4,7}'
cve_matches = re.findall(cve_pattern, title)
if cve_matches:
cve = list(dict.fromkeys(cve_matches))[0]

finding = Finding(
title=title,
test=test,
description=description,
severity=severity,
cvssv3 = cvssv3,
cvssv3_score = cvssv3_score,
mitigation = mitigation,
url = url,
steps_to_reproduce = steps_to_reproduce,
impact=impact,
references = references,
cwe = cwe,
cve = cve,

Comment thread
30vh1 marked this conversation as resolved.
static_finding=True,
dynamic_finding=False,
)
dupe_key = hashlib.sha256(str(description + title).encode('utf-8')).hexdigest()
if dupe_key in dupes:
find = dupes[dupe_key]
if finding.description:
find.description += "\n" + finding.description
find.unsaved_endpoints.extend(finding.unsaved_endpoints)
dupes[dupe_key] = find
else:
dupes[dupe_key] = finding

return list(dupes.values())

def convert_severity(self, num_severity):
"""Convert severity value"""
if num_severity >= -10:
return "Low"
elif -11 >= num_severity > -26:
return "Medium"
elif num_severity <= -26:
return "High"
else:
return "Info"
Loading