Skip to content

Commit 4844bb2

Browse files
committed
Detailed error checking on API and CI/CD example
1 parent 4baf479 commit 4844bb2

6 files changed

Lines changed: 81 additions & 118 deletions

File tree

defectdojo_api/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = '1.0.1'
1+
__version__ = '1.0.2'

defectdojo_api/__init__.pyc

0 Bytes
Binary file not shown.

defectdojo_api/defectdojo.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -873,19 +873,21 @@ def _request(self, method, url, params=None, data=None, files=None):
873873
return DefectDojoResponse(message="Upload complete", data=data, success=True)
874874
elif response.status_code == 204: #Object updates
875875
return DefectDojoResponse(message="Object updated.", success=True)
876+
elif response.status_code == 400: #Object not created
877+
return DefectDojoResponse(message="Error occured in API.", success=False, data=response.text)
876878
elif response.status_code == 404: #Object not created
877-
return DefectDojoResponse(message="Object id does not exist.", success=False)
879+
return DefectDojoResponse(message="Object id does not exist.", success=False, data=response.text)
878880
elif response.status_code == 401:
879-
return DefectDojoResponse(message="Unauthorized.", success=False)
881+
return DefectDojoResponse(message="Unauthorized.", success=False, data=response.text)
880882
elif response.status_code == 414:
881883
return DefectDojoResponse(message="Request-URI Too Large.", success=False)
882884
elif response.status_code == 500:
883-
return DefectDojoResponse(message="An error 500 occured in the API.", success=False)
885+
return DefectDojoResponse(message="An error 500 occured in the API.", success=False, data=response.text)
884886
else:
885887
data = response.json()
886888
return DefectDojoResponse(message="Success", data=data, success=True, response_code=response.status_code)
887889
except ValueError:
888-
return DefectDojoResponse(message='JSON response could not be decoded.', success=False)
890+
return DefectDojoResponse(message='JSON response could not be decoded.', success=False, data=response.text)
889891
except requests.exceptions.SSLError:
890892
return DefectDojoResponse(message='An SSL error occurred.', success=False)
891893
except requests.exceptions.ConnectionError:

defectdojo_api/defectdojo.pyc

114 Bytes
Binary file not shown.

examples/dojo_ci_cd.py

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,6 @@
99
import os, sys
1010
import argparse
1111
import time
12-
import junit_xml_output
13-
14-
DEBUG = True
1512

1613
test_cases = []
1714

@@ -22,18 +19,17 @@ def junit(toolName, file):
2219
print "Writing Junit test files"
2320
file.write(junit_xml.dump())
2421

25-
def dojo_connection(host, api_key, user):
22+
def dojo_connection(host, api_key, user, proxy):
2623
#Optionally, specify a proxy
27-
proxies = {
28-
'http': 'http://localhost:8081',
29-
'https': 'http://localhost:8081',
30-
}
31-
32-
#if DEBUG:
33-
# Instantiate the DefectDojo api wrapper
24+
proxies = None
25+
if proxy:
26+
proxies = {
27+
'http': proxy,
28+
'https': proxy,
29+
}
30+
31+
# Instantiate the DefectDojo api wrapper
3432
dd = defectdojo.DefectDojoAPI(host, api_key, user, proxies=proxies, verify_ssl=False, timeout=360, debug=False)
35-
#else:
36-
# dd = defectdojo.DefectDojoAPI(host, api_key, user, verify_ssl=False, timeout=360, debug=False)
3733

3834
return dd
3935
# Workflow as follows:
@@ -42,9 +38,10 @@ def dojo_connection(host, api_key, user):
4238
# 3. Call this script to load scan data, specifying scanner type
4339
# 4. Script returns along with a pass or fail results: Example: 2 new critical vulns, 1 low out of 10 vulnerabilities
4440

45-
def return_engagement(dd, product_id):
41+
def return_engagement(dd, product_id, user):
4642
#Specify the product id
4743
product_id = product_id
44+
engagement_id = None
4845

4946
# Check for a CI/CD engagement_id
5047
engagements = dd.list_engagements(product_in=product_id, status="In Progress")
@@ -138,8 +135,10 @@ def processFiles(dd, engagement_id, file, scanner=None, build=None):
138135
print "Uploading " + scannerName + " scan: " + file
139136
test_id = dd.upload_scan(engagement_id, scannerName, file, "true", dojoDate, build)
140137

138+
if test_id.success == False:
139+
print "Upload failed: Detailed error message: " + test_id.data
140+
141141
return test_id
142-
#print os.path.basename(full_path)
143142

144143
def create_findings(dd, engagement_id, scanner, file, build=None):
145144
# Upload the scanner export
@@ -169,20 +168,22 @@ def summary(dd, engagement_id, test_ids, max_critical=0, max_high=0, max_medium=
169168
print_findings(sum_severity(findings))
170169
print
171170
#Delay while de-dupes
172-
sys.stdout.write("Sleeping for 30 seconds for de-dupe celery process:")
171+
sys.stdout.write("Sleeping for 10 seconds for de-dupe celery process:")
173172
sys.stdout.flush()
174-
for i in range(15):
173+
for i in range(5):
175174
time.sleep(2)
176175
sys.stdout.write(".")
177176
sys.stdout.flush()
178177

179178
findings = dd.list_findings(test_id_in=test_ids, duplicate="false", limit=500)
180179
if findings.count() > 0:
180+
"""
181181
for finding in findings.data["objects"]:
182182
test_cases.append(junit_xml_output.TestCase(finding["title"] + " Severity: " + finding["severity"], finding["description"],"failure"))
183183
if not os.path.exists("reports"):
184184
os.mkdir("reports")
185185
junit("DefectDojo", "reports/junit_dojo.xml")
186+
"""
186187

187188
print"\n=============================================="
188189
print "Total Number of New Findings: " + str(findings.data["meta"]["total_count"])
@@ -192,7 +193,7 @@ def summary(dd, engagement_id, test_ids, max_critical=0, max_high=0, max_medium=
192193
print
193194
print"=============================================="
194195

195-
strFail = ""
196+
strFail = None
196197
if max_critical is not None:
197198
if sum_new_findings[4] > max_critical:
198199
strFail = "Build Failed: Max Critical"
@@ -234,10 +235,11 @@ def print_findings(findings):
234235
class Main:
235236
if __name__ == "__main__":
236237
parser = argparse.ArgumentParser(description='CI/CD integration for DefectDojo')
237-
parser.add_argument('--host', help="Dojo Hostname", required=True)
238+
parser.add_argument('--host', help="DefectDojo Hostname", required=True)
239+
parser.add_argument('--proxy', help="Proxy ex:localhost:8080", required=False, default=None)
238240
parser.add_argument('--api_key', help="API Key", required=True)
239241
parser.add_argument('--user', help="User", required=True)
240-
parser.add_argument('--product', help="Dojo Product ID", required=True)
242+
parser.add_argument('--product', help="DefectDojo Product ID", required=True)
241243
parser.add_argument('--file', help="Scanner file", required=False)
242244
parser.add_argument('--dir', help="Scanner directory, needs to have the scanner name with the scan file in the folder. Ex: reports/nmap/nmap.csv", required=False)
243245
parser.add_argument('--scanner', help="Type of scanner", required=False)
@@ -261,10 +263,11 @@ class Main:
261263
max_high = args["high"]
262264
max_medium = args["medium"]
263265
build = args["build"]
266+
proxy = args["proxy"]
264267

265268
if dir is not None or file is not None:
266-
dd = dojo_connection(host, api_key, user)
267-
engagement_id = return_engagement(dd, product_id)
269+
dd = dojo_connection(host, api_key, user, proxy=proxy)
270+
engagement_id = return_engagement(dd, product_id, user)
268271
test_ids = None
269272
if file is not None:
270273
if scanner is not None:

examples/reports/junit_dojo.xml

Lines changed: 49 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,97 +1,55 @@
11
<?xml version="1.0" ?>
2-
<testsuite failures="4" name="DefectDojo" tests="4">
3-
<testcase name="blacklist Severity: Info">
4-
<failure>Using cElementTree to parse untrusted XML data is known to be vulnerable to XML attacks. Replace cElementTree with the equivalent defusedxml package, or make sure defusedxml.defuse_stdlib() is called. Filename: PyBitBucket.py Line number: 6 Line range: [6, 7, 8, 9] Issue Confidence: HIGH</failure>
2+
<testsuite failures="13" name="DefectDojo" tests="13">
3+
<testcase name="Application Error Disclosure Severity: Medium">
4+
<failure>&lt;p&gt;This page contains an error/warning message that may disclose sensitive information like the location of the file that produced the unhandled exception. This information can be used to launch further attacks against the web application. The alert could be a false positive if the error message is found inside a documentation page.&lt;/p&gt;
5+
Reference: &lt;p&gt;&lt;/p&gt;</failure>
56
</testcase>
6-
<testcase name="SQL injection Severity: High">
7-
<failure>SQL injection vulnerabilities arise when user-controllable data is
8-
incorporated into database SQL queries in an unsafe manner. An attacker can
9-
supply crafted input to break out of the data context in which their input
10-
appears and interfere with the structure of the surrounding query.
11-
12-
A wide range of damaging attacks can often be delivered via SQL injection,
13-
including reading or modifying critical application data, interfering with
14-
application logic, escalating privileges within the database and taking
15-
control of the database server.
16-
17-
18-
19-
The **sort_column** parameter appears to be vulnerable to SQL injection
20-
attacks. The payload **,(select*from(select(sleep(20)))a)** was submitted in
21-
the sort_column parameter. The application took **20562** milliseconds to
22-
respond to the request, compared with **1980** milliseconds for the original
23-
request, indicating that the injected SQL command caused a time delay.
24-
25-
The database appears to be MySQL.
26-
27-
</failure>
7+
<testcase name="HTTP Parameter Override Severity: Medium">
8+
<failure>&lt;p&gt;Unspecified form action: HTTP parameter override attack potentially possible. This is a known problem with Java Servlets but other platforms may also be vulnerable.&lt;/p&gt;
9+
Reference: &lt;p&gt;http://download.oracle.com/javaee-archive/servlet-spec.java.net/jsr340-experts/att-0317/OnParameterPollutionAttacks.pdf&lt;/p&gt;</failure>
2810
</testcase>
29-
<testcase name="Cross-origin resource sharing Severity: Info">
30-
<failure>An HTML5 cross-origin resource sharing (CORS) policy controls whether and how
31-
content running on other domains can perform two-way interaction with the
32-
domain that publishes the policy. The policy is fine-grained and can apply
33-
access controls per-request based on the URL and other features of the
34-
request.
35-
36-
If another domain is allowed by the policy, then that domain can potentially
37-
attack users of the application. If a user is logged in to the application,
38-
and visits a domain allowed by the policy, then any malicious content running
39-
on that domain can potentially retrieve content from the application, and
40-
sometimes carry out actions within the security context of the logged in user.
41-
42-
Even if an allowed domain is not overtly malicious in itself, security
43-
vulnerabilities within that domain could potentially be leveraged by an
44-
attacker to exploit the trust relationship and attack the application that
45-
allows access. CORS policies on pages containing sensitive information should
46-
be reviewed to determine whether it is appropriate for the application to
47-
trust both the intentions and security posture of any domains granted access.
48-
49-
50-
51-
The application implements an HTML5 cross-origin resource sharing (CORS)
52-
policy for this request.
53-
54-
If the application relies on network firewalls or other IP-based access
55-
controls, this policy is likely to present a security risk.
56-
57-
Since the Vary: Origin header was not present in the response, reverse proxies
58-
and intermediate servers may cache it. This may enable an attacker to carry
59-
out cache poisoning attacks.
60-
61-
</failure>
11+
<testcase name="Weak Authentication Method Severity: Medium">
12+
<failure>&lt;p&gt;HTTP basic or digest authentication has been used over an unsecured connection. The credentials can be read and then reused by someone with access to the network.&lt;/p&gt;
13+
Reference: &lt;p&gt;www.owasp.org/index.php/Category:Authentication_Vulnerability&lt;/p&gt;</failure>
6214
</testcase>
63-
<testcase name="Cross-origin resource sharing: arbitrary origin trusted Severity: Info">
64-
<failure>An HTML5 cross-origin resource sharing (CORS) policy controls whether and how
65-
content running on other domains can perform two-way interaction with the
66-
domain that publishes the policy. The policy is fine-grained and can apply
67-
access controls per-request based on the URL and other features of the
68-
request.
69-
70-
Trusting arbitrary origins effectively disables the same-origin policy,
71-
allowing two-way interaction by third-party web sites. Unless the response
72-
consists only of unprotected public content, this policy is likely to present
73-
a security risk.
74-
75-
If the site specifies the header Access-Control-Allow-Credentials: true,
76-
third-party sites may be able to carry out privileged actions and retrieve
77-
sensitive information. Even if it does not, attackers may be able to bypass
78-
any IP-based access controls by proxying through users' browsers.
79-
80-
81-
82-
The application implements an HTML5 cross-origin resource sharing (CORS)
83-
policy for this request that allows access from any domain.
84-
85-
The application allowed access from the requested origin
86-
**https://pfcxuvwamstc.com**
87-
88-
If the application relies on network firewalls or other IP-based access
89-
controls, this policy is likely to present a security risk.
90-
91-
Since the Vary: Origin header was not present in the response, reverse proxies
92-
and intermediate servers may cache it. This may enable an attacker to carry
93-
out cache poisoning attacks.
94-
95-
</failure>
15+
<testcase name="X-Frame-Options Header Not Set Severity: Medium">
16+
<failure>&lt;p&gt;X-Frame-Options header is not included in the HTTP response to protect against 'ClickJacking' attacks.&lt;/p&gt;
17+
Reference: &lt;p&gt;http://blogs.msdn.com/b/ieinternals/archive/2010/03/30/combating-clickjacking-with-x-frame-options.aspx&lt;/p&gt;</failure>
18+
</testcase>
19+
<testcase name="Absence of Anti-CSRF Tokens Severity: Low">
20+
<failure>&lt;p&gt;No Anti-CSRF tokens were found in a HTML submission form.&lt;/p&gt;&lt;p&gt;A cross-site request forgery is an attack that involves forcing a victim to send an HTTP request to a target destination without their knowledge or intent in order to perform an action as the victim. The underlying cause is application functionality using predictable URL/form actions in a repeatable way. The nature of the attack is that CSRF exploits the trust that a web site has for a user. By contrast, cross-site scripting (XSS) exploits the trust that a user has for a web site. Like XSS, CSRF attacks are not necessarily cross-site, but they can be. Cross-site request forgery is also known as CSRF, XSRF, one-click attack, session riding, confused deputy, and sea surf.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;CSRF attacks are effective in a number of situations, including:&lt;/p&gt;&lt;p&gt; * The victim has an active session on the target site.&lt;/p&gt;&lt;p&gt; * The victim is authenticated via HTTP auth on the target site.&lt;/p&gt;&lt;p&gt; * The victim is on the same local network as the target site.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;CSRF has primarily been used to perform an action against a target site using the victim's privileges, but recent techniques have been discovered to disclose information by gaining access to the response. The risk of information disclosure is dramatically increased when the target site is vulnerable to XSS, because XSS can be used as a platform for CSRF, allowing the attack to operate within the bounds of the same-origin policy.&lt;/p&gt;
21+
Reference: &lt;p&gt;http://projects.webappsec.org/Cross-Site-Request-Forgery&lt;/p&gt;&lt;p&gt;http://cwe.mitre.org/data/definitions/352.html&lt;/p&gt;</failure>
22+
</testcase>
23+
<testcase name="Content-Type Header Missing Severity: Low">
24+
<failure>&lt;p&gt;The Content-Type header was either missing or empty.&lt;/p&gt;
25+
Reference: &lt;p&gt;http://msdn.microsoft.com/en-us/library/ie/gg622941%28v=vs.85%29.aspx&lt;/p&gt;</failure>
26+
</testcase>
27+
<testcase name="Cookie No HttpOnly Flag Severity: Low">
28+
<failure>&lt;p&gt;A cookie has been set without the HttpOnly flag, which means that the cookie can be accessed by JavaScript. If a malicious script can be run on this page then the cookie will be accessible and can be transmitted to another site. If this is a session cookie then session hijacking may be possible.&lt;/p&gt;
29+
Reference: &lt;p&gt;http://www.owasp.org/index.php/HttpOnly&lt;/p&gt;</failure>
30+
</testcase>
31+
<testcase name="Information Disclosure - Debug Error Messages Severity: Low">
32+
<failure>&lt;p&gt;The response appeared to contain common error messages returned by platforms such as ASP.NET, and Web-servers such as IIS and Apache. You can configure the list of common debug messages.&lt;/p&gt;
33+
Reference: &lt;p&gt;&lt;/p&gt;</failure>
34+
</testcase>
35+
<testcase name="Password Autocomplete in Browser Severity: Low">
36+
<failure>&lt;p&gt;The AUTOCOMPLETE attribute is not disabled on an HTML FORM/INPUT element containing password type input. Passwords may be stored in browsers and retrieved.&lt;/p&gt;
37+
Reference: &lt;p&gt;http://www.w3schools.com/tags/att_input_autocomplete.asp&lt;/p&gt;&lt;p&gt;https://msdn.microsoft.com/en-us/library/ms533486%28v=vs.85%29.aspx&lt;/p&gt;</failure>
38+
</testcase>
39+
<testcase name="Private IP Disclosure Severity: Low">
40+
<failure>&lt;p&gt;A private IP (such as 10.x.x.x, 172.x.x.x, 192.168.x.x) or an Amazon EC2 private hostname (for example, ip-10-0-56-78) has been found in the HTTP response body. This information might be helpful for further attacks targeting internal systems.&lt;/p&gt;
41+
Reference: &lt;p&gt;https://tools.ietf.org/html/rfc1918&lt;/p&gt;</failure>
42+
</testcase>
43+
<testcase name="Web Browser XSS Protection Not Enabled Severity: Low">
44+
<failure>&lt;p&gt;Web Browser XSS Protection is not enabled, or is disabled by the configuration of the 'X-XSS-Protection' HTTP response header on the web server&lt;/p&gt;
45+
Reference: &lt;p&gt;https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet&lt;/p&gt;&lt;p&gt;https://blog.veracode.com/2014/03/guidelines-for-setting-security-headers/&lt;/p&gt;</failure>
46+
</testcase>
47+
<testcase name="X-Content-Type-Options Header Missing Severity: Low">
48+
<failure>&lt;p&gt;The Anti-MIME-Sniffing header X-Content-Type-Options was not set to 'nosniff'. This allows older versions of Internet Explorer and Chrome to perform MIME-sniffing on the response body, potentially causing the response body to be interpreted and displayed as a content type other than the declared content type. Current (early 2014) and legacy versions of Firefox will use the declared content type (if one is set), rather than performing MIME-sniffing.&lt;/p&gt;
49+
Reference: &lt;p&gt;http://msdn.microsoft.com/en-us/library/ie/gg622941%28v=vs.85%29.aspx&lt;/p&gt;&lt;p&gt;https://www.owasp.org/index.php/List_of_useful_HTTP_headers&lt;/p&gt;</failure>
50+
</testcase>
51+
<testcase name="Information Disclosure - Suspicious Comments Severity: Info">
52+
<failure>&lt;p&gt;The response appears to contain suspicious comments which may help an attacker.&lt;/p&gt;
53+
Reference: &lt;p&gt;&lt;/p&gt;</failure>
9654
</testcase>
9755
</testsuite>

0 commit comments

Comments
 (0)