Merge branch 'master' into issue_718

This commit is contained in:
Jeremy Long
2017-05-14 13:17:01 -04:00
34 changed files with 1252 additions and 141 deletions

View File

@@ -2,13 +2,28 @@ FROM java:8
MAINTAINER Timo Pagel <dependencycheckmaintainer@timo-pagel.de>
RUN wget -O /tmp/current.txt http://jeremylong.github.io/DependencyCheck/current.txt && current=$(cat /tmp/current.txt) && wget https://dl.bintray.com/jeremy-long/owasp/dependency-check-$current-release.zip && unzip dependency-check-$current-release.zip && mv dependency-check /usr/share/
ENV user=dependencycheck
ENV version_url=https://jeremylong.github.io/DependencyCheck/current.txt
ENV download_url=https://dl.bintray.com/jeremy-long/owasp
RUN useradd -ms /bin/bash dockeruser && chown -R dockeruser:dockeruser /usr/share/dependency-check && mkdir /report && chown -R dockeruser:dockeruser /report
USER dockeruser
RUN wget -O /tmp/current.txt ${version_url} && \
version=$(cat /tmp/current.txt) && \
file="dependency-check-${version}-release.zip" && \
wget "$download_url/$file" && \
unzip ${file} && \
rm ${file} && \
mv dependency-check /usr/share/
VOLUME "/src /usr/share/dependency-check/data /report"
RUN useradd -ms /bin/bash ${user} && \
chown -R ${user}:${user} /usr/share/dependency-check && \
mkdir /report && \
chown -R ${user}:${user} /report
USER ${user}
VOLUME ["/src" "/usr/share/dependency-check/data" "/report"]
WORKDIR /report
ENTRYPOINT ["/usr/share/dependency-check/bin/dependency-check.sh", "--scan", "/src"]
CMD ["--help"]
ENTRYPOINT ["/usr/share/dependency-check/bin/dependency-check.sh"]

View File

@@ -93,40 +93,46 @@ $ ./dependency-check-cli/target/release/bin/dependency-check.sh --project Testin
On Windows
```
> mvn install
> dependency-check-cli/target/release/bin/dependency-check.bat -h
> dependency-check-cli/target/release/bin/dependency-check.bat --project Testing --out . --scan ./src/test/resources
> .\dependency-check-cli\target\release\bin\dependency-check.bat -h
> .\dependency-check-cli\target\release\bin\dependency-check.bat --project Testing --out . --scan ./src/test/resources
```
Then load the resulting 'DependencyCheck-Report.html' into your favorite browser.
### Docker
In the following example it is assumed that the source to be checked is in the actual directory. A persistent data directory and a persistent report directory is used so that the container can be destroyed after running it to make sure that you use the newest version, always.
```
# After the first run, feel free to change the owner of the directories to the owner of the created files and the permissions to 744
DATA_DIRECTORY=$HOME/OWASP-Dependency-Check/data
REPORT_DIRECTORY=/$HOME/OWASP-Dependency-Check/reports
In the following example it is assumed that the source to be checked is in the current working directory. Persistent data and report directories are used, allowing you to destroy the container after running.
if [ ! -d $DATA_DIRECTORY ]; then
echo "Initially creating persistent directories"
mkdir -p $DATA_DIRECTORY
chmod -R 777 $DATA_DIRECTORY
mkdir -p $REPORT_DIRECTORY
chmod -R 777 $REPORT_DIRECTORY
```
#!/bin/sh
OWASPDC_DIRECTORY=$HOME/OWASP-Dependency-Check
DATA_DIRECTORY="$OWASPDC_DIRECTORY/data"
REPORT_DIRECTORY="$OWASPDC_DIRECTORY/reports"
if [ ! -d "$DATA_DIRECTORY" ]; then
echo "Initially creating persistent directories"
mkdir -p "$DATA_DIRECTORY"
chmod -R 777 "$DATA_DIRECTORY"
mkdir -p "$REPORT_DIRECTORY"
chmod -R 777 "$REPORT_DIRECTORY"
fi
docker pull owasp/dependency-check # Make sure it is the actual version
# Make sure we are using the latest version
docker pull owasp/dependency-check
docker run --rm \
--volume $(pwd):/src \
--volume $DATA_DIRECTORY:/usr/share/dependency-check/data \
--volume $REPORT_DIRECTORY:/report \
--name dependency-check \
dc \
--suppression "/src/security/dependency-check-suppression.xml"\
--format "ALL" \
--project "My OWASP Dependency Check Project" \
--volume $(pwd):/src \
--volume "$DATA_DIRECTORY":/usr/share/dependency-check/data \
--volume "$REPORT_DIRECTORY":/report \
owasp/dependency-check \
--scan /src \
--format "ALL" \
--project "My OWASP Dependency Check Project"
# Use suppression like this: (/src == $pwd)
# --suppression "/src/security/dependency-check-suppression.xml"
```

View File

@@ -146,7 +146,7 @@ public class Check extends Update {
private boolean updateOnly = false;
/**
* The report format to be generated (HTML, XML, VULN, ALL). Default is
* The report format to be generated (HTML, XML, VULN, CSV, JSON, ALL). Default is
* HTML.
*/
private String reportFormat = "HTML";
@@ -1102,7 +1102,7 @@ public class Check extends Update {
}
/**
* An enumeration of supported report formats: "ALL", "HTML", "XML", "VULN",
* An enumeration of supported report formats: "ALL", "HTML", "XML", "CSV", "JSON", "VULN",
* etc..
*/
public static class ReportFormats extends EnumeratedAttribute {

View File

@@ -36,11 +36,11 @@ cveValidForHours | Sets the number of hours to wait before checking for new
failBuildOnCVSS | Specifies if the build should be failed if a CVSS score above a specified level is identified. The default is 11 which means since the CVSS scores are 0-10, by default the build will never fail. | 11
failOnError | Whether the build should fail if there is an error executing the dependency-check analysis | true
projectName | The name of the project being scanned. | Dependency-Check
reportFormat | The report format to be generated (HTML, XML, VULN, ALL). This configuration option has no affect if using this within the Site plugin unless the externalReport is set to true. | HTML
reportFormat | The report format to be generated (HTML, XML, CSV, JSON, VULN, ALL). This configuration option has no affect if using this within the Site plugin unless the externalReport is set to true. | HTML
reportOutputDirectory | The location to write the report(s). Note, this is not used if generating the report as part of a `mvn site` build | 'target'
suppressionFile | The file path to the XML suppression file \- used to suppress [false positives](../general/suppression.html) | &nbsp;
hintsFile | The file path to the XML hints file \- used to resolve [false negatives](../general/hints.html) | &nbsp;
proxyServer | The Proxy Server; see the [proxy configuration](../data/proxy.html) page for more information. | &nbsp;
hintsFile | The file path to the XML hints file \- used to resolve [false negatives](../general/hints.html) | &nbsp;
proxyServer | The Proxy Server; see the [proxy configuration](../data/proxy.html) page for more information. | &nbsp;
proxyPort | The Proxy Port. | &nbsp;
proxyUsername | Defines the proxy user name. | &nbsp;
proxyPassword | Defines the proxy password. | &nbsp;

View File

@@ -120,7 +120,7 @@ public final class CliParser {
Format.valueOf(format);
} catch (IllegalArgumentException ex) {
final String msg = String.format("An invalid 'format' of '%s' was specified. "
+ "Supported output formats are XML, HTML, VULN, or ALL", format);
+ "Supported output formats are HTML, XML, CSV, JSON, VULN, or ALL", format);
throw new ParseException(msg);
}
}
@@ -262,7 +262,7 @@ public final class CliParser {
.build();
final Option outputFormat = Option.builder(ARGUMENT.OUTPUT_FORMAT_SHORT).argName("format").hasArg().longOpt(ARGUMENT.OUTPUT_FORMAT)
.desc("The output format to write to (XML, HTML, VULN, ALL). The default is HTML.")
.desc("The output format to write to (XML, JSON, HTML, VULN, ALL). The default is HTML.")
.build();
final Option verboseLog = Option.builder(ARGUMENT.VERBOSE_LOG_SHORT).argName("file").hasArg().longOpt(ARGUMENT.VERBOSE_LOG)

View File

@@ -4,22 +4,22 @@ Command Line Arguments
The following table lists the command line arguments:
Short | Argument&nbsp;Name&nbsp;&nbsp; | Parameter | Description | Requirement
-------|-----------------------|-----------------|-------------|------------
| \-\-project | \<name\> | The name of the project being scanned. | Required
\-s | \-\-scan | \<path\> | The path to scan \- this option can be specified multiple times. It is also possible to specify Ant style paths (e.g. directory/**/*.jar). | Required
| \-\-exclude | \<pattern\> | The path patterns to exclude from the scan \- this option can be specified multiple times. This accepts Ant style path patterns (e.g. **/exclude/**). | Optional
| \-\-symLink | \<depth\> | The depth that symbolic links will be followed; the default is 0 meaning symbolic links will not be followed. | Optional
\-o | \-\-out | \<path\> | The folder to write reports to. This defaults to the current directory. If the format is not set to ALL one could specify a specific file name. | Optional
\-f | \-\-format | \<format\> | The output format to write to (XML, HTML, VULN, ALL). The default is HTML. | Required
| \-\-failOnCvss | \<score\> | If the score set between 0 and 10 the exit code from dependency-check will indicate if a vulnerability with a CVSS score equal to or higher was identified. | Optional
\-l | \-\-log | \<file\> | The file path to write verbose logging information. | Optional
\-n | \-\-noupdate | | Disables the automatic updating of the CPE data. | Optional
| \-\-suppression | \<file\> | The file path to the suppression XML file; used to suppress [false positives](../general/suppression.html). | Optional
\-h | \-\-help | | Print the help message. | Optional
| \-\-advancedHelp | | Print the advanced help message. | Optional
\-v | \-\-version | | Print the version information. | Optional
| \-\-cveValidForHours | \<hours\> | The number of hours to wait before checking for new updates from the NVD. The default is 4 hours. | Optional
| \-\-experimental | | Enable the [experimental analyzers](../analyzers/index.html). If not set the analyzers marked as experimental below will not be loaded or used. | Optional
-------|------------------------|-----------------|-------------|------------
| \-\-project | \<name\> | The name of the project being scanned. | Required
\-s | \-\-scan | \<path\> | The path to scan \- this option can be specified multiple times. It is also possible to specify Ant style paths (e.g. directory/**/*.jar). | Required
| \-\-exclude | \<pattern\> | The path patterns to exclude from the scan \- this option can be specified multiple times. This accepts Ant style path patterns (e.g. **/exclude/**). | Optional
| \-\-symLink | \<depth\> | The depth that symbolic links will be followed; the default is 0 meaning symbolic links will not be followed. | Optional
\-o | \-\-out | \<path\> | The folder to write reports to. This defaults to the current directory. If the format is not set to ALL one could specify a specific file name. | Optional
\-f | \-\-format | \<format\> | The output format to write to (XML, HTML, CSV, JSON, VULN, ALL). The default is HTML. | Required
| \-\-failOnCvss | \<score\> | If the score set between 0 and 10 the exit code from dependency-check will indicate if a vulnerability with a CVSS score equal to or higher was identified. | Optional
\-l | \-\-log | \<file\> | The file path to write verbose logging information. | Optional
\-n | \-\-noupdate | | Disables the automatic updating of the CPE data. | Optional
| \-\-suppression | \<file\> | The file path to the suppression XML file; used to suppress [false positives](../general/suppression.html). | Optional
\-h | \-\-help | | Print the help message. | Optional
| \-\-advancedHelp | | Print the advanced help message. | Optional
\-v | \-\-version | | Print the version information. | Optional
| \-\-cveValidForHours | \<hours\> | The number of hours to wait before checking for new updates from the NVD. The default is 4 hours. | Optional
| \-\-enableExperimental | | Enable the [experimental analyzers](../analyzers/index.html). If not set the analyzers marked as experimental below will not be loaded or used. | Optional
Advanced Options
================

View File

@@ -253,6 +253,10 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
<groupId>com.sun.mail</groupId>
<artifactId>mailapi</artifactId>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<!-- The following dependencies are only used during testing -->
<dependency>
<groupId>org.apache.maven.scm</groupId>
@@ -383,6 +387,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
<scope>test</scope>
<optional>true</optional>
</dependency>
</dependencies>
<profiles>
<profile>
@@ -571,13 +576,6 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
<scope>test</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.3.1</version>
<scope>test</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.google.gerrit</groupId>
<artifactId>gerrit-extension-api</artifactId>

View File

@@ -182,8 +182,8 @@ public class NvdCveUpdater implements CachedWebDataSource {
LOGGER.trace("Ignorable exception", ex);
}
}
if (lockFile != null) {
lockFile.delete();
if (lockFile != null && lockFile.isFile() && !lockFile.delete()) {
LOGGER.error("Lock file '{}' was unable to be deleted. Please manually delete this file.", lockFile.toString());
}
}
}

View File

@@ -0,0 +1,66 @@
/*
* This file is part of dependency-check-core.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (c) 2017 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.exception;
/**
* An exception used when a dependency could not be found.
*
* @author Jeremy Long
*/
public class DependencyNotFoundException extends Exception {
/**
* The serial version uid.
*/
private static final long serialVersionUID = 1L;
/**
* Creates a new DependencyNotFoundException.
*/
public DependencyNotFoundException() {
super();
}
/**
* Creates a new DependencyNotFoundException.
*
* @param msg a message for the exception.
*/
public DependencyNotFoundException(String msg) {
super(msg);
}
/**
* Creates a new DependencyNotFoundException.
*
* @param ex the cause of the exception.
*/
public DependencyNotFoundException(Throwable ex) {
super(ex);
}
/**
* Creates a new DependencyNotFoundException.
*
* @param msg a message for the exception.
* @param ex the cause of the exception.
*/
public DependencyNotFoundException(String msg, Throwable ex) {
super(msg, ex);
}
}

View File

@@ -19,13 +19,16 @@ package org.owasp.dependencycheck.reporting;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Set;
import org.apache.commons.lang3.StringEscapeUtils;
import org.owasp.dependencycheck.dependency.Identifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* An extremely simple wrapper around various escape utils to perform URL and HTML encoding within the reports. This class was
* created to simplify the velocity configuration and avoid using the "built-in" escape tool.
* An extremely simple wrapper around various escape utils to perform URL and
* HTML encoding within the reports. This class was created to simplify the
* velocity configuration and avoid using the "built-in" escape tool.
*
* @author Jeremy Long
*/
@@ -80,4 +83,84 @@ public class EscapeTool {
}
return StringEscapeUtils.escapeXml11(text);
}
/**
* JSON Encodes the provided text.
*
* @param text the text to encode
* @return the JSON encoded text
*/
public String json(String text) {
if (text == null || text.isEmpty()) {
return text;
}
return StringEscapeUtils.escapeJson(text);
}
/**
* Formats text for CSV format. This includes trimming whitespace, replace
* line breaks with spaces, and if necessary quotes the text and/or escapes
* contained quotes.
*
* @param text the text to escape and quote
* @return the escaped and quoted text
*/
public String csv(String text) {
if (text == null || text.isEmpty()) {
return text;
}
return StringEscapeUtils.escapeCsv(text.trim().replace("\n", " "));
}
/**
* Takes a set of Identifiers, filters them to none CPE, and formats them
* for display in a CSV.
*
* @param ids the set of identifiers
* @return the formated list of none CPE identifiers
*/
public String csvIdentifiers(Set<Identifier> ids) {
if (ids == null || ids.isEmpty()) {
return "";
}
boolean addComma = false;
StringBuilder sb = new StringBuilder();
for (Identifier id : ids) {
if (!"cpe".equals(id.getType())) {
if (addComma) {
sb.append(", ");
} else {
addComma = true;
}
sb.append(id.getValue());
}
}
return StringEscapeUtils.escapeCsv(sb.toString());
}
/**
* Takes a set of Identifiers, filters them to just CPEs, and formats them
* for display in a CSV.
*
* @param ids the set of identifiers
* @return the formated list of CPE identifiers
*/
public String csvCpe(Set<Identifier> ids) {
if (ids == null || ids.isEmpty()) {
return "";
}
boolean addComma = false;
StringBuilder sb = new StringBuilder();
for (Identifier id : ids) {
if ("cpe".equals(id.getType())) {
if (addComma) {
sb.append(", ");
} else {
addComma = true;
}
sb.append(id.getValue());
}
}
return StringEscapeUtils.escapeCsv(sb.toString());
}
}

View File

@@ -17,17 +17,16 @@
*/
package org.owasp.dependencycheck.reporting;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.*;
import java.util.List;
import com.google.gson.JsonSyntaxException;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import static com.google.gson.stream.JsonToken.*;
import com.google.gson.stream.JsonWriter;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.context.Context;
@@ -78,7 +77,15 @@ public class ReportGenerator {
/**
* Generate HTML Vulnerability report.
*/
VULN
VULN,
/**
* Generate JSON report.
*/
JSON,
/**
* Generate CSV report.
*/
CSV
}
/**
* The Velocity Engine.
@@ -129,24 +136,23 @@ public class ReportGenerator {
* Constructs a new ReportGenerator.
*
* @param applicationName the application name being analyzed
* @param applicationVersion the application version being analyzed
* @param artifactID the application version being analyzed
* @param applicationVersion the application version being analyzed
* @param groupID the group id of the project being analyzed
* @param artifactID the application id of the project being analyzed
* @param version the application version of the project being analyzed
* @param dependencies the list of dependencies
* @param analyzers the list of analyzers used
* @param properties the database properties (containing timestamps of the
* NVD CVE data)
*/
public ReportGenerator(String applicationName, String groupID, String artifactID, String version,
List<Dependency> dependencies, List<Analyzer> analyzers, DatabaseProperties properties) {
public ReportGenerator(String applicationName,String applicationVersion,String artifactID,String groupID, List<Dependency> dependencies, List<Analyzer> analyzers, DatabaseProperties properties) {
this(applicationName,dependencies,analyzers,properties);
context.put("applicationVersion",applicationVersion);
context.put("artifactID",artifactID);
context.put("groupID",groupID);
this(applicationName, dependencies, analyzers, properties);
context.put("applicationVersion", version);
context.put("artifactID", artifactID);
context.put("groupID", groupID);
}
/**
* Creates a new Velocity Engine.
*
@@ -186,6 +192,12 @@ public class ReportGenerator {
if (format == Format.VULN || format == Format.ALL) {
generateReport("VulnerabilityReport", outputStream);
}
if (format == Format.JSON || format == Format.ALL) {
generateReport("JsonReport", outputStream);
}
if (format == Format.CSV || format == Format.ALL) {
generateReport("CsvReport", outputStream);
}
}
/**
@@ -200,6 +212,13 @@ public class ReportGenerator {
if (format == Format.XML || format == Format.ALL) {
generateReport("XmlReport", outputDir + File.separator + "dependency-check-report.xml");
}
if (format == Format.JSON || format == Format.ALL) {
generateReport("JsonReport", outputDir + File.separator + "dependency-check-report.json");
pretifyJson(outputDir + File.separator + "dependency-check-report.json");
}
if (format == Format.CSV || format == Format.ALL) {
generateReport("CsvReport", outputDir + File.separator + "dependency-check-report.csv");
}
if (format == Format.HTML || format == Format.ALL) {
generateReport("HtmlReport", outputDir + File.separator + "dependency-check-report.html");
}
@@ -208,6 +227,91 @@ public class ReportGenerator {
}
}
/**
* Reformats the given JSON file.
*
* @param pathToJson the path to the JSON file to be reformatted
* @throws JsonSyntaxException thrown if the given JSON file is malformed
*/
private void pretifyJson(String pathToJson) throws JsonSyntaxException {
final String outputPath = pathToJson + ".pretty";
final File in = new File(pathToJson);
final File out = new File(outputPath);
try (JsonReader reader = new JsonReader(new InputStreamReader(new FileInputStream(in), StandardCharsets.UTF_8));
JsonWriter writer = new JsonWriter(new OutputStreamWriter(new FileOutputStream(out), StandardCharsets.UTF_8))) {
prettyPrint(reader, writer);
} catch (IOException ex) {
LOGGER.error("Unable to generate pretty report, caused by: ", ex.getMessage());
return;
}
if (out.isFile() && in.isFile() && in.delete()) {
try {
org.apache.commons.io.FileUtils.moveFile(out, in);
} catch (IOException ex) {
LOGGER.error("Unable to generate pretty report, caused by: ", ex.getMessage());
}
}
}
/**
* Streams from a json reader to a json writer and performs pretty printing.
*
* This function is copied from https://sites.google.com/site/gson/streaming
*
* @param reader json reader
* @param writer json writer
* @throws IOException thrown if the json is malformed
*/
private static void prettyPrint(JsonReader reader, JsonWriter writer) throws IOException {
writer.setIndent(" ");
while (true) {
final JsonToken token = reader.peek();
switch (token) {
case BEGIN_ARRAY:
reader.beginArray();
writer.beginArray();
break;
case END_ARRAY:
reader.endArray();
writer.endArray();
break;
case BEGIN_OBJECT:
reader.beginObject();
writer.beginObject();
break;
case END_OBJECT:
reader.endObject();
writer.endObject();
break;
case NAME:
final String name = reader.nextName();
writer.name(name);
break;
case STRING:
final String s = reader.nextString();
writer.value(s);
break;
case NUMBER:
final String n = reader.nextString();
writer.value(new BigDecimal(n));
break;
case BOOLEAN:
final boolean b = reader.nextBoolean();
writer.value(b);
break;
case NULL:
reader.nextNull();
writer.nullValue();
break;
case END_DOCUMENT:
return;
default:
LOGGER.debug("Unexpected JSON toekn {}", token.toString());
break;
}
}
}
/**
* Generates the Dependency Reports for the identified dependencies.
*
@@ -220,7 +324,7 @@ public class ReportGenerator {
public void generateReports(String outputDir, String outputFormat) throws ReportException {
final String format = outputFormat.toUpperCase();
final String pathToCheck = outputDir.toLowerCase();
if (format.matches("^(XML|HTML|VULN|ALL)$")) {
if (format.matches("^(XML|HTML|VULN|JSON|ALL)$")) {
if ("XML".equalsIgnoreCase(format)) {
if (pathToCheck.endsWith(".xml")) {
generateReport("XmlReport", outputDir);
@@ -242,6 +346,21 @@ public class ReportGenerator {
generateReports(outputDir, Format.VULN);
}
}
if ("JSON".equalsIgnoreCase(format)) {
if (pathToCheck.endsWith(".json")) {
generateReport("JsonReport", outputDir);
pretifyJson(outputDir);
} else {
generateReports(outputDir, Format.JSON);
}
}
if ("CSV".equalsIgnoreCase(format)) {
if (pathToCheck.endsWith(".csv")) {
generateReport("CsvReport", outputDir);
} else {
generateReports(outputDir, Format.JSON);
}
}
if ("ALL".equalsIgnoreCase(format)) {
generateReports(outputDir, Format.ALL);
}

View File

@@ -62,7 +62,7 @@ public class PomParser {
return parse(fis);
} catch (IOException ex) {
LOGGER.debug("", ex);
throw new PomParseException(ex);
throw new PomParseException(String.format("Unable to parse pom '%s'", file.toString()), ex);
}
}

View File

@@ -1,5 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<suppressions xmlns="https://jeremylong.github.io/DependencyCheck/dependency-suppression.1.1.xsd">
<suppress base="true">
<notes><![CDATA[
This suppresses false positives for EntityFramework.SqlServer.dll.
]]></notes>
<filePath regex="true">.*EntityFramework\.SqlServer*\.dll</filePath>
<cpe>cpe:/a:microsoft:server:6.0.0.0</cpe>
<cpe>cpe:/a:microsoft:sql_server:6.0</cpe>
</suppress>
<suppress base="true">
<notes><![CDATA[
This suppresses false positives identified on spring security.
@@ -561,4 +569,36 @@
<gav regex="true">^org\.springframework\.boot:spring-boot-starter-data-jpa:.*$</gav>
<cve>CVE-2016-6652</cve>
</suppress>
<suppress base="true">
<notes><![CDATA[
False positive per issue #699
]]></notes>
<gav regex="true">^com\.splunk:splunk:.*$</gav>
<cpe>cpe:/a:splunk:splunk</cpe>
</suppress>
<suppress base="true">
<notes><![CDATA[
False positive per issue #713
]]></notes>
<gav regex="true">^org\.openid4java:openid4java:.*$</gav>
<cpe>cpe:/a:openid:openid</cpe>
<cpe>cpe:/a:openid:openid4java</cpe>
</suppress>
<suppress base="true">
<notes><![CDATA[
False positive per issue #700
]]></notes>
<gav regex="true">^org\.springframework\.cloud:spring-cloud-netflix-core:.*$</gav>
<cpe>cpe:/a:pivotal:spring_framework</cpe>
<cpe>cpe:/a:pivotal_software:spring_framework</cpe>
</suppress>
<suppress base="true">
<notes><![CDATA[
False positive per issue #700
]]></notes>
<gav regex="true">^org\.springframework\.cloud:spring-cloud-.*$</gav>
<cpe>cpe:/a:pivotal:spring_framework</cpe>
<cpe>cpe:/a:pivotal_software:spring_framework</cpe>
<cpe>cpe:/a:context_project:context</cpe>
</suppress>
</suppressions>

View File

@@ -0,0 +1,27 @@
#**
This file is part of Dependency-Check.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Copyright (c) 2017 Jeremy Long. All Rights Reserved.
@author Jeremy Long <jeremy.long@owasp.org>
@version 1 *###
"Project","ScanDate","DependencyName","DependencyPath","Description","License","Md5","Sha1","Identifiers","CPE","CVE","CWE","Vulnerability","Severity","CVSSv2"
#macro(writeSev $score)#if($score<4.0)"Low"#elseif($score>=7.0)"High"#else"Medium"#end#end
#foreach($dependency in $dependencies)#if($dependency.getVulnerabilities().size()>0)
#foreach($vuln in $dependency.getVulnerabilities())
$enc.csv($applicationName),$enc.csv($scanDate),$enc.csv($dependency.DisplayFileName),#if($dependency.FilePath)$enc.csv($dependency.FilePath)#end,#if($dependency.description)$enc.csv($dependency.description)#end,#if($dependency.license)$enc.csv($dependency.license)#end,#if($dependency.Md5sum)$enc.csv($dependency.Md5sum)#end,#if($dependency.Sha1sum)$enc.csv($dependency.Sha1sum)#end,#if($dependency.identifiers)$enc.csvIdentifiers($dependency.identifiers)#end,#if($dependency.identifiers)$enc.csvCpe($dependency.identifiers)#end,#if($vuln.name)$enc.csv($vuln.name)#end,#if($dependency.cwe)$enc.csv($vuln.cwe)#end,#if($vuln.description)$enc.csv($vuln.description)#end,#writeSev($vuln.cvssScore),$vuln.cvssScore
#end
#end
#end

View File

@@ -632,7 +632,7 @@ Getting Help: <a href="https://groups.google.com/forum/#!forum/dependency-check"
#foreach($dependency in $dependencies)
#set($lnkcnt=$lnkcnt+1)
<tr class="#if($dependency.getVulnerabilities().size()==0)notvulnerable#else vulnerable#end">
<td data-sort-value="$enc.html($dependency.DisplayFileName)"><a href="#l${lnkcnt}_$enc.html($enc.url($dependency.Sha1sum))">$enc.html($dependency.DisplayFileName)</a></td>
<td data-sort-value="$enc.html($dependency.DisplayFileName.toUpperCase())"><a href="#l${lnkcnt}_$enc.html($enc.url($dependency.Sha1sum))">$enc.html($dependency.DisplayFileName)</a></td>
#set($mavenlink="")
#set($cpeIdCount=0)
#set($cpeIdConf="")
@@ -673,9 +673,9 @@ Getting Help: <a href="https://groups.google.com/forum/#!forum/dependency-check"
#if ($mavenlink=="")
<td data-sort-value="">
#else
<td data-sort-value="$enc.html($mavenlink.value)">#if( $mavenlink.url )
<td data-sort-value="$enc.html($mavenlink.value.toLowerCase())">#if( $mavenlink.url )
##yes, we are HTML Encoding the href. This is okay. We can't URL encode as we have to trust the analyzer here...
<a href="$enc.html($mavenlink.url)" target="_blank">$enc.html($mavenlink.value)</a>
<a href="$enc.html($mavenlink.url)" target="_blank">$enc.html($mavenlink.value)</a>&nbsp;<span title="verified from repo" style="color:green">&#x2713;</span>
#elseif ($mavenlink.value)
$enc.html($mavenlink.value)
#end
@@ -762,10 +762,10 @@ Getting Help: <a href="https://groups.google.com/forum/#!forum/dependency-check"
<li>SHA1:&nbsp;$enc.html($related.Sha1sum)</li>
<li>MD5:&nbsp;$enc.html($related.Md5sum)</li>
#foreach($id in $related.getIdentifiers())
#if ($id.type=="maven")
#if( $id.url )
#if( $id.url )
#if ($id.type=="maven")
##yes, we are HTML Encoding the href. this is okay. We can't URL encode as we have to trust the analyzer here...
<li>$enc.html($id.type):&nbsp;<a href="$enc.html($id.url)" target="_blank">$enc.html($id.value)</a>
<li>$enc.html($id.type):&nbsp;<a href="$enc.html($id.url)" target="_blank">$enc.html($id.value)</a>&nbsp;<span title="verified from repo" style="color:green">&#x2713;</span>
#else
<li>$enc.html($id.type):&nbsp;$enc.html($id.value)
#end
@@ -800,8 +800,12 @@ Getting Help: <a href="https://groups.google.com/forum/#!forum/dependency-check"
#end
#foreach($id in $dependency.getIdentifiers())
#if( $id.url )
#if($id.type=="maven")
##yes, we are HTML Encoding the href. this is okay. We can't URL encode as we have to trust the analyzer here...
<li><b>$enc.html($id.type):</b>&nbsp;<a href="$enc.html($id.url)" target="_blank">$enc.html($id.value)</a>&nbsp;<span title="verified from repo" style="color:green">&#x2713;</span>
#else
<li><b>$enc.html($id.type):</b>&nbsp;<a href="$enc.html($id.url)" target="_blank">$enc.html($id.value)</a>
#end
#else
<li><b>$enc.html($id.type):</b>&nbsp;$enc.html($id.value)
#end
@@ -949,8 +953,12 @@ Getting Help: <a href="https://groups.google.com/forum/#!forum/dependency-check"
<ul>
#foreach($id in $dependency.getSuppressedIdentifiers())
#if( $id.url )
#if($id.type=="maven")
##yes, we are HTML Encoding the href. this is okay. We can't URL encode as we have to trust the analyzer here...
<li><b>$enc.html($id.type):</b>&nbsp;<a href="$enc.html($id.url)" target="_blank">$enc.html($id.value)</a>&nbsp;<span title="verified from repo" style="color:green">&#x2713;</span>&nbsp;&nbsp;<span class="suppressedLabel" >suppressed</span>
#else
<li><b>$enc.html($id.type):</b>&nbsp;<a href="$enc.html($id.url)" target="_blank">$enc.html($id.value)</a>&nbsp;&nbsp;<span class="suppressedLabel" >suppressed</span>
#end
#else
<li><b>$enc.html($id.type):</b>&nbsp;$enc.html($id.value)&nbsp;&nbsp;<span class="suppressedLabel" >suppressed</span>
#end

View File

@@ -0,0 +1,198 @@
{
"reportSchema": "1.0",
"analysis": {
"scanInfo": {
"engineVersion": "$version",
"dataSource": [
#foreach($prop in $properties.getMetaData().entrySet())
#if($foreach.count > 1),#end{
"name": "$enc.json($prop.key)",
"timestamp": "$enc.json($prop.value)"
}
#end
]
},
"projectInfo": {
"name": "$enc.json($applicationName)",
#if($groupID)"groupID":"$enc.json($groupID)",#end
#if($artifactID)"artifactID":"$enc.json($artifactID)",#end
#if($version)"version":"$enc.json($version)",#end
"reportDate": "$scanDateXML",
"credits": "This report contains data retrieved from the National Vulnerability Database: http://nvd.nist.gov"
},
"dependencies": [
#foreach($dependency in $dependencies)#if($foreach.count > 1),#end{
"fileName": "$enc.json($dependency.DisplayFileName)",
"filePath": "$enc.json($dependency.FilePath)",
"md5": "$enc.json($dependency.Md5sum)",
"sha1": "$enc.json($dependency.Sha1sum)"
#if($dependency.description),"description": "$enc.json($dependency.description)"#end
#if($dependency.license),"license": "$enc.json($dependency.license)"#end
#if ($dependency.getRelatedDependencies().size()>0)
,"relatedDependencies": [
#foreach($related in $dependency.getRelatedDependencies()) #if($foreach.count > 1),#end {
"filePath": "$enc.json($related.FilePath)",
"sha1": "$enc.json($related.Sha1sum)",
"md5": "$enc.json($related.Md5sum)"#if($related.getIdentifiers()),#end
"identifiers": [
#foreach($id in $related.getIdentifiers())
#if ($id.type=="maven")
{
"type": "$enc.json($id.type)",
"name": "$id.value"
#if( $id.url ),"url": "$enc.json($id.url)"#end
#if ($id.notes),"notes": "$enc.json($id.notes)"#end
}
#end
#end
]
}
#end
]
#end
,"evidenceCollected": {
"vendorEvidence": [
#foreach($evidence in $dependency.getVendorEvidence())
#if($foreach.count > 1),#end{
"type": "vendor",
"confidence": "$enc.json($evidence.getConfidence().toString())",
"source": "$enc.json($evidence.getSource())",
"name": "$enc.json($evidence.getName())",
"value": "$enc.json($evidence.getValue().trim())"
}
#end
],
"productEvidence": [
#foreach($evidence in $dependency.getProductEvidence())
#if($foreach.count > 1),#end{
"type": "product",
"confidence": "$enc.json($evidence.getConfidence().toString())",
"source": "$enc.json($evidence.getSource())",
"name": "$enc.json($evidence.getName())",
"value": "$enc.json($evidence.getValue().trim())"
}
#end
],
"versionEvidence": [
#foreach($evidence in $dependency.getVersionEvidence())
#if($foreach.count > 1),#end{
"type": "version",
"confidence": "$enc.json($evidence.getConfidence().toString())",
"source": "$enc.json($evidence.getSource())",
"name": "$enc.json($evidence.getName())",
"value": "$enc.json($evidence.getValue().trim())"
}
#end
]
},
"identifiers": [
#foreach($id in $dependency.getIdentifiers())#if($foreach.count > 1),#end{
"name": "$id.value",
"type": "$enc.json($id.type)",
#if($id.confidence)"confidence": "$id.confidence",#end
#if($id.url)"url": "$enc.json($id.url)",#end
#if($id.description )"description": "$enc.json($id.description)",#end
#if ($id.notes)"notes": "$enc.json($id.notes)",#end
"suppressedIdentifiers": [
#foreach($id in $dependency.getSuppressedIdentifiers())
#if($foreach.count > 1),#end{
"type": "$enc.json($id.type)",
#if($id.confidence)"confidence": "$id.confidence",#end
"name": "$id.value",
#if($id.url)"url": "$enc.json($id.url),"#end
#if($id.description)"description": "$enc.json($id.description)",#end
#if ($id.notes)"notes": "$enc.json($id.notes)"#end
}
#end
]
}
#end
]
#if($dependency.getVulnerabilities().size()>0 || $dependency.getSuppressedVulnerabilities().size()>0)
,"vulnerabilities": [
#foreach($vuln in $dependency.getVulnerabilities())
#if($foreach.count > 1),#end {
"name": "$enc.json($vuln.name)",
"cvssScore": "$vuln.cvssScore",
"cvssAccessVector": "$enc.json($vuln.cvssAccessVector)",
"cvssAccessComplexity": "$enc.json($vuln.cvssAccessComplexity)",
"cvssAuthenticationr": "$enc.json($vuln.cvssAuthentication)",
"cvssConfidentialImpact": "$enc.json($vuln.cvssConfidentialityImpact)",
"cvssIntegrityImpact": "$enc.json($vuln.cvssIntegrityImpact)",
"cvssAvailabilityImpact": "$enc.json($vuln.cvssAvailabilityImpact)",
#if ($vuln.cvssScore<4.0)
"severity": "Low",
#elseif ($vuln.cvssScore>=7.0)
"severity": "High",
#else
"severity": "Medium",
#end
#if($vuln.cwe)"cwe": "$enc.json($vuln.cwe)",#end
"description": "$enc.json($vuln.description)",
#if ($vuln.notes)"notes": "$enc.json($vuln.notes)"#end
"references": [
#foreach($ref in $vuln.getReferences())
#if($foreach.count > 1),#end {
"source": "$enc.json($ref.source)",
"url": "$enc.json($ref.url)",
"name": "$enc.json($ref.name)"
}
#end
],
"vulnerableSoftware": [
#foreach($vs in $vuln.getVulnerableSoftware())
#if($foreach.count > 1),#end {
#if($vs.hasPreviousVersion()) "allPreviousVersion": "true",#end
"software": "$enc.json($vs.name)"
}
#end
]
}#end
]
#end
#if($dependency.getSuppressedVulnerabilities().size()>0 || $dependency.getSuppressedVulnerabilities().size()>0)
,"suppressedVulnerabilities": [
#foreach($vuln in $dependency.getSuppressedVulnerabilities())#if($foreach.count > 1),#end {
"name": "$enc.json($vuln.name)",
"cvssScore": "$vuln.cvssScore",
"cvssAccessVector": "$enc.json($vuln.cvssAccessVector)",
"cvssAccessComplexity": "$enc.json($vuln.cvssAccessComplexity)",
"cvssAuthenticationr": "$enc.json($vuln.cvssAuthentication)",
"cvssConfidentialImpact": "$enc.json($vuln.cvssConfidentialityImpact)",
"cvssIntegrityImpact": "$enc.json($vuln.cvssIntegrityImpact)",
"cvssAvailabilityImpact": "$enc.json($vuln.cvssAvailabilityImpact)",
#if ($vuln.cvssScore<4.0) "severity": "Low",
#elseif ($vuln.cvssScore>=7.0) "severity": "High",
#else "severity": "Medium",
#end
#if ($vuln.cwe)"cwe": "$enc.json($vuln.cwe)",#end
"description": "$enc.json($vuln.description)"
#if ($vuln.notes),"notes": "$enc.json($vuln.notes)"#end
,"references": [
#foreach($ref in $vuln.getReferences())
#if($foreach.count > 1),#end {
"source": "$enc.json($ref.source)",
"url": "$enc.json($ref.url)",
"name": "$enc.json($ref.name)"
}
#end
],
"vulnerableSoftware": [
#foreach($vs in $vuln.getVulnerableSoftware())
#if($foreach.count > 1),#end {
#if($vs.hasPreviousVersion()) "allPreviousVersion": "true",#end
"name": "$enc.json($vs.name)"
}
#end
]
}
#end
]
#end
}
#end
]
}
}

View File

@@ -0,0 +1,231 @@
/*
* This file is part of dependency-check-core.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (c) 2017 Jeremy Long. All Rights Reserved.
*/
package org.owasp.dependencycheck.reporting;
import java.util.HashSet;
import java.util.Set;
import org.junit.Test;
import static org.junit.Assert.*;
import org.owasp.dependencycheck.dependency.Identifier;
/**
*
* @author jerem
*/
public class EscapeToolTest {
/**
* Test of url method, of class EscapeTool.
*/
@Test
public void testUrl() {
String text = null;
EscapeTool instance = new EscapeTool();
String expResult = null;
String result = instance.url(text);
assertEquals(expResult, result);
text = "";
expResult = "";
result = instance.url(text);
assertEquals(expResult, result);
text = " ";
expResult = "+";
result = instance.url(text);
assertEquals(expResult, result);
}
/**
* Test of html method, of class EscapeTool.
*/
@Test
public void testHtml() {
EscapeTool instance = new EscapeTool();
String text = null;
String expResult = null;
String result = instance.html(text);
assertEquals(expResult, result);
text = "";
expResult = "";
result = instance.html(text);
assertEquals(expResult, result);
text = "<div>";
expResult = "&lt;div&gt;";
result = instance.html(text);
assertEquals(expResult, result);
}
/**
* Test of xml method, of class EscapeTool.
*/
@Test
public void testXml() {
EscapeTool instance = new EscapeTool();
String text = null;
String expResult = null;
String result = instance.xml(text);
assertEquals(expResult, result);
text = "";
expResult = "";
result = instance.xml(text);
assertEquals(expResult, result);
text = "<div>";
expResult = "&lt;div&gt;";
result = instance.xml(text);
assertEquals(expResult, result);
}
/**
* Test of json method, of class EscapeTool.
*/
@Test
public void testJson() {
String text = null;
EscapeTool instance = new EscapeTool();
String expResult = null;
String result = instance.json(text);
assertEquals(expResult, result);
text = "";
expResult = "";
result = instance.json(text);
assertEquals(expResult, result);
text = "test \"quote\"\"";
expResult = "test \\\"quote\\\"\\\"";
result = instance.json(text);
assertEquals(expResult, result);
}
/**
* Test of csv method, of class EscapeTool.
*/
@Test
public void testCsv() {
String text = null;
EscapeTool instance = new EscapeTool();
String expResult = null;
String result = instance.csv(text);
assertEquals(expResult, result);
text = "";
expResult = "";
result = instance.csv(text);
assertEquals(expResult, result);
text = "one, two";
expResult = "\"one, two\"";
result = instance.csv(text);
assertEquals(expResult, result);
}
/**
* Test of csvIdentifiers method, of class EscapeTool.
*/
@Test
public void testCsvIdentifiers() {
EscapeTool instance = new EscapeTool();
Set<Identifier> ids = null;
String expResult = "";
String result = instance.csvIdentifiers(ids);
assertEquals(expResult, result);
ids = new HashSet<>();
expResult = "";
result = instance.csvIdentifiers(ids);
assertEquals(expResult, result);
ids = new HashSet<>();
ids.add(new Identifier("cpe", "cpe:/a:somegroup:something:1.0", ""));
expResult = "";
result = instance.csvIdentifiers(ids);
assertEquals(expResult, result);
ids = new HashSet<>();
ids.add(new Identifier("gav", "somegroup:something:1.0", ""));
expResult = "somegroup:something:1.0";
result = instance.csvIdentifiers(ids);
assertEquals(expResult, result);
ids = new HashSet<>();
ids.add(new Identifier("cpe", "cpe:/a:somegroup:something:1.0", ""));
ids.add(new Identifier("gav", "somegroup:something:1.0", ""));
expResult = "somegroup:something:1.0";
result = instance.csvIdentifiers(ids);
assertEquals(expResult, result);
ids = new HashSet<>();
ids.add(new Identifier("cpe", "cpe:/a:somegroup:something:1.0", ""));
ids.add(new Identifier("gav", "somegroup:something:1.0", ""));
ids.add(new Identifier("gav", "somegroup2:something:1.2", ""));
expResult = "\"somegroup:something:1.0, somegroup2:something:1.2\"";
String expResult2 = "\"somegroup2:something:1.2, somegroup:something:1.0\"";
result = instance.csvIdentifiers(ids);
assertTrue(expResult.equals(result) || expResult2.equals(result));
}
/**
* Test of csvCpe method, of class EscapeTool.
*/
@Test
public void testCsvCpe() {
EscapeTool instance = new EscapeTool();
Set<Identifier> ids = null;
String expResult = "";
String result = instance.csvCpe(ids);
assertEquals(expResult, result);
ids = new HashSet<>();
expResult = "";
result = instance.csvCpe(ids);
assertEquals(expResult, result);
ids = new HashSet<>();
ids.add(new Identifier("gav", "somegroup:something:1.0", ""));
expResult = "";
result = instance.csvCpe(ids);
assertEquals(expResult, result);
ids = new HashSet<>();
ids.add(new Identifier("cpe", "cpe:/a:somegroup:something:1.0", ""));
expResult = "cpe:/a:somegroup:something:1.0";
result = instance.csvCpe(ids);
assertEquals(expResult, result);
ids = new HashSet<>();
ids.add(new Identifier("cpe", "cpe:/a:somegroup:something:1.0", ""));
ids.add(new Identifier("gav", "somegroup:something:1.0", ""));
expResult = "cpe:/a:somegroup:something:1.0";
result = instance.csvCpe(ids);
assertEquals(expResult, result);
ids = new HashSet<>();
ids.add(new Identifier("cpe", "cpe:/a:somegroup:something:1.0", ""));
ids.add(new Identifier("gav", "somegroup:something:1.0", ""));
ids.add(new Identifier("cpe", "cpe:/a:somegroup2:something:1.2", ""));
expResult = "\"cpe:/a:somegroup:something:1.0, cpe:/a:somegroup2:something:1.2\"";
String expResult2 = "\"cpe:/a:somegroup2:something:1.2, cpe:/a:somegroup:something:1.0\"";
result = instance.csvCpe(ids);
assertTrue(expResult.equals(result) || expResult2.equals(result));
}
}

View File

@@ -109,8 +109,8 @@ public class ReportGeneratorIT extends BaseDBTestCase {
}
/**
* Generates an XML report containing known vulnerabilities and realistic data and validates the generated XML document
* against the XSD.
* Generates an XML report containing known vulnerabilities and realistic
* data and validates the generated XML document against the XSD.
*
* @throws Exception
*/
@@ -118,42 +118,43 @@ public class ReportGeneratorIT extends BaseDBTestCase {
public void testGenerateXMLReport() {
try {
String templateName = "XmlReport";
File f = new File("target/test-reports");
if (!f.exists()) {
f.mkdir();
}
String writeTo = "target/test-reports/Report.xml";
File suppressionFile = BaseTest.getResourceAsFile(this, "incorrectSuppressions.xml");
Settings.setString(Settings.KEYS.SUPPRESSION_FILE, suppressionFile.getAbsolutePath());
//File struts = new File(this.getClass().getClassLoader().getResource("struts2-core-2.1.2.jar").getPath());
File struts = BaseTest.getResourceAsFile(this, "struts2-core-2.1.2.jar");
//File axis = new File(this.getClass().getClassLoader().getResource("axis2-adb-1.4.1.jar").getPath());
File axis = BaseTest.getResourceAsFile(this, "axis2-adb-1.4.1.jar");
//File jetty = new File(this.getClass().getClassLoader().getResource("org.mortbay.jetty.jar").getPath());
File jetty = BaseTest.getResourceAsFile(this, "org.mortbay.jetty.jar");
boolean autoUpdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE);
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, false);
Engine engine = new Engine();
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
engine.scan(struts);
engine.scan(axis);
engine.scan(jetty);
engine.analyzeDependencies();
CveDB cveDB = CveDB.getInstance();
DatabaseProperties dbProp = cveDB.getDatabaseProperties();
ReportGenerator generator = new ReportGenerator("Test Report","1.4.7","dependency-check-core","org.owasp", engine.getDependencies(), engine.getAnalyzers(), dbProp);
ReportGenerator generator = new ReportGenerator("Test Report", "org.owasp", "dependency-check-core", "1.4.7",
engine.getDependencies(), engine.getAnalyzers(), dbProp);
generator.generateReport(templateName, writeTo);
cveDB.close();
engine.cleanup();
InputStream xsdStream = ReportGenerator.class.getClassLoader().getResourceAsStream("schema/dependency-check.1.5.xsd");
StreamSource xsdSource = new StreamSource(xsdStream);
StreamSource xmlSource = new StreamSource(new File(writeTo));

View File

@@ -227,6 +227,13 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-invoker-plugin</artifactId>
<version>2.0.0</version>
<dependencies>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>2.4.11</version>
</dependency>
</dependencies>
<configuration>
<!--streamLogs>true</streamLogs-->
<!-- The parallel builds cannot be increased beyond 2 as 690 must run before others (can be run parralel to 618 though) -->

View File

@@ -0,0 +1,19 @@
#
# This file is part of dependency-check-maven.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Copyright (c) 2017 Jeremy Long. All Rights Reserved.
#
invoker.goals = install ${project.groupId}:${project.artifactId}:${project.version}:check -e -Dformat=JSON

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
This file is part of dependency-check-maven.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Copyright (c) 2017 Jeremy Long. All Rights Reserved.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.owasp.test</groupId>
<artifactId>test-system-scope</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<scope>system</scope>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
<version>1.8</version>
<systemPath>${java.home}/../lib/tools.jar</systemPath>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,30 @@
/*
* This file is part of dependency-check-maven.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (c) 2017 Jeremy Long. All Rights Reserved.
*/
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import java.nio.charset.Charset;
import groovy.json.JsonSlurper;
def slurper = new JsonSlurper()
def json = slurper.parse(new File(basedir, "target/dependency-check-report.json"), "UTF-8")
assert json instanceof Map
assert json.analysis.dependencies instanceof List
assert json.analysis.dependencies.size()==1
return true;

View File

@@ -0,0 +1,17 @@
/*
* This file is part of dependency-check-maven.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (c) 2017 Jeremy Long. All Rights Reserved.
*/

View File

@@ -0,0 +1,19 @@
#
# This file is part of dependency-check-maven.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Copyright (c) 2014 Jeremy Long. All Rights Reserved.
#
invoker.goals = install ${project.groupId}:${project.artifactId}:${project.version}:check -DskipSystemScope=true -Dformat=JSON

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
This file is part of dependency-check-maven.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Copyright (c) 2017 Jeremy Long. All Rights Reserved.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.owasp.test</groupId>
<artifactId>test-system-scope</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<scope>system</scope>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
<version>1.8</version>
<systemPath>${java.home}/../lib/tools.jar</systemPath>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,30 @@
/*
* This file is part of dependency-check-maven.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (c) 2017 Jeremy Long. All Rights Reserved.
*/
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import java.nio.charset.Charset;
import groovy.json.JsonSlurper;
def slurper = new JsonSlurper()
def json = slurper.parse(new File(basedir, "target/dependency-check-report.json"), "UTF-8")
assert json instanceof Map
assert json.analysis.dependencies instanceof List
assert json.analysis.dependencies.size()==0
return true;

View File

@@ -0,0 +1,17 @@
/*
* This file is part of dependency-check-maven.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (c) 2014 Jeremy Long. All Rights Reserved.
*/

View File

@@ -22,6 +22,19 @@ Copyright (c) 2017 Jeremy Long. All Rights Reserved.
<artifactId>test-dataformat-jackson</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<repositories>
<repository>
<id>redhat</id>
<name>redhat</name>
<url>https://maven.repository.redhat.com/ga/</url>
</repository>
<repository>
<id>spring</id>
<name>spring</name>
<url>http://repo.spring.io/plugins-release/</url>
</repository>
</repositories>
<dependencies>
<!-- False Positives from issue #642 -->
<dependency>
@@ -29,6 +42,37 @@ Copyright (c) 2017 Jeremy Long. All Rights Reserved.
<artifactId>spring-boot</artifactId>
<version>1.4.3.RELEASE</version>
</dependency>
<!-- end issue #642 -->
<!-- End Issue #642 -->
<!-- False Positives from issue #699 -->
<dependency>
<groupId>com.splunk</groupId>
<artifactId>splunk</artifactId>
<version>1.6.2.0</version>
</dependency>
<!-- End Issue #699 -->
<!-- False Positives from issue #700 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix-core</artifactId>
<version>1.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons</artifactId>
<version>1.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-context</artifactId>
<version>1.1.7.RELEASE</version>
</dependency>
<!-- End Issue #700 -->
<!-- False Positives from issue #713 -->
<dependency>
<groupId>org.openid4java</groupId>
<artifactId>openid4java</artifactId>
<version>0.9.7</version>
</dependency>
<!-- End Issue #713 -->
</dependencies>
</project>

View File

@@ -20,16 +20,6 @@ import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import java.nio.charset.Charset;
// Save NVD-CVE for next IT (if not already done)
File datasDwl = new File("target/local-repo/org/owasp/dependency-check-data/3.0", "dc.h2.db");
File datasSave = new File("target/nvd-cve-backup", "dc.h2.db");
if (datasDwl.exists() && !datasSave.exists()){
System.out.println("Save NVD-CVE into backup");
FileUtils.copyFile(datasDwl, datasSave);
}
// Check to see if jackson-dataformat-xml-2.4.5.jar was identified.
//TODO change this to xpath and check for CVE-2016-3720

View File

@@ -55,6 +55,7 @@ import org.owasp.dependencycheck.dependency.Confidence;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.Identifier;
import org.owasp.dependencycheck.dependency.Vulnerability;
import org.owasp.dependencycheck.exception.DependencyNotFoundException;
import org.owasp.dependencycheck.exception.ExceptionCollection;
import org.owasp.dependencycheck.exception.ReportException;
import org.owasp.dependencycheck.reporting.ReportGenerator;
@@ -117,7 +118,7 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma
* The Maven Session.
*/
@Parameter(defaultValue = "${session}", readonly = true, required = true)
protected MavenSession session;
private MavenSession session;
/**
* Remote repositories which will be searched for artifacts.
@@ -403,6 +404,13 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma
@SuppressWarnings("CanBeFinal")
@Parameter(property = "skipProvidedScope", defaultValue = "false", required = false)
private boolean skipProvidedScope = false;
/**
* Skip Analysis for Provided Scope Dependencies.
*/
@SuppressWarnings("CanBeFinal")
@Parameter(property = "skipSystemScope", defaultValue = "false", required = false)
private boolean skipSystemScope = false;
/**
* The data directory, hold DC SQL DB.
*/
@@ -627,24 +635,54 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma
* @return a collection of exceptions that may have occurred while resolving
* and scanning the dependencies
*/
private ExceptionCollection collectDependencies(Engine engine, MavenProject project, List<DependencyNode> nodes, ProjectBuildingRequest buildingRequest) {
private ExceptionCollection collectDependencies(Engine engine, MavenProject project,
List<DependencyNode> nodes, ProjectBuildingRequest buildingRequest) {
ExceptionCollection exCol = null;
for (DependencyNode dependencyNode : nodes) {
exCol = collectDependencies(engine, project, dependencyNode.getChildren(), buildingRequest);
if (excludeFromScan(dependencyNode.getArtifact().getScope())) {
continue;
}
exCol = collectDependencies(engine, project, dependencyNode.getChildren(), buildingRequest);
try {
final ArtifactCoordinate coordinate = TransferUtils.toArtifactCoordinate(dependencyNode.getArtifact());
final Artifact result = artifactResolver.resolveArtifact(buildingRequest, coordinate).getArtifact();
if (result.isResolved() && result.getFile() != null) {
final List<Dependency> deps = engine.scan(result.getFile().getAbsoluteFile(),
boolean isResolved = false;
File artifactFile = null;
String artifactId = null;
String groupId = null;
String version = null;
if (org.apache.maven.artifact.Artifact.SCOPE_SYSTEM.equals(dependencyNode.getArtifact().getScope())) {
for (org.apache.maven.model.Dependency d : project.getDependencies()) {
Artifact a = dependencyNode.getArtifact();
if (d.getSystemPath() != null && artifactsMatch(d, a)) {
artifactFile = new File(d.getSystemPath());
isResolved = artifactFile.isFile();
groupId = a.getGroupId();
artifactId = a.getArtifactId();
version = a.getVersion();
break;
}
}
if (!isResolved) {
getLog().error("Unable to resolve system scoped dependency: " + dependencyNode.toNodeString());
exCol.addException(new DependencyNotFoundException("Unable to resolve system scoped dependency: " + dependencyNode.toNodeString()));
}
} else {
final ArtifactCoordinate coordinate = TransferUtils.toArtifactCoordinate(dependencyNode.getArtifact());
final Artifact result = artifactResolver.resolveArtifact(buildingRequest, coordinate).getArtifact();
isResolved = result.isResolved();
artifactFile = result.getFile();
groupId = result.getGroupId();
artifactId = result.getArtifactId();
version = result.getVersion();
}
if (isResolved && artifactFile != null) {
final List<Dependency> deps = engine.scan(artifactFile.getAbsoluteFile(),
project.getName() + ":" + dependencyNode.getArtifact().getScope());
if (deps != null) {
if (deps.size() == 1) {
final Dependency d = deps.get(0);
if (d != null) {
final MavenArtifact ma = new MavenArtifact(result.getGroupId(), result.getArtifactId(), result.getVersion());
final MavenArtifact ma = new MavenArtifact(groupId, artifactId, version);
d.addAsEvidence("pom", ma, Confidence.HIGHEST);
if (getLog().isDebugEnabled()) {
getLog().debug(String.format("Adding project reference %s on dependency %s",
@@ -682,6 +720,33 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma
return exCol;
}
/**
* Determines if the groupId, artifactId, and version of the Maven
* dependency and artifact match.
*
* @param d the Maven dependency
* @param a the Maven artifact
* @return true if the groupId, artifactId, and version match
*/
private static boolean artifactsMatch(org.apache.maven.model.Dependency d, Artifact a) {
return (isEqualOrNull(a.getArtifactId(), d.getArtifactId()))
&& (isEqualOrNull(a.getGroupId(), d.getGroupId()))
&& (isEqualOrNull(a.getVersion(), d.getVersion()));
}
/**
* Compares two strings for equality; if both strings are null they are
* considered equal.
*
* @param left the first string to compare
* @param right the second string to compare
* @return true if the strings are equal or if they are both null; otherwise
* false.
*/
private static boolean isEqualOrNull(String left, String right) {
return (left != null && left.equals(right)) || (left == null && right == null);
}
/**
* @return Returns a new ProjectBuildingRequest populated from the current
* session and the current project remote repositories, used to resolve
@@ -756,6 +821,10 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma
return "dependency-check-report.xml#";
} else if ("VULN".equalsIgnoreCase(this.format)) {
return "dependency-check-vulnerability";
} else if ("JSON".equalsIgnoreCase(this.format)) {
return "dependency-check-report.json";
} else if ("CSV".equalsIgnoreCase(this.format)) {
return "dependency-check-report.csv";
} else {
getLog().warn("Unknown report format used during site generation.");
return "dependency-check-report";
@@ -962,6 +1031,9 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma
if (skipProvidedScope && org.apache.maven.artifact.Artifact.SCOPE_PROVIDED.equals(scope)) {
return true;
}
if (skipSystemScope && org.apache.maven.artifact.Artifact.SCOPE_SYSTEM.equals(scope)) {
return true;
}
return skipRuntimeScope && !org.apache.maven.artifact.Artifact.SCOPE_RUNTIME.equals(scope);
}
@@ -1015,7 +1087,8 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma
getLog().debug("Unable to retrieve DB Properties", ex);
}
}
final ReportGenerator r = new ReportGenerator(p.getName(),p.getVersion(),p.getArtifactId(),p.getGroupId(), engine.getDependencies(), engine.getAnalyzers(), prop);
final ReportGenerator r = new ReportGenerator(p.getName(), p.getGroupId(), p.getArtifactId(), p.getVersion(),
engine.getDependencies(), engine.getAnalyzers(), prop);
try {
r.generateReports(outputDir.getAbsolutePath(), format);
} catch (ReportException ex) {

View File

@@ -108,24 +108,23 @@ public class CheckMojo extends BaseDependencyCheckMojo {
}
exCol = ex;
}
if (exCol == null || !exCol.isFatal()) {
try {
writeReports(engine, getProject(), getCorrectOutputDirectory());
} catch (ReportException ex) {
if (this.isFailOnError()) {
if (exCol != null) {
exCol.addException(ex);
} else {
exCol = new ExceptionCollection("Unable to write the dependency-check report", ex);
}
}
if (exCol == null || !exCol.isFatal()) {
try {
writeReports(engine, getProject(), getCorrectOutputDirectory());
} catch (ReportException ex) {
if (this.isFailOnError()) {
if (exCol != null) {
exCol.addException(ex);
} else {
exCol = new ExceptionCollection("Unable to write the dependency-check report", ex);
}
}
//writeDataFile(getProject(), null, engine.getDependencies());
showSummary(getProject(), engine.getDependencies());
checkForFailure(engine.getDependencies());
if (exCol != null && this.isFailOnError()) {
throw new MojoExecutionException("One or more exceptions occurred during dependency-check analysis", exCol);
}
}
showSummary(getProject(), engine.getDependencies());
checkForFailure(engine.getDependencies());
if (exCol != null && this.isFailOnError()) {
throw new MojoExecutionException("One or more exceptions occurred during dependency-check analysis", exCol);
}
}
engine.cleanup();

View File

@@ -19,13 +19,14 @@ cveValidForHours | Sets the number of hours to wait before checking f
failBuildOnCVSS | Specifies if the build should be failed if a CVSS score above a specified level is identified. The default is 11 which means since the CVSS scores are 0-10, by default the build will never fail. | 11
failBuildOnAnyVulnerability | Specific that if any vulnerability is identified, the build will fail. | false
failOnError | Whether the build should fail if there is an error executing the dependency-check analysis. | true
format | The report format to be generated (HTML, XML, VULN, ALL). This configuration option has no affect if using this within the Site plugin unless the externalReport is set to true. | HTML
format | The report format to be generated (HTML, XML, CSV, JSON, VULN, ALL). This configuration option has no affect if using this within the Site plugin unless the externalReport is set to true. | HTML
name | The name of the report in the site. | dependency-check or dependency-check:aggregate
outputDirectory | The location to write the report(s). Note, this is not used if generating the report as part of a `mvn site` build. | 'target'
skip | Skips the dependency-check analysis. | false
skipTestScope | Skip analysis for artifacts with Test Scope. | true
skipProvidedScope | Skip analysis for artifacts with Provided Scope. | false
skipRuntimeScope | Skip analysis for artifacts with Runtime Scope. | false
skipSystemScope | Skip analysis for artifacts with System Scope. | false
skipTestScope | Skip analysis for artifacts with Test Scope. | true
suppressionFile | The file path to the XML suppression file \- used to suppress [false positives](../general/suppression.html). | &nbsp;
hintsFile | The file path to the XML hints file \- used to resolve [false negatives](../general/hints.html). | &nbsp;
enableExperimental | Enable the [experimental analyzers](../analyzers/index.html). If not enabled the experimental analyzers (see below) will not be loaded or used. | false

View File

@@ -644,6 +644,11 @@ Copyright (c) 2012 - Jeremy Long
<artifactId>annotations</artifactId>
<version>3.0.1u2</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>

View File

@@ -17,7 +17,7 @@ autoUpdate | Sets whether auto-updating of the NVD CVE/CPE data is ena
cveValidForHours | Sets the number of hours to wait before checking for new updates from the NVD. | 4
failOnError | Fails the build if an error occurs during the dependency-check analysis. | true
failBuildOnCVSS | Specifies if the build should be failed if a CVSS score above a specified level is identified. The default is 11; since the CVSS scores are 0-10, by default the build will never fail. | 11
format | The report format to be generated (HTML, XML, VULN, ALL). | HTML
format | The report format to be generated (HTML, XML, CSV, JSON, VULN, ALL). | HTML
outputDirectory | The location to write the report(s). This directory will be located in the build directory. | build/reports
skipTestGroups | When set to true (the default) all dependency groups that being with 'test' will be skipped. | true
suppressionFile | The file path to the XML suppression file \- used to suppress [false positives](../general/suppression.html) | &nbsp;