diff --git a/plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/CodeQLReader.java b/plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/CodeQLReader.java index e52bf925..e48e89f9 100644 --- a/plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/CodeQLReader.java +++ b/plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/CodeQLReader.java @@ -43,7 +43,8 @@ public boolean canRead(ResultFile resultFile) { .getJSONObject(0) .getJSONObject("tool") .getJSONObject("driver") - .has("semanticVersion"); + .get("name") + .equals("CodeQL"); } catch (Exception e) { return false; } diff --git a/plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/Reader.java b/plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/Reader.java index 0a7354c8..53787e5a 100644 --- a/plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/Reader.java +++ b/plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/Reader.java @@ -88,6 +88,7 @@ public static List allReaders() { new ScnrReader(), new SeekerReader(), new SemgrepReader(), + new SemgrepSarifReader(), new ShiftLeftReader(), new ShiftLeftScanReader(), new SnappyTickReader(), diff --git a/plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/SarifReader.java b/plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/SarifReader.java new file mode 100644 index 00000000..e2a6db91 --- /dev/null +++ b/plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/SarifReader.java @@ -0,0 +1,114 @@ +/** + * OWASP Benchmark Project + * + *

This file is part of the Open Web Application Security Project (OWASP) Benchmark Project For + * details, please see https://owasp.org/www-project-benchmark/. + * + *

The OWASP Benchmark is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Foundation, version 2. + * + *

The OWASP Benchmark is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * @author Sascha Knoop + * @created 2024 + */ +package org.owasp.benchmarkutils.score.parsers; + +import java.util.Map; +import org.json.JSONArray; +import org.json.JSONObject; +import org.owasp.benchmarkutils.score.BenchmarkScore; +import org.owasp.benchmarkutils.score.ResultFile; +import org.owasp.benchmarkutils.score.TestCaseResult; +import org.owasp.benchmarkutils.score.TestSuiteResults; + +public abstract class SarifReader extends Reader { + + private static final int INVALID_RULE_ID = -1; + + protected abstract String expectedSarifToolName(); + + protected abstract boolean isCommercial(); + + protected abstract Map ruleCweMappings(JSONArray rules); + + @Override + public boolean canRead(ResultFile resultFile) { + try { + return resultFile.isJson() && sarifToolName(resultFile).equals(expectedSarifToolName()); + } catch (Exception e) { + return false; + } + } + + private String sarifToolName(ResultFile resultFile) { + return toolDriver(resultFile).getString("name"); + } + + private static JSONObject toolDriver(ResultFile resultFile) { + return firstRun(resultFile).getJSONObject("tool").getJSONObject("driver"); + } + + private static JSONObject firstRun(ResultFile resultFile) { + return resultFile.json().getJSONArray("runs").getJSONObject(0); + } + + @Override + public TestSuiteResults parse(ResultFile resultFile) throws Exception { + JSONObject driver = toolDriver(resultFile); + + Map mappings = ruleCweMappings(driver.getJSONArray("rules")); + + TestSuiteResults testSuiteResults = + new TestSuiteResults( + sarifToolName(resultFile), isCommercial(), TestSuiteResults.ToolType.SAST); + + testSuiteResults.setToolVersion(driver.getString("semanticVersion")); + + JSONArray results = firstRun(resultFile).getJSONArray("results"); + + for (int i = 0; i < results.length(); i++) { + JSONObject result = results.getJSONObject(i); + + String className = extractFilename(resultUri(result)); + + if (!className.startsWith(BenchmarkScore.TESTCASENAME)) { + continue; + } + + TestCaseResult tcr = new TestCaseResult(); + + String ruleId = result.getString("ruleId"); + + int cwe = mappings.getOrDefault(ruleId, INVALID_RULE_ID); + + if (cwe == INVALID_RULE_ID) { + System.out.println("CWE # not parseable from: " + ruleId); + continue; + } + + String evidence = result.getJSONObject("message").getString("text"); + + tcr.setCWE(cwe); + tcr.setCategory(ruleId); + tcr.setEvidence(evidence); + tcr.setConfidence(0); + tcr.setNumber(testNumber(className)); + + testSuiteResults.put(tcr); + } + + return testSuiteResults; + } + + private static String resultUri(JSONObject result) { + return result.getJSONArray("locations") + .getJSONObject(0) + .getJSONObject("physicalLocation") + .getJSONObject("artifactLocation") + .getString("uri"); + } +} diff --git a/plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/SemgrepSarifReader.java b/plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/SemgrepSarifReader.java new file mode 100644 index 00000000..2795c5e9 --- /dev/null +++ b/plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/SemgrepSarifReader.java @@ -0,0 +1,61 @@ +/** + * OWASP Benchmark Project + * + *

This file is part of the Open Web Application Security Project (OWASP) Benchmark Project For + * details, please see https://owasp.org/www-project-benchmark/. + * + *

The OWASP Benchmark is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Foundation, version 2. + * + *

The OWASP Benchmark is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * @author Sascha Knoop + * @created 2024 + */ +package org.owasp.benchmarkutils.score.parsers; + +import static java.lang.Integer.parseInt; + +import java.util.HashMap; +import java.util.Map; +import org.json.JSONArray; +import org.json.JSONObject; + +public class SemgrepSarifReader extends SarifReader { + + @Override + protected String expectedSarifToolName() { + return "Semgrep OSS"; + } + + @Override + protected boolean isCommercial() { + return false; + } + + @Override + protected Map ruleCweMappings(JSONArray rules) { + Map mappings = new HashMap<>(); + + for (int i = 0; i < rules.length(); i++) { + JSONObject rule = rules.getJSONObject(i); + + JSONArray tags = rule.getJSONObject("properties").getJSONArray("tags"); + + for (int j = 0; j < tags.length(); j++) { + String tag = tags.getString(j); + + if (tag.startsWith("CWE")) { + int cwe = parseInt(tag.split(":")[0].substring(4)); + + mappings.put(rule.getString("id"), cwe); + } + } + } + + return mappings; + } +} diff --git a/plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/SnykReader.java b/plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/SnykReader.java index 52d405d6..10439bd3 100644 --- a/plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/SnykReader.java +++ b/plugin/src/main/java/org/owasp/benchmarkutils/score/parsers/SnykReader.java @@ -1,121 +1,58 @@ +/** + * OWASP Benchmark Project + * + *

This file is part of the Open Web Application Security Project (OWASP) Benchmark Project For + * details, please see https://owasp.org/www-project-benchmark/. + * + *

The OWASP Benchmark is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Foundation, version 2. + * + *

The OWASP Benchmark is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details + * + * @author Raj Barath + * @created 2023 + */ package org.owasp.benchmarkutils.score.parsers; +import static java.lang.Integer.parseInt; + import java.util.HashMap; import java.util.Map; import org.json.JSONArray; -import org.json.JSONException; import org.json.JSONObject; -import org.owasp.benchmarkutils.score.BenchmarkScore; -import org.owasp.benchmarkutils.score.CweNumber; -import org.owasp.benchmarkutils.score.ResultFile; -import org.owasp.benchmarkutils.score.TestCaseResult; -import org.owasp.benchmarkutils.score.TestSuiteResults; - -public class SnykReader extends Reader { - public static final int INVALID_RULE_ID = -1; - private static final Map snykCweMap = - new HashMap() { - { - put("Xpath", CweNumber.XPATH_INJECTION); - put("WebCookieWithSecureFalse", CweNumber.INSECURE_COOKIE); - put("Sqli", CweNumber.SQL_INJECTION); - put("PT", CweNumber.PATH_TRAVERSAL); - put("HardcodedPassword", 0); - put("NoHardcodedCredentials", 0); - put("WebCookieMissesCallToSetHttpOnly", CweNumber.COOKIE_WITHOUT_HTTPONLY); - put("ServerInformationExposure", 0); - put("UserControlledFormatString", CweNumber.EXTERNALLY_CONTROLLED_STRING); - put("SpringCSRF", CweNumber.CSRF); - put("TrustBoundaryViolation", CweNumber.TRUST_BOUNDARY_VIOLATION); - put("CommandInjection", CweNumber.COMMAND_INJECTION); - put("EnvCommandInjection", CweNumber.COMMAND_INJECTION); - put("DOMXSS", CweNumber.XSS); - put("XSS", CweNumber.XSS); - put("InsecureCipherNoIntegrity", CweNumber.WEAK_CRYPTO_ALGO); - put("InsecureDefaultAesCipher", CweNumber.WEAK_CRYPTO_ALGO); - put("HttpResponseSplitting", CweNumber.HTTP_RESPONSE_SPLITTING); - put("InsecureSecret", CweNumber.WEAK_RANDOM); - put("LdapInjection", CweNumber.LDAP_INJECTION); - put("InsecureCipher", CweNumber.WEAK_CRYPTO_ALGO); - put("InsecureHash", CweNumber.WEAK_HASH_ALGO); - } - }; +public class SnykReader extends SarifReader { @Override - public boolean canRead(ResultFile resultFile) { - return resultFile.isJson() && isSnyk(resultFile); + protected String expectedSarifToolName() { + return "SnykCode"; } @Override - public TestSuiteResults parse(ResultFile resultFile) throws Exception { - TestSuiteResults tr = new TestSuiteResults("Snyk", true, TestSuiteResults.ToolType.SAST); - - JSONArray results = - resultFile.json().getJSONArray("runs").getJSONObject(0).getJSONArray("results"); - - for (int result = 0; result < results.length(); result++) { - TestCaseResult tcr = parseSnykFindings(results.getJSONObject(result)); - if (tcr != null) { - tr.put(tcr); - } - } - return tr; + protected boolean isCommercial() { + return true; } - private TestCaseResult parseSnykFindings(JSONObject result) { - try { - String className = - result.getJSONArray("locations") - .getJSONObject(0) - .getJSONObject("physicalLocation") - .getJSONObject("artifactLocation") - .getString("uri"); - className = (className.substring(className.lastIndexOf('/') + 1)).split("\\.")[0]; - if (className.startsWith(BenchmarkScore.TESTCASENAME)) { - - TestCaseResult tcr = new TestCaseResult(); - - String ruleId = result.getString("ruleId"); - ruleId = (ruleId.substring(ruleId.lastIndexOf('/') + 1)).split("\\.")[0]; - - int cwe = snykCweMap.getOrDefault(ruleId, INVALID_RULE_ID); - - if (cwe == INVALID_RULE_ID) { - System.out.println("CWE # not parseable from: " + ruleId); - return null; - } + @Override + protected Map ruleCweMappings(JSONArray rules) { + Map mappings = new HashMap<>(); - String evidence = result.getJSONObject("message").getString("text"); + for (int i = 0; i < rules.length(); i++) { + JSONObject rule = rules.getJSONObject(i); - tcr.setCWE(cwe); - tcr.setCategory(ruleId); - tcr.setEvidence(evidence); - tcr.setConfidence(0); - tcr.setNumber(testNumber(className)); + int cwe = + parseInt( + rule.getJSONObject("properties") + .getJSONArray("cwe") + .getString(0) + .substring(4)); - return tcr; - } - } catch (Exception ex) { - ex.printStackTrace(); + mappings.put(rule.getString("id"), cwe); } - return null; - } - - private Boolean isSnyk(ResultFile resultFile) { - - try { - return resultFile - .json() - .getJSONArray("runs") - .getJSONObject(0) - .getJSONObject("tool") - .getJSONObject("driver") - .getString("name") - .equalsIgnoreCase("SnykCode"); - } catch (JSONException e) { - return false; - } + return mappings; } } diff --git a/plugin/src/test/java/org/owasp/benchmarkutils/score/builder/ToolResultsBuilder.java b/plugin/src/test/java/org/owasp/benchmarkutils/score/builder/ToolResultsBuilder.java new file mode 100644 index 00000000..7b2f6ba4 --- /dev/null +++ b/plugin/src/test/java/org/owasp/benchmarkutils/score/builder/ToolResultsBuilder.java @@ -0,0 +1,33 @@ +package org.owasp.benchmarkutils.score.builder; + +import java.util.HashMap; +import java.util.Map; +import org.owasp.benchmarkutils.score.CategoryResults; +import org.owasp.benchmarkutils.score.ToolResults; + +public class ToolResultsBuilder { + + private Map categoryResultsMap = new HashMap<>(); + + private ToolResultsBuilder() {} + + public static ToolResultsBuilder builder() { + return new ToolResultsBuilder(); + } + + public ToolResults build() { + return null; + } + + public ToolResultsBuilder setCategoryResults(Map categoryResultsMap) { + this.categoryResultsMap = categoryResultsMap; + + return this; + } + + public ToolResultsBuilder setCategoryResult(String key, CategoryResults value) { + this.categoryResultsMap.put(key, value); + + return this; + } +} diff --git a/plugin/src/test/java/org/owasp/benchmarkutils/score/parsers/SemgrepSarifReaderTest.java b/plugin/src/test/java/org/owasp/benchmarkutils/score/parsers/SemgrepSarifReaderTest.java new file mode 100644 index 00000000..1627cb88 --- /dev/null +++ b/plugin/src/test/java/org/owasp/benchmarkutils/score/parsers/SemgrepSarifReaderTest.java @@ -0,0 +1,61 @@ +/** + * OWASP Benchmark Project + * + *

This file is part of the Open Web Application Security Project (OWASP) Benchmark Project For + * details, please see https://owasp.org/www-project-benchmark/. + * + *

The OWASP Benchmark is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Foundation, version 2. + * + *

The OWASP Benchmark is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * @author Sascha Knoop + * @created 2024 + */ +package org.owasp.benchmarkutils.score.parsers; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.owasp.benchmarkutils.score.BenchmarkScore; +import org.owasp.benchmarkutils.score.CweNumber; +import org.owasp.benchmarkutils.score.ResultFile; +import org.owasp.benchmarkutils.score.TestHelper; +import org.owasp.benchmarkutils.score.TestSuiteResults; + +class SemgrepSarifReaderTest extends ReaderTestBase { + + private ResultFile resultFile; + + @BeforeEach + void setUp() { + resultFile = TestHelper.resultFileOf("testfiles/Benchmark_semgrep-v1.67.0.sarif"); + BenchmarkScore.TESTCASENAME = "BenchmarkTest"; + } + + @Test + public void onlySemgrepSarifReaderReportsCanReadAsTrue() { + assertOnlyMatcherClassIs(this.resultFile, SemgrepSarifReader.class); + } + + @Test + void readerHandlesGivenResultFile() throws Exception { + SemgrepSarifReader reader = new SemgrepSarifReader(); + TestSuiteResults result = reader.parse(resultFile); + + assertEquals(TestSuiteResults.ToolType.SAST, result.getToolType()); + assertFalse(result.isCommercial()); + assertEquals("Semgrep OSS", result.getToolName()); + assertEquals("1.67.0", result.getToolVersion()); + + assertEquals(2, result.getTotalResults()); + + assertEquals(CweNumber.COOKIE_WITHOUT_HTTPONLY, result.get(1).get(0).getCWE()); + assertEquals(CweNumber.XSS, result.get(2).get(0).getCWE()); + } +} diff --git a/plugin/src/test/java/org/owasp/benchmarkutils/score/parsers/SnykReaderTest.java b/plugin/src/test/java/org/owasp/benchmarkutils/score/parsers/SnykReaderTest.java index 92e2e855..99f20cd4 100644 --- a/plugin/src/test/java/org/owasp/benchmarkutils/score/parsers/SnykReaderTest.java +++ b/plugin/src/test/java/org/owasp/benchmarkutils/score/parsers/SnykReaderTest.java @@ -1,3 +1,20 @@ +/** + * OWASP Benchmark Project + * + *

This file is part of the Open Web Application Security Project (OWASP) Benchmark Project For + * details, please see https://owasp.org/www-project-benchmark/. + * + *

The OWASP Benchmark is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Foundation, version 2. + * + *

The OWASP Benchmark is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details + * + * @author Raj Barath + * @created 2023 + */ package org.owasp.benchmarkutils.score.parsers; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -11,13 +28,13 @@ import org.owasp.benchmarkutils.score.TestHelper; import org.owasp.benchmarkutils.score.TestSuiteResults; -public class SnykReaderTest extends ReaderTestBase { +class SnykReaderTest extends ReaderTestBase { private ResultFile resultFile; @BeforeEach void setUp() { - resultFile = TestHelper.resultFileOf("testfiles/Benchmark_Snyk-v1.json"); + resultFile = TestHelper.resultFileOf("testfiles/Benchmark_SnykCodeCli.sarif"); BenchmarkScore.TESTCASENAME = "BenchmarkTest"; } @@ -33,10 +50,12 @@ void readerHandlesGivenResultFile() throws Exception { assertEquals(TestSuiteResults.ToolType.SAST, result.getToolType()); assertTrue(result.isCommercial()); - assertEquals("Snyk", result.getToolName()); + assertEquals("SnykCode", result.getToolName()); + assertEquals("1.0.0", result.getToolVersion()); assertEquals(2, result.getTotalResults()); - assertEquals(CweNumber.XSS, result.get(1).get(0).getCWE()); - assertEquals(CweNumber.SQL_INJECTION, result.get(2).get(0).getCWE()); + + assertEquals(CweNumber.INSECURE_COOKIE, result.get(1).get(0).getCWE()); + assertEquals(CweNumber.XPATH_INJECTION, result.get(2).get(0).getCWE()); } } diff --git a/plugin/src/test/resources/testfiles/Benchmark_Snyk-v1.json b/plugin/src/test/resources/testfiles/Benchmark_Snyk-v1.json deleted file mode 100644 index 7b8a9935..00000000 --- a/plugin/src/test/resources/testfiles/Benchmark_Snyk-v1.json +++ /dev/null @@ -1,487 +0,0 @@ -{ - "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json", - "version": "2.1.0", - "runs": [ - { - "tool": { - "driver": { - "name": "SnykCode", - "semanticVersion": "1.0.0", - "version": "1.0.0", - "rules": [] - } - }, - "results": [ - { - "ruleId": "java/Sqli", - "ruleIndex": 2, - "level": "error", - "message": { - "text": "Unsanitized input from an HTTP parameter flows into executeUpdate, where it is used in an SQL query. This may result in an SQL Injection vulnerability.", - "markdown": "Unsanitized input from {0} {1} into {2}, where it is used in an SQL query. This may result in an SQL Injection vulnerability.", - "arguments": [ - "[an HTTP parameter](0)", - "[flows](1),(2),(3),(4),(5),(6),(7),(8)", - "[executeUpdate](9)" - ] - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "src/main/java/org/owasp/benchmark/testcode/BenchmarkTest00002.java", - "uriBaseId": "%SRCROOT%" - }, - "region": { - "startLine": 55, - "endLine": 55, - "startColumn": 25, - "endColumn": 48 - } - } - } - ], - "fingerprints": { - "0": "ae420f466c438a07f83839c953ad67d48c6a47b8db137dea582f78d7310eae70", - "1": "19689298.83dbfe52.62790746.7723e099.9c64308b.7a44f5da.f189b689.54d46e25.c9f51d48.0cb0dce9.62790746.66516a7b.0f22ce88.aebaea90.0ac97cd8.0dceee21" - }, - "codeFlows": [ - { - "threadFlows": [ - { - "locations": [ - { - "location": { - "id": 0, - "physicalLocation": { - "artifactLocation": { - "uri": "src/main/java/org/owasp/benchmark/testcode/BenchmarkTest00002.java", - "uriBaseId": "%SRCROOT%" - }, - "region": { - "startLine": 45, - "endLine": 45, - "startColumn": 24, - "endColumn": 43 - } - } - } - }, - { - "location": { - "id": 1, - "physicalLocation": { - "artifactLocation": { - "uri": "src/main/java/org/owasp/benchmark/testcode/BenchmarkTest00002.java", - "uriBaseId": "%SRCROOT%" - }, - "region": { - "startLine": 45, - "endLine": 45, - "startColumn": 24, - "endColumn": 43 - } - } - } - }, - { - "location": { - "id": 2, - "physicalLocation": { - "artifactLocation": { - "uri": "src/main/java/org/owasp/benchmark/testcode/BenchmarkTest00002.java", - "uriBaseId": "%SRCROOT%" - }, - "region": { - "startLine": 45, - "endLine": 45, - "startColumn": 16, - "endColumn": 65 - } - } - } - }, - { - "location": { - "id": 3, - "physicalLocation": { - "artifactLocation": { - "uri": "src/main/java/org/owasp/benchmark/testcode/BenchmarkTest00002.java", - "uriBaseId": "%SRCROOT%" - }, - "region": { - "startLine": 48, - "endLine": 48, - "startColumn": 22, - "endColumn": 44 - } - } - } - }, - { - "location": { - "id": 4, - "physicalLocation": { - "artifactLocation": { - "uri": "src/main/java/org/owasp/benchmark/testcode/BenchmarkTest00002.java", - "uriBaseId": "%SRCROOT%" - }, - "region": { - "startLine": 48, - "endLine": 48, - "startColumn": 16, - "endColumn": 60 - } - } - } - }, - { - "location": { - "id": 5, - "physicalLocation": { - "artifactLocation": { - "uri": "src/main/java/org/owasp/benchmark/testcode/BenchmarkTest00002.java", - "uriBaseId": "%SRCROOT%" - }, - "region": { - "startLine": 50, - "endLine": 50, - "startColumn": 22, - "endColumn": 84 - } - } - } - }, - { - "location": { - "id": 6, - "physicalLocation": { - "artifactLocation": { - "uri": "src/main/java/org/owasp/benchmark/testcode/BenchmarkTest00002.java", - "uriBaseId": "%SRCROOT%" - }, - "region": { - "startLine": 50, - "endLine": 50, - "startColumn": 22, - "endColumn": 91 - } - } - } - }, - { - "location": { - "id": 7, - "physicalLocation": { - "artifactLocation": { - "uri": "src/main/java/org/owasp/benchmark/testcode/BenchmarkTest00002.java", - "uriBaseId": "%SRCROOT%" - }, - "region": { - "startLine": 50, - "endLine": 50, - "startColumn": 16, - "endColumn": 91 - } - } - } - }, - { - "location": { - "id": 8, - "physicalLocation": { - "artifactLocation": { - "uri": "src/main/java/org/owasp/benchmark/testcode/BenchmarkTest00002.java", - "uriBaseId": "%SRCROOT%" - }, - "region": { - "startLine": 55, - "endLine": 55, - "startColumn": 49, - "endColumn": 52 - } - } - } - }, - { - "location": { - "id": 9, - "physicalLocation": { - "artifactLocation": { - "uri": "src/main/java/org/owasp/benchmark/testcode/BenchmarkTest00002.java", - "uriBaseId": "%SRCROOT%" - }, - "region": { - "startLine": 55, - "endLine": 55, - "startColumn": 25, - "endColumn": 48 - } - } - } - } - ] - } - ] - } - ], - "properties": { - "priorityScore": 756, - "priorityScoreFactors": [ - { - "label": true, - "type": "multipleOccurrence" - }, - { - "label": true, - "type": "hotFileCodeFlow" - }, - { - "label": true, - "type": "fixExamples" - } - ] - } - }, - { - "ruleId": "java/XSS", - "ruleIndex": 17, - "level": "error", - "message": { - "text": "Unsanitized input from an HTTP parameter flows into write, where it is used to render an HTML page returned to the user. This may result in a Cross-Site Scripting attack (XSS).", - "markdown": "Unsanitized input from {0} {1} into {2}, where it is used to render an HTML page returned to the user. This may result in a Cross-Site Scripting attack (XSS).", - "arguments": [ - "[an HTTP parameter](0)", - "[flows](1),(2),(3),(4),(5),(6),(7)", - "[write](8)" - ] - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "src/main/java/org/owasp/benchmark/testcode/BenchmarkTest00001.java", - "uriBaseId": "%SRCROOT%" - }, - "region": { - "startLine": 72, - "endLine": 72, - "startColumn": 13, - "endColumn": 39 - } - } - } - ], - "fingerprints": { - "0": "7ec672c875358716d1019adda98d870d5254cdd561c102bbc6b8ad2d20f7d7ac", - "1": "46d785bf.49766a9f.a7db88c8.8bdc56f8.390f960b.21fcf215.ec290f27.54d46e25.19689298.0cb0dce9.ae546236.d6ab05b5.0f22ce88.aebaea90.76a0da3b.54d46e25" - }, - "codeFlows": [ - { - "threadFlows": [ - { - "locations": [ - { - "location": { - "id": 0, - "physicalLocation": { - "artifactLocation": { - "uri": "src/main/java/org/owasp/benchmark/testcode/BenchmarkTest00001.java", - "uriBaseId": "%SRCROOT%" - }, - "region": { - "startLine": 45, - "endLine": 45, - "startColumn": 24, - "endColumn": 39 - } - } - } - }, - { - "location": { - "id": 1, - "physicalLocation": { - "artifactLocation": { - "uri": "src/main/java/org/owasp/benchmark/testcode/BenchmarkTest00001.java", - "uriBaseId": "%SRCROOT%" - }, - "region": { - "startLine": 45, - "endLine": 45, - "startColumn": 24, - "endColumn": 39 - } - } - } - }, - { - "location": { - "id": 2, - "physicalLocation": { - "artifactLocation": { - "uri": "src/main/java/org/owasp/benchmark/testcode/BenchmarkTest00001.java", - "uriBaseId": "%SRCROOT%" - }, - "region": { - "startLine": 45, - "endLine": 45, - "startColumn": 16, - "endColumn": 61 - } - } - } - }, - { - "location": { - "id": 3, - "physicalLocation": { - "artifactLocation": { - "uri": "src/main/java/org/owasp/benchmark/testcode/BenchmarkTest00001.java", - "uriBaseId": "%SRCROOT%" - }, - "region": { - "startLine": 54, - "endLine": 54, - "startColumn": 23, - "endColumn": 28 - } - } - } - }, - { - "location": { - "id": 4, - "physicalLocation": { - "artifactLocation": { - "uri": "src/main/java/org/owasp/benchmark/testcode/BenchmarkTest00001.java", - "uriBaseId": "%SRCROOT%" - }, - "region": { - "startLine": 54, - "endLine": 54, - "startColumn": 17, - "endColumn": 28 - } - } - } - }, - { - "location": { - "id": 5, - "physicalLocation": { - "artifactLocation": { - "uri": "src/main/java/org/owasp/benchmark/testcode/BenchmarkTest00001.java", - "uriBaseId": "%SRCROOT%" - }, - "region": { - "startLine": 71, - "endLine": 71, - "startColumn": 22, - "endColumn": 25 - } - } - } - }, - { - "location": { - "id": 6, - "physicalLocation": { - "artifactLocation": { - "uri": "src/main/java/org/owasp/benchmark/testcode/BenchmarkTest00001.java", - "uriBaseId": "%SRCROOT%" - }, - "region": { - "startLine": 72, - "endLine": 72, - "startColumn": 40, - "endColumn": 43 - } - } - } - }, - { - "location": { - "id": 7, - "physicalLocation": { - "artifactLocation": { - "uri": "src/main/java/org/owasp/benchmark/testcode/BenchmarkTest00001.java", - "uriBaseId": "%SRCROOT%" - }, - "region": { - "startLine": 72, - "endLine": 72, - "startColumn": 40, - "endColumn": 55 - } - } - } - }, - { - "location": { - "id": 8, - "physicalLocation": { - "artifactLocation": { - "uri": "src/main/java/org/owasp/benchmark/testcode/BenchmarkTest00001.java", - "uriBaseId": "%SRCROOT%" - }, - "region": { - "startLine": 72, - "endLine": 72, - "startColumn": 13, - "endColumn": 39 - } - } - } - } - ] - } - ] - } - ], - "properties": { - "priorityScore": 760, - "priorityScoreFactors": [ - { - "label": true, - "type": "multipleOccurrence" - }, - { - "label": true, - "type": "hotFileCodeFlow" - }, - { - "label": true, - "type": "fixExamples" - } - ] - } - } - ], - "properties": { - "coverage": [ - { - "files": 2766, - "isSupported": true, - "lang": "XML" - }, - { - "files": 2778, - "isSupported": true, - "lang": "HTML" - }, - { - "files": 6, - "isSupported": true, - "lang": "JavaScript" - }, - { - "files": 2763, - "isSupported": true, - "lang": "Java" - } - ] - } - } - ] -} diff --git a/plugin/src/test/resources/testfiles/Benchmark_SnykCodeCli.sarif b/plugin/src/test/resources/testfiles/Benchmark_SnykCodeCli.sarif new file mode 100644 index 00000000..c99a7308 --- /dev/null +++ b/plugin/src/test/resources/testfiles/Benchmark_SnykCodeCli.sarif @@ -0,0 +1,184 @@ +{ + "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json", + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "SnykCode", + "semanticVersion": "1.0.0", + "version": "1.0.0", + "rules": [ + { + "id": "java/WebCookieWithSecureFalse", + "name": "WebCookieWithSecureFalse", + "shortDescription": { + "text": "Sensitive Cookie in HTTPS Session Without 'Secure' Attribute" + }, + "defaultConfiguration": { + "level": "note" + }, + "help": { + "markdown": "\n## Details\n\nIn a session hijacking attack, if a cookie containing sensitive data is set without the `secure` attribute, an attacker might be able to intercept that cookie. Once the attacker has this information, they can potentially impersonate a user, accessing confidential data and performing actions that they would not normally be authorized to do. Attackers often gain access to this sensitive cookie data when it is transmitted insecurely in plain text over a standard HTTP session, rather than being encrypted and sent over an HTTPS session. This type of attack is highly preventable by following best practices when setting sensitive session cookies.\n\n## Best practices for prevention\n* Set the `secure` attribute in the response header when setting cookies on the client side, and use a test tool to verify that secure cookie transmission is in place.\n* Always use HTTPS for all login pages and never redirect from HTTP to HTTPS, which leaves secure session data open to interception.\n* Follow other best practices when it comes to session cookies, such as setting the HttpOnly flag and maintaining highly time-limited sessions.\n* Consider implementing browser checks and providing secure data only within a browser that supports tight cookie security.\n* Generate session IDs in a way that is not easily predictable, invalidate sessions upon logout, and never reuse session IDs.\n* Educate developers to use built-in secure session-management functionality within the development environment instead of taking a DIY approach.", + "text": "" + }, + "properties": { + "tags": [ + "java", + "WebCookieWithSecureFalse", + "Security" + ], + "categories": [ + "Security" + ], + "exampleCommitFixes": [], + "exampleCommitDescriptions": [], + "precision": "very-high", + "repoDatasetSize": 3, + "cwe": [ + "CWE-614" + ] + } + }, + { + "id": "java/Xpath", + "name": "Xpath", + "shortDescription": { + "text": "XPath Injection" + }, + "defaultConfiguration": { + "level": "error" + }, + "help": { + "markdown": "\n## Details\n\nXPath expressions are a standard method of querying data stored in XML format, allowing applications to return data based on attributes, patterns, and more. However, as with other injection-type attacks, if a malicious user is able to manipulate the query that is sent to the server, they may be able to gain control of application flow and logic or access unauthorized data, including user authentication data. This weakness is an inherent design flaw that can be easily corrected through awareness of the hazards of allowing unchecked user input in XPath queries.\n\n## Best practices for prevention\n* Use a parameterized XPath interface for all types of user input if possible.\n* Avoid passing unsanitized parameters to the XML database.\n* Never pass a query directly from the user to the server without sanitizing input.\n* Use a denylist to eliminate user-entered forbidden query characters.\n* Consider using precompiled XPath queries to circumvent issues with user-entered parameters altogether.", + "text": "" + }, + "properties": { + "tags": [ + "java", + "Xpath", + "Security", + "SourceServer", + "SourceHttpHeader", + "Taint" + ], + "categories": [ + "Security" + ], + "exampleCommitFixes": [], + "exampleCommitDescriptions": [], + "precision": "very-high", + "repoDatasetSize": 0, + "cwe": [ + "CWE-643" + ] + } + } + ] + } + }, + "results": [ + { + "ruleId": "java/WebCookieWithSecureFalse", + "ruleIndex": 0, + "level": "note", + "message": { + "text": "The cookie's Secure flag is set to setSecure. Set it to true to protect the cookie from man-in-the-middle attacks.", + "markdown": "The cookie's Secure flag is set to {0}. Set it to true to protect the cookie from man-in-the-middle attacks.", + "arguments": [ + "[setSecure](0)" + ] + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "src/main/java/org/owasp/benchmark/testcode/BenchmarkTest00001.java", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 65, + "endLine": 65, + "startColumn": 9, + "endColumn": 25 + } + } + } + ], + "fingerprints": { + "0": "0", + "1": "1" + }, + "codeFlows": [], + "properties": { + "priorityScore": 402, + "priorityScoreFactors": [ + { + "label": true, + "type": "multipleOccurrence" + }, + { + "label": true, + "type": "hotFileSource" + }, + { + "label": true, + "type": "fixExamples" + } + ], + "isAutofixable": false + } + }, + { + "ruleId": "java/Xpath", + "ruleIndex": 8, + "level": "error", + "message": { + "text": "Unsanitized input from an HTTP parameter flows into compile, where it is used in an XPath query. This may result in an XPath Injection vulnerability.", + "markdown": "Unsanitized input from {0} {1} into {2}, where it is used in an XPath query. This may result in an XPath Injection vulnerability.", + "arguments": [ + "[an HTTP parameter](0)", + "[flows](1),(2),(3),(4),(5),(6),(7),(8)", + "[compile](9)" + ] + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "src/main/java/org/owasp/benchmark/testcode/BenchmarkTest00002.java", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "startLine": 67, + "endLine": 67, + "startColumn": 29, + "endColumn": 39 + } + } + } + ], + "fingerprints": { + "0": "0", + "1": "1" + }, + "codeFlows": [], + "properties": { + "priorityScore": 601, + "priorityScoreFactors": [ + { + "label": true, + "type": "multipleOccurrence" + }, + { + "label": true, + "type": "hotFileSource" + } + ], + "isAutofixable": false + } + } + ] + } + ] +} diff --git a/plugin/src/test/resources/testfiles/Benchmark_semgrep-v1.67.0.sarif b/plugin/src/test/resources/testfiles/Benchmark_semgrep-v1.67.0.sarif new file mode 100644 index 00000000..b86ee2c3 --- /dev/null +++ b/plugin/src/test/resources/testfiles/Benchmark_semgrep-v1.67.0.sarif @@ -0,0 +1,131 @@ +{ + "$schema": "https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/schemas/sarif-schema-2.1.0.json", + "runs": [ + { + "results": [ + { + "fingerprints": { + "matchBasedId/v1": "1" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "src/main/java/org/owasp/benchmark/testcode/BenchmarkTest00001.java", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "endColumn": 40, + "endLine": 42, + "snippet": { + "text": " response.addCookie(userCookie);" + }, + "startColumn": 9, + "startLine": 42 + } + } + } + ], + "message": { + "text": "A cookie was detected without setting the 'HttpOnly' flag. The 'HttpOnly' flag for cookies instructs the browser to forbid client-side scripts from reading the cookie. Set the 'HttpOnly' flag by calling 'cookie.setHttpOnly(true);'" + }, + "properties": {}, + "ruleId": "java.lang.security.audit.cookie-missing-httponly.cookie-missing-httponly" + }, + { + "fingerprints": { + "matchBasedId/v1": "1" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "src/main/java/org/owasp/benchmark/testcode/BenchmarkTest00002.java", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "endColumn": 77, + "endLine": 73, + "snippet": { + "text": " response.getWriter()\n .println(\n \"Item: '\"\n + org.owasp.benchmark.helpers.Utils.encodeForHTML(param)\n + \"' with value: '10340' saved in session.\");" + }, + "startColumn": 9, + "startLine": 69 + } + } + } + ], + "message": { + "text": "Detected a request with potential user-input going into a OutputStream or Writer object. This bypasses any view or template environments, including HTML escaping, which may expose this application to cross-site scripting (XSS) vulnerabilities. Consider using a view technology such as JavaServer Faces (JSFs) which automatically escapes HTML views." + }, + "properties": {}, + "ruleId": "java.lang.security.audit.xss.no-direct-response-writer.no-direct-response-writer" + } + ], + "tool": { + "driver": { + "name": "Semgrep OSS", + "rules": [ + { + "defaultConfiguration": { + "level": "warning" + }, + "fullDescription": { + "text": "A cookie was detected without setting the 'HttpOnly' flag. The 'HttpOnly' flag for cookies instructs the browser to forbid client-side scripts from reading the cookie. Set the 'HttpOnly' flag by calling 'cookie.setHttpOnly(true);'" + }, + "help": { + "markdown": "A cookie was detected without setting the 'HttpOnly' flag. The 'HttpOnly' flag for cookies instructs the browser to forbid client-side scripts from reading the cookie. Set the 'HttpOnly' flag by calling 'cookie.setHttpOnly(true);'\n\n#### \ud83d\udc8e Enable cross-file analysis and Pro rules for free at sg.run/pro\n\nReferences:\n - [Semgrep Rule](https://semgrep.dev/r/java.lang.security.audit.cookie-missing-httponly.cookie-missing-httponly)\n - [https://owasp.org/Top10/A05_2021-Security_Misconfiguration](https://owasp.org/Top10/A05_2021-Security_Misconfiguration)\n", + "text": "A cookie was detected without setting the 'HttpOnly' flag. The 'HttpOnly' flag for cookies instructs the browser to forbid client-side scripts from reading the cookie. Set the 'HttpOnly' flag by calling 'cookie.setHttpOnly(true);'\n\ud83d\udc8e Enable cross-file analysis and Pro rules for free at sg.run/pro" + }, + "helpUri": "https://semgrep.dev/r/java.lang.security.audit.cookie-missing-httponly.cookie-missing-httponly", + "id": "java.lang.security.audit.cookie-missing-httponly.cookie-missing-httponly", + "name": "java.lang.security.audit.cookie-missing-httponly.cookie-missing-httponly", + "properties": { + "precision": "very-high", + "tags": [ + "CWE-1004: Sensitive Cookie Without 'HttpOnly' Flag", + "LOW CONFIDENCE", + "OWASP-A05:2021 - Security Misconfiguration", + "security" + ] + }, + "shortDescription": { + "text": "Semgrep Finding: java.lang.security.audit.cookie-missing-httponly.cookie-missing-httponly" + } + }, + { + "defaultConfiguration": { + "level": "warning" + }, + "fullDescription": { + "text": "Detected a request with potential user-input going into a OutputStream or Writer object. This bypasses any view or template environments, including HTML escaping, which may expose this application to cross-site scripting (XSS) vulnerabilities. Consider using a view technology such as JavaServer Faces (JSFs) which automatically escapes HTML views." + }, + "help": { + "markdown": "Detected a request with potential user-input going into a OutputStream or Writer object. This bypasses any view or template environments, including HTML escaping, which may expose this application to cross-site scripting (XSS) vulnerabilities. Consider using a view technology such as JavaServer Faces (JSFs) which automatically escapes HTML views.\n\n#### \ud83d\udc8e Enable cross-file analysis and Pro rules for free at sg.run/pro\n\nReferences:\n - [Semgrep Rule](https://semgrep.dev/r/java.lang.security.audit.xss.no-direct-response-writer.no-direct-response-writer)\n - [https://www3.ntu.edu.sg/home/ehchua/programming/java/JavaServerFaces.html](https://www3.ntu.edu.sg/home/ehchua/programming/java/JavaServerFaces.html)\n", + "text": "Detected a request with potential user-input going into a OutputStream or Writer object. This bypasses any view or template environments, including HTML escaping, which may expose this application to cross-site scripting (XSS) vulnerabilities. Consider using a view technology such as JavaServer Faces (JSFs) which automatically escapes HTML views.\n\ud83d\udc8e Enable cross-file analysis and Pro rules for free at sg.run/pro" + }, + "helpUri": "https://semgrep.dev/r/java.lang.security.audit.xss.no-direct-response-writer.no-direct-response-writer", + "id": "java.lang.security.audit.xss.no-direct-response-writer.no-direct-response-writer", + "name": "java.lang.security.audit.xss.no-direct-response-writer.no-direct-response-writer", + "properties": { + "precision": "very-high", + "tags": [ + "CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')", + "MEDIUM CONFIDENCE", + "OWASP-A03:2021 - Injection", + "OWASP-A07:2017 - Cross-Site Scripting (XSS)", + "security" + ] + }, + "shortDescription": { + "text": "Semgrep Finding: java.lang.security.audit.xss.no-direct-response-writer.no-direct-response-writer" + } + } + ], + "semanticVersion": "1.67.0" + } + } + } + ], + "version": "2.1.0" +} \ No newline at end of file