mirror of
https://github.com/ysoftdevs/DependencyCheck.git
synced 2026-01-15 16:23:37 +01:00
Compare commits
11 Commits
stevesprin
...
reportGene
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3e4d012a69 | ||
|
|
dccbd659ed | ||
|
|
1b84095c0e | ||
|
|
c96ef88222 | ||
|
|
0540474e0c | ||
|
|
2dbfba9ac5 | ||
|
|
8eff628303 | ||
|
|
519167bf0f | ||
|
|
e8e06d12c7 | ||
|
|
006224b52c | ||
|
|
6007be1b5f |
@@ -29,8 +29,8 @@ $ ./bin/dependency-check.sh --project Testing --out . --scan [path to jar files
|
|||||||
```
|
```
|
||||||
On Windows
|
On Windows
|
||||||
```
|
```
|
||||||
> bin/dependency-check.bat -h
|
> .\bin\dependency-check.bat -h
|
||||||
> bin/dependency-check.bat --project Testing --out . --scan [path to jar files to be scanned]
|
> .\bin\dependency-check.bat --project Testing --out . --scan [path to jar files to be scanned]
|
||||||
```
|
```
|
||||||
On Mac with [Homebrew](http://brew.sh)
|
On Mac with [Homebrew](http://brew.sh)
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -940,16 +940,7 @@ public class Check extends Update {
|
|||||||
throw new BuildException(ex);
|
throw new BuildException(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DatabaseProperties prop = null;
|
engine.writeReports(getProjectName(),new File(reportOutputDirectory), reportFormat);
|
||||||
try (CveDB cve = CveDB.getInstance()) {
|
|
||||||
prop = cve.getDatabaseProperties();
|
|
||||||
} catch (DatabaseException ex) {
|
|
||||||
//TODO shouldn't this be a fatal exception
|
|
||||||
log("Unable to retrieve DB Properties", ex, Project.MSG_DEBUG);
|
|
||||||
}
|
|
||||||
|
|
||||||
final ReportGenerator reporter = new ReportGenerator(getProjectName(), engine.getDependencies(), engine.getAnalyzers(), prop);
|
|
||||||
reporter.generateReports(reportOutputDirectory, reportFormat);
|
|
||||||
|
|
||||||
if (this.failBuildOnCVSS <= 10) {
|
if (this.failBuildOnCVSS <= 10) {
|
||||||
checkForFailure(engine.getDependencies());
|
checkForFailure(engine.getDependencies());
|
||||||
|
|||||||
@@ -281,18 +281,9 @@ public class App {
|
|||||||
}
|
}
|
||||||
exCol = ex;
|
exCol = ex;
|
||||||
}
|
}
|
||||||
final List<Dependency> dependencies = engine.getDependencies();
|
|
||||||
DatabaseProperties prop = null;
|
|
||||||
try (CveDB cve = CveDB.getInstance()) {
|
|
||||||
prop = cve.getDatabaseProperties();
|
|
||||||
} catch (DatabaseException ex) {
|
|
||||||
//TODO shouldn't this be a fatal exception
|
|
||||||
LOGGER.debug("Unable to retrieve DB Properties", ex);
|
|
||||||
}
|
|
||||||
final ReportGenerator report = new ReportGenerator(applicationName, dependencies, engine.getAnalyzers(), prop);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
report.generateReports(reportDirectory, outputFormat);
|
engine.writeReports(applicationName, new File(reportDirectory), outputFormat);
|
||||||
} catch (ReportException ex) {
|
} catch (ReportException ex) {
|
||||||
if (exCol != null) {
|
if (exCol != null) {
|
||||||
exCol.addException(ex);
|
exCol.addException(ex);
|
||||||
@@ -306,7 +297,7 @@ public class App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Set the exit code based on whether we found a high enough vulnerability
|
//Set the exit code based on whether we found a high enough vulnerability
|
||||||
for (Dependency dep : dependencies) {
|
for (Dependency dep : engine.getDependencies()) {
|
||||||
if (!dep.getVulnerabilities().isEmpty()) {
|
if (!dep.getVulnerabilities().isEmpty()) {
|
||||||
for (Vulnerability vuln : dep.getVulnerabilities()) {
|
for (Vulnerability vuln : dep.getVulnerabilities()) {
|
||||||
LOGGER.debug("VULNERABILITY FOUND " + dep.getDisplayFileName());
|
LOGGER.debug("VULNERABILITY FOUND " + dep.getDisplayFileName());
|
||||||
@@ -316,7 +307,6 @@ public class App {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return retCode;
|
return retCode;
|
||||||
} finally {
|
} finally {
|
||||||
if (engine != null) {
|
if (engine != null) {
|
||||||
|
|||||||
@@ -54,6 +54,9 @@ import java.util.concurrent.ExecutorService;
|
|||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
|
||||||
|
import org.owasp.dependencycheck.exception.ReportException;
|
||||||
|
import org.owasp.dependencycheck.reporting.ReportGenerator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scans files, directories, etc. for Dependencies. Analyzers are loaded and
|
* Scans files, directories, etc. for Dependencies. Analyzers are loaded and
|
||||||
@@ -796,4 +799,42 @@ public class Engine implements FileFilter {
|
|||||||
exceptions.add(throwable);
|
exceptions.add(throwable);
|
||||||
throw new ExceptionCollection(message, exceptions, true);
|
throw new ExceptionCollection(message, exceptions, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes the report to the given output directory.
|
||||||
|
*
|
||||||
|
* @param applicationName the name of the application/project
|
||||||
|
* @param groupId the Maven groupId
|
||||||
|
* @param artifactId the Maven artifactId
|
||||||
|
* @param version the Maven version
|
||||||
|
* @param outputDir the path to the output directory (can include the full
|
||||||
|
* file name if the format is not ALL)
|
||||||
|
* @param format the report format (ALL, HTML, CSV, JSON, etc.)
|
||||||
|
* @throws ReportException thrown if there is an error generating the report
|
||||||
|
*/
|
||||||
|
public void writeReports(String applicationName, String groupId, String artifactId,
|
||||||
|
String version, File outputDir, String format) throws ReportException {
|
||||||
|
|
||||||
|
DatabaseProperties prop = database.getDatabaseProperties();
|
||||||
|
final ReportGenerator r = new ReportGenerator(applicationName, groupId, artifactId, version, dependencies, getAnalyzers(), prop);
|
||||||
|
try {
|
||||||
|
r.write(outputDir.getAbsolutePath(), format);
|
||||||
|
} catch (ReportException ex) {
|
||||||
|
final String msg = String.format("Error generating the report for %s", applicationName);
|
||||||
|
throw new ReportException(msg, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes the report to the given output directory.
|
||||||
|
*
|
||||||
|
* @param applicationName the name of the application/project
|
||||||
|
* @param outputDir the path to the output directory (can include the full
|
||||||
|
* file name if the format is not ALL)
|
||||||
|
* @param format the report format (ALL, HTML, CSV, JSON, etc.)
|
||||||
|
* @throws ReportException thrown if there is an error generating the report
|
||||||
|
*/
|
||||||
|
public void writeReports(String applicationName, File outputDir, String format) throws ReportException {
|
||||||
|
writeReports(applicationName, null, null, null, outputDir, format);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -840,21 +840,15 @@ public class DependencyCheckScanAgent {
|
|||||||
*
|
*
|
||||||
* @param engine a dependency-check engine
|
* @param engine a dependency-check engine
|
||||||
* @param outDirectory the directory to write the reports to
|
* @param outDirectory the directory to write the reports to
|
||||||
|
* @throw ScanAgentException thrown if there is an error generating the
|
||||||
|
* report
|
||||||
*/
|
*/
|
||||||
private void generateExternalReports(Engine engine, File outDirectory) {
|
private void generateExternalReports(Engine engine, File outDirectory) throws ScanAgentException {
|
||||||
DatabaseProperties prop = null;
|
|
||||||
try (CveDB cve = CveDB.getInstance()) {
|
|
||||||
prop = cve.getDatabaseProperties();
|
|
||||||
} catch (DatabaseException ex) {
|
|
||||||
//TODO shouldn't this be a fatal exception
|
|
||||||
LOGGER.debug("Unable to retrieve DB Properties", ex);
|
|
||||||
}
|
|
||||||
final ReportGenerator r = new ReportGenerator(this.applicationName, engine.getDependencies(), engine.getAnalyzers(), prop);
|
|
||||||
try {
|
try {
|
||||||
r.generateReports(outDirectory.getCanonicalPath(), this.reportFormat.name());
|
engine.writeReports(applicationName, outDirectory, this.reportFormat.name());
|
||||||
} catch (IOException | ReportException ex) {
|
} catch (ReportException ex) {
|
||||||
LOGGER.error("Unexpected exception occurred during analysis; please see the verbose error log for more details.");
|
LOGGER.debug("Unexpected exception occurred during analysis; please see the verbose error log for more details.", ex);
|
||||||
LOGGER.debug("", ex);
|
throw new ScanAgentException("Error generating the report", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,334 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 Steve Springett. All Rights Reserved.
|
|
||||||
*/
|
|
||||||
package org.owasp.dependencycheck.analyzer;
|
|
||||||
|
|
||||||
import org.apache.commons.io.FileUtils;
|
|
||||||
import org.owasp.dependencycheck.Engine;
|
|
||||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
|
||||||
import org.owasp.dependencycheck.data.nsp.Advisory;
|
|
||||||
import org.owasp.dependencycheck.data.nsp.NspSearch;
|
|
||||||
import org.owasp.dependencycheck.data.nsp.SanitizePackage;
|
|
||||||
import org.owasp.dependencycheck.dependency.Confidence;
|
|
||||||
import org.owasp.dependencycheck.dependency.Dependency;
|
|
||||||
import org.owasp.dependencycheck.dependency.EvidenceCollection;
|
|
||||||
import org.owasp.dependencycheck.dependency.Identifier;
|
|
||||||
import org.owasp.dependencycheck.dependency.Vulnerability;
|
|
||||||
import org.owasp.dependencycheck.dependency.VulnerableSoftware;
|
|
||||||
import org.owasp.dependencycheck.utils.FileFilterBuilder;
|
|
||||||
import org.owasp.dependencycheck.utils.Settings;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileFilter;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import javax.json.Json;
|
|
||||||
import javax.json.JsonException;
|
|
||||||
import javax.json.JsonObject;
|
|
||||||
import javax.json.JsonObjectBuilder;
|
|
||||||
import javax.json.JsonReader;
|
|
||||||
import javax.json.JsonString;
|
|
||||||
import javax.json.JsonValue;
|
|
||||||
import org.owasp.dependencycheck.exception.InitializationException;
|
|
||||||
import org.owasp.dependencycheck.utils.URLConnectionFailureException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to analyze Node Package Manager (npm) package.json files via Node
|
|
||||||
* Security Platform (nsp).
|
|
||||||
*
|
|
||||||
* @author Steve Springett
|
|
||||||
*/
|
|
||||||
public class NspAnalyzer extends AbstractFileTypeAnalyzer {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The logger.
|
|
||||||
*/
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(NspAnalyzer.class);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The default URL to the NSP check API.
|
|
||||||
*/
|
|
||||||
public static final String DEFAULT_URL = "https://api.nodesecurity.io/check";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The file name to scan.
|
|
||||||
*/
|
|
||||||
private static final String PACKAGE_JSON = "package.json";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Filter that detects files named "package.json".
|
|
||||||
*/
|
|
||||||
private static final FileFilter PACKAGE_JSON_FILTER = FileFilterBuilder.newInstance()
|
|
||||||
.addFilenames(PACKAGE_JSON).build();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The NSP Searcher.
|
|
||||||
*/
|
|
||||||
private NspSearch searcher;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the FileFilter
|
|
||||||
*
|
|
||||||
* @return the FileFilter
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected FileFilter getFileFilter() {
|
|
||||||
return PACKAGE_JSON_FILTER;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the analyzer once before any analysis is performed.
|
|
||||||
*
|
|
||||||
* @throws InitializationException if there's an error during initialization
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void initializeFileTypeAnalyzer() throws InitializationException {
|
|
||||||
LOGGER.debug("Initializing " + getName());
|
|
||||||
final String searchUrl = Settings.getString(Settings.KEYS.ANALYZER_NSP_URL, DEFAULT_URL);
|
|
||||||
try {
|
|
||||||
searcher = new NspSearch(new URL(searchUrl));
|
|
||||||
} catch (MalformedURLException ex) {
|
|
||||||
setEnabled(false);
|
|
||||||
throw new InitializationException("The configured URL to Node Security Platform is malformed: " + searchUrl, ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the name of the analyzer.
|
|
||||||
*
|
|
||||||
* @return the name of the analyzer.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String getName() {
|
|
||||||
return "Node Security Platform Analyzer";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the phase that the analyzer is intended to run in.
|
|
||||||
*
|
|
||||||
* @return the phase that the analyzer is intended to run in.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public AnalysisPhase getAnalysisPhase() {
|
|
||||||
return AnalysisPhase.FINDING_ANALYSIS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the key used in the properties file to reference the analyzer's
|
|
||||||
* enabled property.x
|
|
||||||
*
|
|
||||||
* @return the analyzer's enabled property setting key
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected String getAnalyzerEnabledSettingKey() {
|
|
||||||
return Settings.KEYS.ANALYZER_NSP_PACKAGE_ENABLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
|
|
||||||
final File file = dependency.getActualFile();
|
|
||||||
try (JsonReader jsonReader = Json.createReader(FileUtils.openInputStream(file))) {
|
|
||||||
|
|
||||||
// Retrieves the contents of package.json from the Dependency
|
|
||||||
final JsonObject packageJson = jsonReader.readObject();
|
|
||||||
|
|
||||||
// Create a sanitized version of the package.json
|
|
||||||
final JsonObject sanitizedJson = SanitizePackage.sanitize(packageJson);
|
|
||||||
|
|
||||||
// Create a new 'package' object that acts as a container for the sanitized package.json
|
|
||||||
final JsonObjectBuilder builder = Json.createObjectBuilder();
|
|
||||||
final JsonObject nspPayload = builder.add("package", sanitizedJson).build();
|
|
||||||
|
|
||||||
// Submits the package payload to the nsp check service
|
|
||||||
final List<Advisory> advisories = searcher.submitPackage(nspPayload);
|
|
||||||
|
|
||||||
for (Advisory advisory : advisories) {
|
|
||||||
/*
|
|
||||||
* Create a new vulnerability out of the advisory returned by nsp.
|
|
||||||
*/
|
|
||||||
final Vulnerability vuln = new Vulnerability();
|
|
||||||
vuln.setCvssScore(advisory.getCvssScore());
|
|
||||||
vuln.setDescription(advisory.getOverview());
|
|
||||||
vuln.setName(String.valueOf(advisory.getId()));
|
|
||||||
vuln.setSource(Vulnerability.Source.NSP);
|
|
||||||
vuln.addReference(
|
|
||||||
"NSP",
|
|
||||||
"Advisory " + advisory.getId() + ": " + advisory.getTitle(),
|
|
||||||
advisory.getAdvisory()
|
|
||||||
);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Create a single vulnerable software object - these do not use CPEs unlike the NVD.
|
|
||||||
*/
|
|
||||||
final VulnerableSoftware vs = new VulnerableSoftware();
|
|
||||||
//vs.setVersion(advisory.getVulnerableVersions());
|
|
||||||
vs.setUpdate(advisory.getPatchedVersions());
|
|
||||||
vs.setName(advisory.getModule() + ":" + advisory.getVulnerableVersions());
|
|
||||||
vuln.setVulnerableSoftware(new HashSet<>(Arrays.asList(vs)));
|
|
||||||
|
|
||||||
// Add the vulnerability to package.json
|
|
||||||
dependency.getVulnerabilities().add(vuln);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Adds evidence about the node package itself, not any of the modules.
|
|
||||||
*/
|
|
||||||
final EvidenceCollection productEvidence = dependency.getProductEvidence();
|
|
||||||
final EvidenceCollection vendorEvidence = dependency.getVendorEvidence();
|
|
||||||
if (packageJson.containsKey("name")) {
|
|
||||||
final Object value = packageJson.get("name");
|
|
||||||
if (value instanceof JsonString) {
|
|
||||||
final String valueString = ((JsonString) value).getString();
|
|
||||||
productEvidence.addEvidence(PACKAGE_JSON, "name", valueString, Confidence.HIGHEST);
|
|
||||||
vendorEvidence.addEvidence(PACKAGE_JSON, "name_project", String.format("%s_project", valueString), Confidence.LOW);
|
|
||||||
} else {
|
|
||||||
LOGGER.warn("JSON value not string as expected: {}", value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Processes the dependencies objects in package.json and adds all the modules as related dependencies
|
|
||||||
*/
|
|
||||||
if (packageJson.containsKey("dependencies")) {
|
|
||||||
final JsonObject dependencies = packageJson.getJsonObject("dependencies");
|
|
||||||
processPackage(dependency, dependencies, "dependencies");
|
|
||||||
}
|
|
||||||
if (packageJson.containsKey("devDependencies")) {
|
|
||||||
final JsonObject dependencies = packageJson.getJsonObject("devDependencies");
|
|
||||||
processPackage(dependency, dependencies, "devDependencies");
|
|
||||||
}
|
|
||||||
if (packageJson.containsKey("optionalDependencies")) {
|
|
||||||
final JsonObject dependencies = packageJson.getJsonObject("optionalDependencies");
|
|
||||||
processPackage(dependency, dependencies, "optionalDependencies");
|
|
||||||
}
|
|
||||||
if (packageJson.containsKey("peerDependencies")) {
|
|
||||||
final JsonObject dependencies = packageJson.getJsonObject("peerDependencies");
|
|
||||||
processPackage(dependency, dependencies, "peerDependencies");
|
|
||||||
}
|
|
||||||
if (packageJson.containsKey("bundleDependencies")) {
|
|
||||||
final JsonObject dependencies = packageJson.getJsonObject("bundleDependencies");
|
|
||||||
processPackage(dependency, dependencies, "bundleDependencies");
|
|
||||||
}
|
|
||||||
if (packageJson.containsKey("bundledDependencies")) {
|
|
||||||
final JsonObject dependencies = packageJson.getJsonObject("bundledDependencies");
|
|
||||||
processPackage(dependency, dependencies, "bundledDependencies");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Adds the license if defined in package.json
|
|
||||||
*/
|
|
||||||
if (packageJson.containsKey("license")) {
|
|
||||||
dependency.setLicense(packageJson.getString("license"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Adds general evidence to about the package.
|
|
||||||
*/
|
|
||||||
addToEvidence(packageJson, productEvidence, "description");
|
|
||||||
addToEvidence(packageJson, vendorEvidence, "author");
|
|
||||||
addToEvidence(packageJson, dependency.getVersionEvidence(), "version");
|
|
||||||
dependency.setDisplayFileName(String.format("%s/%s", file.getParentFile().getName(), file.getName()));
|
|
||||||
} catch (URLConnectionFailureException e) {
|
|
||||||
this.setEnabled(false);
|
|
||||||
throw new AnalysisException(e.getMessage(), e);
|
|
||||||
} catch (IOException e) {
|
|
||||||
LOGGER.debug("Error reading dependency or connecting to Node Security Platform - check API", e);
|
|
||||||
this.setEnabled(false);
|
|
||||||
throw new AnalysisException(e.getMessage(), e);
|
|
||||||
} catch (JsonException e) {
|
|
||||||
throw new AnalysisException(String.format("Failed to parse %s file.", file.getPath()), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Processes a part of package.json (as defined by JsobObject) and update
|
|
||||||
* the specified dependency with relevant info.
|
|
||||||
*
|
|
||||||
* @param dependency the Dependency to update
|
|
||||||
* @param jsonObject the jsonObject to parse
|
|
||||||
*/
|
|
||||||
private void processPackage(Dependency dependency, JsonObject jsonObject, String depType) {
|
|
||||||
for (int i = 0; i < jsonObject.size(); i++) {
|
|
||||||
for (Map.Entry<String, JsonValue> entry : jsonObject.entrySet()) {
|
|
||||||
/*
|
|
||||||
* Create identifies that include the npm module and version. Since these are defined,
|
|
||||||
* assign the highest confidence.
|
|
||||||
*/
|
|
||||||
final Identifier moduleName = new Identifier("npm", "Module", null, entry.getKey());
|
|
||||||
moduleName.setConfidence(Confidence.HIGHEST);
|
|
||||||
String version = "";
|
|
||||||
if (entry.getValue() != null && entry.getValue().getValueType() == JsonValue.ValueType.STRING) {
|
|
||||||
version = ((JsonString) entry.getValue()).getString();
|
|
||||||
}
|
|
||||||
final Identifier moduleVersion = new Identifier("npm", "Version", null, version);
|
|
||||||
moduleVersion.setConfidence(Confidence.HIGHEST);
|
|
||||||
|
|
||||||
final Identifier moduleDepType = new Identifier("npm", "Scope", null, depType);
|
|
||||||
moduleVersion.setConfidence(Confidence.HIGHEST);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Create related dependencies for each module defined in package.json. The path to the related
|
|
||||||
* dependency will not actually exist but needs to be unique (due to the use of Set in Dependency).
|
|
||||||
* The use of related dependencies is a way to specify the actual software BOM in package.json.
|
|
||||||
*/
|
|
||||||
Dependency nodeModule = new Dependency(new File(dependency.getActualFile() + "#" + entry.getKey()), true);
|
|
||||||
nodeModule.setDisplayFileName(entry.getKey());
|
|
||||||
nodeModule.setIdentifiers(new HashSet<>(Arrays.asList(moduleName, moduleVersion, moduleDepType)));
|
|
||||||
dependency.addRelatedDependency(nodeModule);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds information to an evidence collection from the node json
|
|
||||||
* configuration.
|
|
||||||
*
|
|
||||||
* @param json information from node.js
|
|
||||||
* @param collection a set of evidence about a dependency
|
|
||||||
* @param key the key to obtain the data from the json information
|
|
||||||
*/
|
|
||||||
private void addToEvidence(JsonObject json, EvidenceCollection collection, String key) {
|
|
||||||
if (json.containsKey(key)) {
|
|
||||||
final JsonValue value = json.get(key);
|
|
||||||
if (value instanceof JsonString) {
|
|
||||||
collection.addEvidence(PACKAGE_JSON, key, ((JsonString) value).getString(), Confidence.HIGHEST);
|
|
||||||
} else if (value instanceof JsonObject) {
|
|
||||||
final JsonObject jsonObject = (JsonObject) value;
|
|
||||||
for (final Map.Entry<String, JsonValue> entry : jsonObject.entrySet()) {
|
|
||||||
final String property = entry.getKey();
|
|
||||||
final JsonValue subValue = entry.getValue();
|
|
||||||
if (subValue instanceof JsonString) {
|
|
||||||
collection.addEvidence(PACKAGE_JSON,
|
|
||||||
String.format("%s.%s", key, property),
|
|
||||||
((JsonString) subValue).getString(),
|
|
||||||
Confidence.HIGHEST);
|
|
||||||
} else {
|
|
||||||
LOGGER.warn("JSON sub-value not string as expected: {}", subValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LOGGER.warn("JSON value not string or JSON object as expected: {}", value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,344 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 Steve Springett. All Rights Reserved.
|
|
||||||
*/
|
|
||||||
package org.owasp.dependencycheck.data.nsp;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The response from NSP check API will respond with 0 or more advisories.
|
|
||||||
* This class defines the Advisory objects returned.
|
|
||||||
*
|
|
||||||
* @author Steve Springett
|
|
||||||
*/
|
|
||||||
public class Advisory {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The unique ID of the advisory as issued by Node Security Platform.
|
|
||||||
*/
|
|
||||||
private int id;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The timestamp of the last update to the advisory.
|
|
||||||
*/
|
|
||||||
private String updatedAt;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The timestamp of which the advisory was created.
|
|
||||||
*/
|
|
||||||
private String createdAt;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The timestamp of when the advisory was published.
|
|
||||||
*/
|
|
||||||
private String publishDate;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A detailed description of the advisory.
|
|
||||||
*/
|
|
||||||
private String overview;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Recommendations for mitigation. Typically involves updating to a newer release.
|
|
||||||
*/
|
|
||||||
private String recommendation;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The CVSS vector used to calculate the score.
|
|
||||||
*/
|
|
||||||
private String cvssVector;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The CVSS score.
|
|
||||||
*/
|
|
||||||
private float cvssScore;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The name of the Node module the advisory is for.
|
|
||||||
*/
|
|
||||||
private String module;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The version of the Node module the advisory is for.
|
|
||||||
*/
|
|
||||||
private String version;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A string representation of the versions containing the vulnerability.
|
|
||||||
*/
|
|
||||||
private String vulnerableVersions;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A string representation of the versions that have been patched.
|
|
||||||
*/
|
|
||||||
private String patchedVersions;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The title/name of the advisory.
|
|
||||||
*/
|
|
||||||
private String title;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The linear dependency path that lead to this module.
|
|
||||||
* [0] is the root with each subsequent array member leading up to the
|
|
||||||
* final (this) module.
|
|
||||||
*/
|
|
||||||
private String[] path;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The URL to the advisory.
|
|
||||||
*/
|
|
||||||
private String advisory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the unique ID of the advisory as issued by Node Security Platform.
|
|
||||||
* @return a unique ID
|
|
||||||
*/
|
|
||||||
public int getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the unique ID of the advisory as issued by Node Security Platform.
|
|
||||||
* @param id a unique ID
|
|
||||||
*/
|
|
||||||
public void setId(int id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the timestamp of the last update to the advisory.
|
|
||||||
* @return a timestamp
|
|
||||||
*/
|
|
||||||
public String getUpdatedAt() {
|
|
||||||
return updatedAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the timestamp of the last update to the advisory.
|
|
||||||
* @param updatedAt a timestamp
|
|
||||||
*/
|
|
||||||
public void setUpdatedAt(String updatedAt) {
|
|
||||||
this.updatedAt = updatedAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the timestamp of which the advisory was created.
|
|
||||||
* @return a timestamp
|
|
||||||
*/
|
|
||||||
public String getCreatedAt() {
|
|
||||||
return createdAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the timestamp of which the advisory was created.
|
|
||||||
* @param createdAt a timestamp
|
|
||||||
*/
|
|
||||||
public void setCreatedAt(String createdAt) {
|
|
||||||
this.createdAt = createdAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the timestamp of when the advisory was published.
|
|
||||||
* @return a timestamp
|
|
||||||
*/
|
|
||||||
public String getPublishDate() {
|
|
||||||
return publishDate;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the timestamp of when the advisory was published.
|
|
||||||
* @param publishDate a timestamp
|
|
||||||
*/
|
|
||||||
public void setPublishDate(String publishDate) {
|
|
||||||
this.publishDate = publishDate;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a detailed description of the advisory.
|
|
||||||
* @return the overview
|
|
||||||
*/
|
|
||||||
public String getOverview() {
|
|
||||||
return overview;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the detailed description of the advisory.
|
|
||||||
* @param overview the overview
|
|
||||||
*/
|
|
||||||
public void setOverview(String overview) {
|
|
||||||
this.overview = overview;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns recommendations for mitigation. Typically involves updating to a newer release.
|
|
||||||
* @return recommendations
|
|
||||||
*/
|
|
||||||
public String getRecommendation() {
|
|
||||||
return recommendation;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets recommendations for mitigation. Typically involves updating to a newer release.
|
|
||||||
* @param recommendation recommendations
|
|
||||||
*/
|
|
||||||
public void setRecommendation(String recommendation) {
|
|
||||||
this.recommendation = recommendation;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the CVSS vector used to calculate the score.
|
|
||||||
* @return the CVSS vector
|
|
||||||
*/
|
|
||||||
public String getCvssVector() {
|
|
||||||
return cvssVector;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the CVSS vector used to calculate the score.
|
|
||||||
* @param cvssVector the CVSS vector
|
|
||||||
*/
|
|
||||||
public void setCvssVector(String cvssVector) {
|
|
||||||
this.cvssVector = cvssVector;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the CVSS score.
|
|
||||||
* @return the CVSS score
|
|
||||||
*/
|
|
||||||
public float getCvssScore() {
|
|
||||||
return cvssScore;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the CVSS score.
|
|
||||||
* @param cvssScore the CVSS score
|
|
||||||
*/
|
|
||||||
public void setCvssScore(float cvssScore) {
|
|
||||||
this.cvssScore = cvssScore;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the name of the Node module the advisory is for.
|
|
||||||
* @return the name of the module
|
|
||||||
*/
|
|
||||||
public String getModule() {
|
|
||||||
return module;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the name of the Node module the advisory is for.
|
|
||||||
* @param module the name of the4 module
|
|
||||||
*/
|
|
||||||
public void setModule(String module) {
|
|
||||||
this.module = module;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the version of the Node module the advisory is for.
|
|
||||||
* @return the module version
|
|
||||||
*/
|
|
||||||
public String getVersion() {
|
|
||||||
return version;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the version of the Node module the advisory is for.
|
|
||||||
* @param version the module version
|
|
||||||
*/
|
|
||||||
public void setVersion(String version) {
|
|
||||||
this.version = version;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a string representation of the versions containing the vulnerability.
|
|
||||||
* @return the affected versions
|
|
||||||
*/
|
|
||||||
public String getVulnerableVersions() {
|
|
||||||
return vulnerableVersions;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the string representation of the versions containing the vulnerability.
|
|
||||||
* @param vulnerableVersions the affected versions
|
|
||||||
*/
|
|
||||||
public void setVulnerableVersions(String vulnerableVersions) {
|
|
||||||
this.vulnerableVersions = vulnerableVersions;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a string representation of the versions that have been patched.
|
|
||||||
* @return the patched versions
|
|
||||||
*/
|
|
||||||
public String getPatchedVersions() {
|
|
||||||
return patchedVersions;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the string representation of the versions that have been patched.
|
|
||||||
* @param patchedVersions the patched versions
|
|
||||||
*/
|
|
||||||
public void setPatchedVersions(String patchedVersions) {
|
|
||||||
this.patchedVersions = patchedVersions;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the title/name of the advisory.
|
|
||||||
* @return the title/name of the advisory
|
|
||||||
*/
|
|
||||||
public String getTitle() {
|
|
||||||
return title;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the title/name of the advisory.
|
|
||||||
* @param title the title/name of the advisory
|
|
||||||
*/
|
|
||||||
public void setTitle(String title) {
|
|
||||||
this.title = title;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the linear dependency path that lead to this module.
|
|
||||||
* @return the dependency path
|
|
||||||
*/
|
|
||||||
public String[] getPath() {
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the linear dependency path that lead to this module.
|
|
||||||
* @param path the dependency path
|
|
||||||
*/
|
|
||||||
public void setPath(String[] path) {
|
|
||||||
this.path = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the URL to the advisory.
|
|
||||||
* @return the advisory URL
|
|
||||||
*/
|
|
||||||
public String getAdvisory() {
|
|
||||||
return advisory;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the URL to the advisory.
|
|
||||||
* @param advisory the advisory URL
|
|
||||||
*/
|
|
||||||
public void setAdvisory(String advisory) {
|
|
||||||
this.advisory = advisory;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,161 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 Steve Springett. All Rights Reserved.
|
|
||||||
*/
|
|
||||||
package org.owasp.dependencycheck.data.nsp;
|
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
|
||||||
import java.io.BufferedOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.net.HttpURLConnection;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
|
||||||
import org.owasp.dependencycheck.utils.Settings;
|
|
||||||
import org.owasp.dependencycheck.utils.URLConnectionFactory;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import javax.json.Json;
|
|
||||||
import javax.json.JsonArray;
|
|
||||||
import javax.json.JsonObject;
|
|
||||||
import javax.json.JsonReader;
|
|
||||||
import org.owasp.dependencycheck.utils.URLConnectionFailureException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class of methods to search via Node Security Platform.
|
|
||||||
*
|
|
||||||
* @author Steve Springett
|
|
||||||
*/
|
|
||||||
public class NspSearch {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The URL for the public NSP check API.
|
|
||||||
*/
|
|
||||||
private final URL nspCheckUrl;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether to use the Proxy when making requests.
|
|
||||||
*/
|
|
||||||
private final boolean useProxy;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used for logging.
|
|
||||||
*/
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(NspSearch.class);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a NspSearch for the given repository URL.
|
|
||||||
*
|
|
||||||
* @param nspCheckUrl the URL to the public NSP check API
|
|
||||||
*/
|
|
||||||
public NspSearch(URL nspCheckUrl) {
|
|
||||||
this.nspCheckUrl = nspCheckUrl;
|
|
||||||
if (null != Settings.getString(Settings.KEYS.PROXY_SERVER)) {
|
|
||||||
useProxy = true;
|
|
||||||
LOGGER.debug("Using proxy");
|
|
||||||
} else {
|
|
||||||
useProxy = false;
|
|
||||||
LOGGER.debug("Not using proxy");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Submits the package.json file to the NSP public /check API and returns a
|
|
||||||
* list of zero or more Advisories.
|
|
||||||
*
|
|
||||||
* @param packageJson the package.json file retrieved from the Dependency
|
|
||||||
* @return a List of zero or more Advisory object
|
|
||||||
* @throws AnalysisException if Node Security Platform is unable to analyze the package
|
|
||||||
* @throws IOException if it's unable to connect to Node Security Platform
|
|
||||||
*/
|
|
||||||
public List<Advisory> submitPackage(JsonObject packageJson) throws AnalysisException, IOException {
|
|
||||||
try {
|
|
||||||
List<Advisory> result = new ArrayList<>();
|
|
||||||
byte[] packageDatabytes = packageJson.toString().getBytes(StandardCharsets.UTF_8);
|
|
||||||
|
|
||||||
final HttpURLConnection conn = URLConnectionFactory.createHttpURLConnection(nspCheckUrl, useProxy);
|
|
||||||
conn.setDoOutput(true);
|
|
||||||
conn.setDoInput(true);
|
|
||||||
conn.setRequestMethod("POST");
|
|
||||||
conn.setRequestProperty("X-NSP-VERSION", "2.6.2");
|
|
||||||
conn.setRequestProperty("Content-Type", "application/json");
|
|
||||||
conn.setRequestProperty("Content-Length", Integer.toString(packageDatabytes.length));
|
|
||||||
conn.connect();
|
|
||||||
|
|
||||||
try (OutputStream os = new BufferedOutputStream(conn.getOutputStream())) {
|
|
||||||
os.write(packageDatabytes);
|
|
||||||
os.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (conn.getResponseCode() == 200) {
|
|
||||||
try (InputStream in = new BufferedInputStream(conn.getInputStream())) {
|
|
||||||
JsonReader jsonReader = Json.createReader(in);
|
|
||||||
JsonArray array = jsonReader.readArray();
|
|
||||||
if (array != null) {
|
|
||||||
for (int i = 0; i < array.size(); i++) {
|
|
||||||
JsonObject object = array.getJsonObject(i);
|
|
||||||
Advisory advisory = new Advisory();
|
|
||||||
advisory.setId(object.getInt("id"));
|
|
||||||
advisory.setUpdatedAt(object.getString("updated_at", null));
|
|
||||||
advisory.setCreatedAt(object.getString("created_at", null));
|
|
||||||
advisory.setPublishDate(object.getString("publish_date", null));
|
|
||||||
advisory.setOverview(object.getString("overview"));
|
|
||||||
advisory.setRecommendation(object.getString("recommendation", null));
|
|
||||||
advisory.setCvssVector(object.getString("cvss_vector", null));
|
|
||||||
advisory.setCvssScore(Float.parseFloat(object.getJsonNumber("cvss_score").toString()));
|
|
||||||
advisory.setModule(object.getString("module", null));
|
|
||||||
advisory.setVersion(object.getString("version", null));
|
|
||||||
advisory.setVulnerableVersions(object.getString("vulnerable_versions", null));
|
|
||||||
advisory.setPatchedVersions(object.getString("patched_versions", null));
|
|
||||||
advisory.setTitle(object.getString("title", null));
|
|
||||||
advisory.setAdvisory(object.getString("advisory", null));
|
|
||||||
|
|
||||||
JsonArray jsonPath = object.getJsonArray("path");
|
|
||||||
List<String> stringPath = new ArrayList<>();
|
|
||||||
for (int j = 0; j < jsonPath.size(); j++) {
|
|
||||||
stringPath.add(jsonPath.getString(j));
|
|
||||||
}
|
|
||||||
advisory.setPath(stringPath.toArray(new String[stringPath.size()]));
|
|
||||||
|
|
||||||
result.add(advisory);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (conn.getResponseCode() == 400) {
|
|
||||||
LOGGER.debug("Invalid payload submitted to Node Security Platform. Received response code: {} {}",
|
|
||||||
conn.getResponseCode(), conn.getResponseMessage());
|
|
||||||
throw new AnalysisException("Could not perform NSP analysis. Invalid payload submitted to Node Security Platform.");
|
|
||||||
} else {
|
|
||||||
LOGGER.debug("Could not connect to Node Security Platform. Received response code: {} {}",
|
|
||||||
conn.getResponseCode(), conn.getResponseMessage());
|
|
||||||
throw new IOException("Could not connect to Node Security Platform");
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
} catch (IOException ex) {
|
|
||||||
if (ex instanceof javax.net.ssl.SSLHandshakeException
|
|
||||||
&& ex.getMessage().contains("unable to find valid certification path to requested target")) {
|
|
||||||
final String msg = String.format("Unable to connect to '%s' - the Java trust store does not contain a trusted root for the cert. "
|
|
||||||
+ " Please see https://github.com/jeremylong/InstallCert for one method of updating the trusted certificates.", nspCheckUrl);
|
|
||||||
throw new URLConnectionFailureException(msg, ex);
|
|
||||||
}
|
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 Steve Springett. All Rights Reserved.
|
|
||||||
*/
|
|
||||||
package org.owasp.dependencycheck.data.nsp;
|
|
||||||
|
|
||||||
import javax.json.Json;
|
|
||||||
import javax.json.JsonObject;
|
|
||||||
import javax.json.JsonObjectBuilder;
|
|
||||||
import javax.json.JsonValue;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class used to create a Sanitized version of package.json
|
|
||||||
* suitable for submission to the nsp/check service.
|
|
||||||
*
|
|
||||||
* @author Steve Springett
|
|
||||||
*/
|
|
||||||
public class SanitizePackage {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specifies a whitelist of allowable objects that package.json should contain.
|
|
||||||
*/
|
|
||||||
private static final List<String> WHITELIST = new ArrayList<>(Arrays.asList(
|
|
||||||
"name",
|
|
||||||
"version",
|
|
||||||
"engine",
|
|
||||||
"dependencies",
|
|
||||||
"devDependencies",
|
|
||||||
"optionalDependencies",
|
|
||||||
"peerDependencies",
|
|
||||||
"bundleDependencies",
|
|
||||||
"bundledDependencies"
|
|
||||||
));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The NSP API only accepts a subset of objects typically found in package.json.
|
|
||||||
* This method accepts a JsonObject of a raw package.json file and returns a
|
|
||||||
* new 'sanitized' version based on a pre-defined whitelist of allowable object
|
|
||||||
* NSP accepts.
|
|
||||||
*
|
|
||||||
* @param rawPackage a raw package.json file
|
|
||||||
* @return a sanitized version of the package.json file
|
|
||||||
*/
|
|
||||||
public static JsonObject sanitize(JsonObject rawPackage) {
|
|
||||||
JsonObjectBuilder builder = Json.createObjectBuilder();
|
|
||||||
for (Map.Entry<String, JsonValue> entry: rawPackage.entrySet()) {
|
|
||||||
if (WHITELIST.contains(entry.getKey())) {
|
|
||||||
builder.add(entry.getKey(), entry.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return builder.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
/**
|
|
||||||
*
|
|
||||||
* Contains classes related to searching Node Security Platform (nsp).<br><br>
|
|
||||||
*
|
|
||||||
* These are used to abstract NSP searching away from OWASP Dependency Check so they can be reused elsewhere.
|
|
||||||
*/
|
|
||||||
package org.owasp.dependencycheck.data.nsp;
|
|
||||||
@@ -138,11 +138,6 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
|||||||
*/
|
*/
|
||||||
private List<String> availableVersions = new ArrayList<>();
|
private List<String> availableVersions = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
|
||||||
* Defines an actual or virtual dependency.
|
|
||||||
*/
|
|
||||||
private boolean isVirtual = false;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the package path.
|
* Returns the package path.
|
||||||
*
|
*
|
||||||
@@ -180,18 +175,7 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
|||||||
* @param file the File to create the dependency object from.
|
* @param file the File to create the dependency object from.
|
||||||
*/
|
*/
|
||||||
public Dependency(File file) {
|
public Dependency(File file) {
|
||||||
this(file, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new Dependency object.
|
|
||||||
*
|
|
||||||
* @param file the File to create the dependency object from.
|
|
||||||
* @param isVirtual specifies if the dependency is virtual indicating the file doesn't actually exist.
|
|
||||||
*/
|
|
||||||
public Dependency(File file, boolean isVirtual) {
|
|
||||||
this();
|
this();
|
||||||
this.isVirtual = isVirtual;
|
|
||||||
this.actualFilePath = file.getAbsolutePath();
|
this.actualFilePath = file.getAbsolutePath();
|
||||||
this.filePath = this.actualFilePath;
|
this.filePath = this.actualFilePath;
|
||||||
this.fileName = file.getName();
|
this.fileName = file.getName();
|
||||||
@@ -607,9 +591,6 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
|||||||
private void determineHashes(File file) {
|
private void determineHashes(File file) {
|
||||||
String md5 = null;
|
String md5 = null;
|
||||||
String sha1 = null;
|
String sha1 = null;
|
||||||
if (isVirtual) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
md5 = Checksum.getMD5Checksum(file);
|
md5 = Checksum.getMD5Checksum(file);
|
||||||
sha1 = Checksum.getSHA1Checksum(file);
|
sha1 = Checksum.getSHA1Checksum(file);
|
||||||
|
|||||||
@@ -32,11 +32,6 @@ import org.apache.commons.lang3.builder.CompareToBuilder;
|
|||||||
*/
|
*/
|
||||||
public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
||||||
|
|
||||||
public enum Source {
|
|
||||||
NVD, // National Vulnerability Database
|
|
||||||
NSP // Node Security Platform
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The serial version uid.
|
* The serial version uid.
|
||||||
*/
|
*/
|
||||||
@@ -105,11 +100,6 @@ public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
|||||||
*/
|
*/
|
||||||
private String notes;
|
private String notes;
|
||||||
|
|
||||||
/**
|
|
||||||
* The source that identified the vulnerability.
|
|
||||||
*/
|
|
||||||
private Source source = Source.NVD;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of name.
|
* Get the value of name.
|
||||||
*
|
*
|
||||||
@@ -526,20 +516,4 @@ public class Vulnerability implements Serializable, Comparable<Vulnerability> {
|
|||||||
public boolean hasMatchedAllPreviousCPE() {
|
public boolean hasMatchedAllPreviousCPE() {
|
||||||
return matchedAllPreviousCPE != null;
|
return matchedAllPreviousCPE != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Retruns the source that identified the vulnerability.
|
|
||||||
* @return the source
|
|
||||||
*/
|
|
||||||
public Source getSource() {
|
|
||||||
return source;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the source that identified the vulnerability.
|
|
||||||
* @param source the source
|
|
||||||
*/
|
|
||||||
public void setSource(Source source) {
|
|
||||||
this.source = source;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -107,29 +107,8 @@ public class ReportGenerator {
|
|||||||
*/
|
*/
|
||||||
public ReportGenerator(String applicationName, List<Dependency> dependencies, List<Analyzer> analyzers, DatabaseProperties properties) {
|
public ReportGenerator(String applicationName, List<Dependency> dependencies, List<Analyzer> analyzers, DatabaseProperties properties) {
|
||||||
velocityEngine = createVelocityEngine();
|
velocityEngine = createVelocityEngine();
|
||||||
context = createContext();
|
|
||||||
|
|
||||||
velocityEngine.init();
|
velocityEngine.init();
|
||||||
final EscapeTool enc = new EscapeTool();
|
context = createContext(applicationName, dependencies, analyzers, properties);
|
||||||
|
|
||||||
final DateTime dt = new DateTime();
|
|
||||||
final DateTimeFormatter dateFormat = DateTimeFormat.forPattern("MMM d, yyyy 'at' HH:mm:ss z");
|
|
||||||
final DateTimeFormatter dateFormatXML = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
|
|
||||||
|
|
||||||
// final Date d = new Date();
|
|
||||||
// final DateFormat dateFormat = new SimpleDateFormat("MMM d, yyyy 'at' HH:mm:ss z");
|
|
||||||
// final DateFormat dateFormatXML = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
|
|
||||||
final String scanDate = dateFormat.print(dt);
|
|
||||||
final String scanDateXML = dateFormatXML.print(dt);
|
|
||||||
|
|
||||||
context.put("applicationName", applicationName);
|
|
||||||
context.put("dependencies", dependencies);
|
|
||||||
context.put("analyzers", analyzers);
|
|
||||||
context.put("properties", properties);
|
|
||||||
context.put("scanDate", scanDate);
|
|
||||||
context.put("scanDateXML", scanDateXML);
|
|
||||||
context.put("enc", enc);
|
|
||||||
context.put("version", Settings.getString(Settings.KEYS.APPLICATION_VERSION, "Unknown"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -148,9 +127,15 @@ public class ReportGenerator {
|
|||||||
List<Dependency> dependencies, List<Analyzer> analyzers, DatabaseProperties properties) {
|
List<Dependency> dependencies, List<Analyzer> analyzers, DatabaseProperties properties) {
|
||||||
|
|
||||||
this(applicationName, dependencies, analyzers, properties);
|
this(applicationName, dependencies, analyzers, properties);
|
||||||
context.put("applicationVersion", version);
|
if (version != null) {
|
||||||
context.put("artifactID", artifactID);
|
context.put("applicationVersion", version);
|
||||||
context.put("groupID", groupID);
|
}
|
||||||
|
if (artifactID != null) {
|
||||||
|
context.put("artifactID", artifactID);
|
||||||
|
}
|
||||||
|
if (groupID != null) {
|
||||||
|
context.put("groupID", groupID);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -166,67 +151,235 @@ public class ReportGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new Velocity Context.
|
* Constructs the velocity context used to generate the dependency-check
|
||||||
|
* reports.
|
||||||
*
|
*
|
||||||
* @return a Velocity Context
|
* @param applicationName the application name 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)
|
||||||
|
* @return the velocity context
|
||||||
*/
|
*/
|
||||||
private Context createContext() {
|
private VelocityContext createContext(String applicationName, List<Dependency> dependencies, List<Analyzer> analyzers, DatabaseProperties properties) {
|
||||||
return new VelocityContext();
|
final DateTime dt = new DateTime();
|
||||||
|
final DateTimeFormatter dateFormat = DateTimeFormat.forPattern("MMM d, yyyy 'at' HH:mm:ss z");
|
||||||
|
final DateTimeFormatter dateFormatXML = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
|
||||||
|
|
||||||
|
final String scanDate = dateFormat.print(dt);
|
||||||
|
final String scanDateXML = dateFormatXML.print(dt);
|
||||||
|
|
||||||
|
VelocityContext ctxt = new VelocityContext();
|
||||||
|
ctxt.put("applicationName", applicationName);
|
||||||
|
ctxt.put("dependencies", dependencies);
|
||||||
|
ctxt.put("analyzers", analyzers);
|
||||||
|
ctxt.put("properties", properties);
|
||||||
|
ctxt.put("scanDate", scanDate);
|
||||||
|
ctxt.put("scanDateXML", scanDateXML);
|
||||||
|
ctxt.put("enc", new EscapeTool());
|
||||||
|
ctxt.put("version", Settings.getString(Settings.KEYS.APPLICATION_VERSION, "Unknown"));
|
||||||
|
return ctxt;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates the Dependency Reports for the identified dependencies.
|
* Writes the dependency-check report to the given output location.
|
||||||
*
|
*
|
||||||
* @param outputStream the OutputStream to send the generated report to
|
* @param outputLocation the path where the reports should be written
|
||||||
* @param format the format the report should be written in
|
* @param format the format the report should be written in (XML, HTML,
|
||||||
* @throws IOException is thrown when the template file does not exist
|
* JSON, CSV, ALL) or even the path to a custom velocity template (either
|
||||||
* @throws Exception is thrown if there is an error writing out the reports
|
* fully qualified or the template name on the class path).
|
||||||
*/
|
* @throws ReportException is thrown if there is an error creating out the
|
||||||
public void generateReports(OutputStream outputStream, Format format) throws IOException, Exception {
|
|
||||||
if (format == Format.XML || format == Format.ALL) {
|
|
||||||
generateReport("XmlReport", outputStream);
|
|
||||||
}
|
|
||||||
if (format == Format.HTML || format == Format.ALL) {
|
|
||||||
generateReport("HtmlReport", outputStream);
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates the Dependency Reports for the identified dependencies.
|
|
||||||
*
|
|
||||||
* @param outputDir the path where the reports should be written
|
|
||||||
* @param format the format the report should be written in
|
|
||||||
* @throws ReportException is thrown if there is an error writing out the
|
|
||||||
* reports
|
* reports
|
||||||
*/
|
*/
|
||||||
public void generateReports(String outputDir, Format format) throws ReportException {
|
public void write(String outputLocation, String format) throws ReportException {
|
||||||
if (format == Format.XML || format == Format.ALL) {
|
Format reportFormat = null;
|
||||||
generateReport("XmlReport", outputDir + File.separator + "dependency-check-report.xml");
|
try {
|
||||||
|
reportFormat = Format.valueOf(format.toUpperCase());
|
||||||
|
} catch (IllegalArgumentException ex) {
|
||||||
|
LOGGER.trace("ignore this exception", ex);
|
||||||
}
|
}
|
||||||
if (format == Format.JSON || format == Format.ALL) {
|
|
||||||
generateReport("JsonReport", outputDir + File.separator + "dependency-check-report.json");
|
if (reportFormat != null) {
|
||||||
pretifyJson(outputDir + File.separator + "dependency-check-report.json");
|
write(outputLocation, reportFormat);
|
||||||
|
} else {
|
||||||
|
File out = getReportFile(outputLocation, null);
|
||||||
|
if (out.isDirectory()) {
|
||||||
|
throw new ReportException("Unable to write non-standard VSL output to a directory, please specify a file name");
|
||||||
|
}
|
||||||
|
processTemplate(format, out);
|
||||||
}
|
}
|
||||||
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");
|
* Writes the dependency-check report(s).
|
||||||
}
|
*
|
||||||
if (format == Format.VULN || format == Format.ALL) {
|
* @param outputLocation the path where the reports should be written
|
||||||
generateReport("VulnerabilityReport", outputDir + File.separator + "dependency-check-vulnerability.html");
|
* @param format the format the report should be written in (XML, HTML, ALL)
|
||||||
|
* @throws ReportException is thrown if there is an error creating out the
|
||||||
|
* reports
|
||||||
|
*/
|
||||||
|
public void write(String outputLocation, Format format) throws ReportException {
|
||||||
|
if (format == Format.ALL) {
|
||||||
|
for (Format f : Format.values()) {
|
||||||
|
if (f != Format.ALL) {
|
||||||
|
write(outputLocation, f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
final File out = getReportFile(outputLocation, format);
|
||||||
|
final String templateName = format.toString().toLowerCase() + "Report";
|
||||||
|
processTemplate(templateName, out);
|
||||||
|
if (format == Format.JSON) {
|
||||||
|
pretifyJson(out.getPath());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * Writes the dependency-check report(s).
|
||||||
|
// *
|
||||||
|
// * @param outputStream the OutputStream to send the generated report to
|
||||||
|
// * @param format the format the report should be written in
|
||||||
|
// * @throws ReportException thrown if the report format is ALL
|
||||||
|
// * @throws IOException is thrown when the template file does not exist
|
||||||
|
// * @throws Exception is thrown if there is an error writing out the reports
|
||||||
|
// */
|
||||||
|
// public void write(OutputStream outputStream, Format format) throws ReportException, IOException, Exception {
|
||||||
|
// if (format == Format.ALL) {
|
||||||
|
// throw new ReportException("Unable to write ALL reports to a single output stream, please check the API");
|
||||||
|
// }
|
||||||
|
// final String templateName = format.toString().toLowerCase() + "Report";
|
||||||
|
// processTemplate(templateName, outputStream);
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines the report file name based on the give output location and
|
||||||
|
* format. If the output location contains a full file name that has the
|
||||||
|
* correct extension for the given report type then the output location is
|
||||||
|
* returned. However, if the output location is a directory, this method
|
||||||
|
* will generate the correct name for the given output format.
|
||||||
|
*
|
||||||
|
* @param outputLocation the specified output location
|
||||||
|
* @param format the report format
|
||||||
|
* @return the report File
|
||||||
|
*/
|
||||||
|
protected File getReportFile(String outputLocation, Format format) {
|
||||||
|
File outFile = new File(outputLocation);
|
||||||
|
if (outFile.getParentFile() == null) {
|
||||||
|
outFile = new File(".", outputLocation);
|
||||||
|
}
|
||||||
|
final String pathToCheck = outputLocation.toLowerCase();
|
||||||
|
if (format == Format.XML && !pathToCheck.endsWith(".xml")) {
|
||||||
|
return new File(outFile, "dependency-check-report.xml");
|
||||||
|
}
|
||||||
|
if (format == Format.HTML && !pathToCheck.endsWith(".html") && !pathToCheck.endsWith(".htm")) {
|
||||||
|
return new File(outFile, "dependency-check-report.html");
|
||||||
|
}
|
||||||
|
if (format == Format.VULN && !pathToCheck.endsWith(".html") && !pathToCheck.endsWith(".htm")) {
|
||||||
|
return new File(outFile, "dependency-check-vulnerability.html");
|
||||||
|
}
|
||||||
|
if (format == Format.JSON && !pathToCheck.endsWith(".json")) {
|
||||||
|
return new File(outFile, "dependency-check-report.json");
|
||||||
|
}
|
||||||
|
if (format == Format.CSV && !pathToCheck.endsWith(".csv")) {
|
||||||
|
return new File(outFile, "dependency-check-report.csv");
|
||||||
|
}
|
||||||
|
return outFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a report from a given Velocity Template. The template name
|
||||||
|
* provided can be the name of a template contained in the jar file, such as
|
||||||
|
* 'XmlReport' or 'HtmlReport', or the template name can be the path to a
|
||||||
|
* template file.
|
||||||
|
*
|
||||||
|
* @param template the name of the template to load
|
||||||
|
* @param file the output file to write the report to
|
||||||
|
* @throws ReportException is thrown when the report cannot be generated
|
||||||
|
*/
|
||||||
|
protected void processTemplate(String template, File file) throws ReportException {
|
||||||
|
ensureParentDirectoryExists(file);
|
||||||
|
try (OutputStream output = new FileOutputStream(file)) {
|
||||||
|
processTemplate(template, output);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new ReportException(String.format("Unable to write to file: %s", file), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a report from a given Velocity Template. The template name
|
||||||
|
* provided can be the name of a template contained in the jar file, such as
|
||||||
|
* 'XmlReport' or 'HtmlReport', or the template name can be the path to a
|
||||||
|
* template file.
|
||||||
|
*
|
||||||
|
* @param templateName the name of the template to load
|
||||||
|
* @param outputStream the OutputStream to write the report to
|
||||||
|
* @throws ReportException is thrown when an exception occurs
|
||||||
|
*/
|
||||||
|
protected void processTemplate(String templateName, OutputStream outputStream) throws ReportException {
|
||||||
|
InputStream input = null;
|
||||||
|
String logTag = null;
|
||||||
|
final File f = new File(templateName);
|
||||||
|
try {
|
||||||
|
if (f.isFile()) {
|
||||||
|
try {
|
||||||
|
logTag = templateName;
|
||||||
|
input = new FileInputStream(f);
|
||||||
|
} catch (FileNotFoundException ex) {
|
||||||
|
throw new ReportException("Unable to locate template file: " + templateName, ex);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logTag = "templates/" + templateName + ".vsl";
|
||||||
|
input = this.getClass().getClassLoader().getResourceAsStream(logTag);
|
||||||
|
}
|
||||||
|
if (input == null) {
|
||||||
|
logTag = templateName;
|
||||||
|
input = this.getClass().getClassLoader().getResourceAsStream(templateName);
|
||||||
|
}
|
||||||
|
if (input == null) {
|
||||||
|
throw new ReportException("Template file doesn't exist: " + logTag);
|
||||||
|
}
|
||||||
|
|
||||||
|
try (InputStreamReader reader = new InputStreamReader(input, "UTF-8");
|
||||||
|
OutputStreamWriter writer = new OutputStreamWriter(outputStream, "UTF-8")) {
|
||||||
|
if (!velocityEngine.evaluate(context, writer, logTag, reader)) {
|
||||||
|
throw new ReportException("Failed to convert the template into html.");
|
||||||
|
}
|
||||||
|
writer.flush();
|
||||||
|
} catch (UnsupportedEncodingException ex) {
|
||||||
|
throw new ReportException("Unable to generate the report using UTF-8", ex);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new ReportException("Unable to write the report", ex);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (input != null) {
|
||||||
|
try {
|
||||||
|
input.close();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
LOGGER.trace("Error closing input", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Validates that the given file's parent directory exists. If the directory
|
||||||
|
* does not exist an attempt to create the necessary path is made; if that
|
||||||
|
* fails a ReportException will be raised.
|
||||||
|
*
|
||||||
|
* @param file the file or directory directory
|
||||||
|
* @throws ReportException thrown if the parent directory does not exist and
|
||||||
|
* cannot be created
|
||||||
|
*/
|
||||||
|
private void ensureParentDirectoryExists(File file) throws ReportException {
|
||||||
|
if (!file.getParentFile().exists()) {
|
||||||
|
final boolean created = file.getParentFile().mkdirs();
|
||||||
|
if (!created) {
|
||||||
|
final String msg = String.format("Unable to create directory '%s'.", file.getParentFile().getAbsolutePath());
|
||||||
|
throw new ReportException(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Reformats the given JSON file.
|
* Reformats the given JSON file.
|
||||||
*
|
*
|
||||||
@@ -311,139 +464,4 @@ public class ReportGenerator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates the Dependency Reports for the identified dependencies.
|
|
||||||
*
|
|
||||||
* @param outputDir the path where the reports should be written
|
|
||||||
* @param outputFormat the format the report should be written in (XML,
|
|
||||||
* HTML, ALL)
|
|
||||||
* @throws ReportException is thrown if there is an error creating out the
|
|
||||||
* reports
|
|
||||||
*/
|
|
||||||
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|JSON|ALL)$")) {
|
|
||||||
if ("XML".equalsIgnoreCase(format)) {
|
|
||||||
if (pathToCheck.endsWith(".xml")) {
|
|
||||||
generateReport("XmlReport", outputDir);
|
|
||||||
} else {
|
|
||||||
generateReports(outputDir, Format.XML);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ("HTML".equalsIgnoreCase(format)) {
|
|
||||||
if (pathToCheck.endsWith(".html") || pathToCheck.endsWith(".htm")) {
|
|
||||||
generateReport("HtmlReport", outputDir);
|
|
||||||
} else {
|
|
||||||
generateReports(outputDir, Format.HTML);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ("VULN".equalsIgnoreCase(format)) {
|
|
||||||
if (pathToCheck.endsWith(".html") || pathToCheck.endsWith(".htm")) {
|
|
||||||
generateReport("VulnReport", outputDir);
|
|
||||||
} else {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates a report from a given Velocity Template. The template name
|
|
||||||
* provided can be the name of a template contained in the jar file, such as
|
|
||||||
* 'XmlReport' or 'HtmlReport', or the template name can be the path to a
|
|
||||||
* template file.
|
|
||||||
*
|
|
||||||
* @param templateName the name of the template to load
|
|
||||||
* @param outputStream the OutputStream to write the report to
|
|
||||||
* @throws ReportException is thrown when an exception occurs
|
|
||||||
*/
|
|
||||||
protected void generateReport(String templateName, OutputStream outputStream) throws ReportException {
|
|
||||||
InputStream input = null;
|
|
||||||
String templatePath = null;
|
|
||||||
final File f = new File(templateName);
|
|
||||||
try {
|
|
||||||
if (f.exists() && f.isFile()) {
|
|
||||||
try {
|
|
||||||
templatePath = templateName;
|
|
||||||
input = new FileInputStream(f);
|
|
||||||
} catch (FileNotFoundException ex) {
|
|
||||||
throw new ReportException("Unable to locate template file: " + templateName, ex);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
templatePath = "templates/" + templateName + ".vsl";
|
|
||||||
input = this.getClass().getClassLoader().getResourceAsStream(templatePath);
|
|
||||||
}
|
|
||||||
if (input == null) {
|
|
||||||
throw new ReportException("Template file doesn't exist: " + templatePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
try (InputStreamReader reader = new InputStreamReader(input, "UTF-8");
|
|
||||||
OutputStreamWriter writer = new OutputStreamWriter(outputStream, "UTF-8")) {
|
|
||||||
if (!velocityEngine.evaluate(context, writer, templatePath, reader)) {
|
|
||||||
throw new ReportException("Failed to convert the template into html.");
|
|
||||||
}
|
|
||||||
writer.flush();
|
|
||||||
} catch (UnsupportedEncodingException ex) {
|
|
||||||
throw new ReportException("Unable to generate the report using UTF-8", ex);
|
|
||||||
} catch (IOException ex) {
|
|
||||||
throw new ReportException("Unable to write the report", ex);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
if (input != null) {
|
|
||||||
try {
|
|
||||||
input.close();
|
|
||||||
} catch (IOException ex) {
|
|
||||||
LOGGER.trace("Error closing input", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates a report from a given Velocity Template. The template name
|
|
||||||
* provided can be the name of a template contained in the jar file, such as
|
|
||||||
* 'XmlReport' or 'HtmlReport', or the template name can be the path to a
|
|
||||||
* template file.
|
|
||||||
*
|
|
||||||
* @param templateName the name of the template to load
|
|
||||||
* @param outFileName the filename and path to write the report to
|
|
||||||
* @throws ReportException is thrown when the report cannot be generated
|
|
||||||
*/
|
|
||||||
protected void generateReport(String templateName, String outFileName) throws ReportException {
|
|
||||||
File outFile = new File(outFileName);
|
|
||||||
if (outFile.getParentFile() == null) {
|
|
||||||
outFile = new File(".", outFileName);
|
|
||||||
}
|
|
||||||
if (!outFile.getParentFile().exists()) {
|
|
||||||
final boolean created = outFile.getParentFile().mkdirs();
|
|
||||||
if (!created) {
|
|
||||||
throw new ReportException("Unable to create directory '" + outFile.getParentFile().getAbsolutePath() + "'.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
try (OutputStream outputSteam = new FileOutputStream(outFile)) {
|
|
||||||
generateReport(templateName, outputSteam);
|
|
||||||
} catch (IOException ex) {
|
|
||||||
throw new ReportException("Unable to write to file: " + outFile, ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ org.owasp.dependencycheck.analyzer.AutoconfAnalyzer
|
|||||||
org.owasp.dependencycheck.analyzer.OpenSSLAnalyzer
|
org.owasp.dependencycheck.analyzer.OpenSSLAnalyzer
|
||||||
org.owasp.dependencycheck.analyzer.CMakeAnalyzer
|
org.owasp.dependencycheck.analyzer.CMakeAnalyzer
|
||||||
org.owasp.dependencycheck.analyzer.NodePackageAnalyzer
|
org.owasp.dependencycheck.analyzer.NodePackageAnalyzer
|
||||||
org.owasp.dependencycheck.analyzer.NspAnalyzer
|
|
||||||
org.owasp.dependencycheck.analyzer.RubyGemspecAnalyzer
|
org.owasp.dependencycheck.analyzer.RubyGemspecAnalyzer
|
||||||
org.owasp.dependencycheck.analyzer.RubyBundlerAnalyzer
|
org.owasp.dependencycheck.analyzer.RubyBundlerAnalyzer
|
||||||
org.owasp.dependencycheck.analyzer.RubyBundleAuditAnalyzer
|
org.owasp.dependencycheck.analyzer.RubyBundleAuditAnalyzer
|
||||||
|
|||||||
@@ -78,9 +78,6 @@ analyzer.nexus.proxy=true
|
|||||||
analyzer.central.enabled=true
|
analyzer.central.enabled=true
|
||||||
analyzer.central.url=https://search.maven.org/solrsearch/select
|
analyzer.central.url=https://search.maven.org/solrsearch/select
|
||||||
|
|
||||||
# the URL for searching api.nodesecurity.io
|
|
||||||
analyzer.nsp.url=https://api.nodesecurity.io/check
|
|
||||||
|
|
||||||
# the number of nested archives that will be searched.
|
# the number of nested archives that will be searched.
|
||||||
archive.scan.depth=3
|
archive.scan.depth=3
|
||||||
|
|
||||||
@@ -92,7 +89,6 @@ analyzer.experimental.enabled=false
|
|||||||
analyzer.jar.enabled=true
|
analyzer.jar.enabled=true
|
||||||
analyzer.archive.enabled=true
|
analyzer.archive.enabled=true
|
||||||
analyzer.node.package.enabled=true
|
analyzer.node.package.enabled=true
|
||||||
analyzer.nsp.package.enabled=true
|
|
||||||
analyzer.composer.lock.enabled=true
|
analyzer.composer.lock.enabled=true
|
||||||
analyzer.python.distribution.enabled=true
|
analyzer.python.distribution.enabled=true
|
||||||
analyzer.python.package.enabled=true
|
analyzer.python.package.enabled=true
|
||||||
|
|||||||
@@ -759,8 +759,8 @@ Getting Help: <a href="https://groups.google.com/forum/#!forum/dependency-check"
|
|||||||
<li>$enc.html($related.DisplayFileName)
|
<li>$enc.html($related.DisplayFileName)
|
||||||
<ul>
|
<ul>
|
||||||
<li>File Path: $enc.html($related.FilePath)</li>
|
<li>File Path: $enc.html($related.FilePath)</li>
|
||||||
<li>SHA1: #if($related.Sha1sum)$enc.html($related.Sha1sum)#end</li>
|
<li>SHA1: $enc.html($related.Sha1sum)</li>
|
||||||
<li>MD5: #if($related.Md5sum)$enc.html($related.Md5sum)#end</li>
|
<li>MD5: $enc.html($related.Md5sum)</li>
|
||||||
#foreach($id in $related.getIdentifiers())
|
#foreach($id in $related.getIdentifiers())
|
||||||
#if( $id.url )
|
#if( $id.url )
|
||||||
#if ($id.type=="maven")
|
#if ($id.type=="maven")
|
||||||
@@ -771,9 +771,6 @@ Getting Help: <a href="https://groups.google.com/forum/#!forum/dependency-check"
|
|||||||
#end
|
#end
|
||||||
</li>
|
</li>
|
||||||
#end
|
#end
|
||||||
#if ($id.type=="npm")
|
|
||||||
<li>$enc.html($id.value): $enc.html($id.description)</li>
|
|
||||||
#end
|
|
||||||
#end
|
#end
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
@@ -840,11 +837,7 @@ Getting Help: <a href="https://groups.google.com/forum/#!forum/dependency-check"
|
|||||||
<div id="content$cnt" class="subsectioncontent standardsubsection">
|
<div id="content$cnt" class="subsectioncontent standardsubsection">
|
||||||
#foreach($vuln in $dependency.getVulnerabilities())
|
#foreach($vuln in $dependency.getVulnerabilities())
|
||||||
#set($vsctr=$vsctr+1)
|
#set($vsctr=$vsctr+1)
|
||||||
#if($vuln.getSource().name().equals("NVD"))
|
<p><b><a target="_blank" href="http://web.nvd.nist.gov/view/vuln/detail?vulnId=$enc.url($vuln.name)">$enc.html($vuln.name)</a></b> <button class="copybutton" title="Generate Suppression XML for this CCE for this file" onclick="copyText('$enc.html($dependency.FileNameForJavaScript)', '$enc.html($dependency.Sha1sum)', '$enc.html($suppressGav)', 'cve', '$enc.html($vuln.name)')">suppress</button></p>
|
||||||
<p><b><a target="_blank" href="http://web.nvd.nist.gov/view/vuln/detail?vulnId=$enc.url($vuln.name)">$enc.html($vuln.name)</a></b> <button class="copybutton" title="Generate Suppression XML for this CCE for this file" onclick="copyText('$enc.html($dependency.FileNameForJavaScript)', '$enc.html($dependency.Sha1sum)', '$enc.html($suppressGav)', 'cve', '$enc.html($vuln.name)')">suppress</button></p>
|
|
||||||
#elseif($vuln.getSource().name().equals("NSP"))
|
|
||||||
<p><b><a target="_blank" href="https://nodesecurity.io/advisories/$enc.url($vuln.name)">NSP-$enc.html($vuln.name)</a></b></p>
|
|
||||||
#end
|
|
||||||
<p>Severity:
|
<p>Severity:
|
||||||
#if ($vuln.cvssScore<4.0)
|
#if ($vuln.cvssScore<4.0)
|
||||||
Low
|
Low
|
||||||
@@ -853,11 +846,7 @@ Getting Help: <a href="https://groups.google.com/forum/#!forum/dependency-check"
|
|||||||
#else
|
#else
|
||||||
Medium
|
Medium
|
||||||
#end
|
#end
|
||||||
<br/>CVSS Score: $vuln.cvssScore
|
<br/>CVSS Score: $vuln.cvssScore (AV:$enc.html($vuln.cvssAccessVector.substring(0,1))/AC:$enc.html($vuln.cvssAccessComplexity.substring(0,1))/Au:$enc.html($vuln.cvssAuthentication.substring(0,1))/C:$enc.html($vuln.cvssConfidentialityImpact.substring(0,1))/I:$enc.html($vuln.cvssIntegrityImpact.substring(0,1))/A:$enc.html($vuln.cvssAvailabilityImpact.substring(0,1)))
|
||||||
#if ($vuln.getSource().name().equals("NVD"))
|
|
||||||
<!-- todo: temp workaround as NSP uses CVSSv3 and supplies the full vector -->
|
|
||||||
(AV:$enc.html($vuln.cvssAccessVector.substring(0,1))/AC:$enc.html($vuln.cvssAccessComplexity.substring(0,1))/Au:$enc.html($vuln.cvssAuthentication.substring(0,1))/C:$enc.html($vuln.cvssConfidentialityImpact.substring(0,1))/I:$enc.html($vuln.cvssIntegrityImpact.substring(0,1))/A:$enc.html($vuln.cvssAvailabilityImpact.substring(0,1)))
|
|
||||||
#end
|
|
||||||
#if ($vuln.cwe)
|
#if ($vuln.cwe)
|
||||||
<br/>CWE: $vuln.cwe
|
<br/>CWE: $vuln.cwe
|
||||||
#end
|
#end
|
||||||
@@ -874,28 +863,18 @@ Getting Help: <a href="https://groups.google.com/forum/#!forum/dependency-check"
|
|||||||
#end
|
#end
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
#if ($vuln.getSource().name().equals("NVD"))
|
#if ($vuln.getVulnerableSoftware().size()<2)
|
||||||
#if ($vuln.getVulnerableSoftware().size()<2)
|
<p>Vulnerable Software & Versions:<ul>
|
||||||
<p>Vulnerable Software & Versions:<ul>
|
<li class="vs$vsctr"><a target="_blank" href="https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=$enc.url($vuln.matchedCPE)">$enc.html($vuln.matchedCPE)</a> #if($vuln.hasMatchedAllPreviousCPE()) and all previous versions#end</li>
|
||||||
<li class="vs$vsctr"><a target="_blank" href="https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=$enc.url($vuln.matchedCPE)">$enc.html($vuln.matchedCPE)</a> #if($vuln.hasMatchedAllPreviousCPE()) and all previous versions#end</li>
|
</ul></p>
|
||||||
</ul></p>
|
#else
|
||||||
#else
|
<p>Vulnerable Software & Versions: (<a href="#" onclick="return toggleDisplay(this,'.vs$vsctr', 'show all', 'show less');">show all</a>)<ul>
|
||||||
<p>Vulnerable Software & Versions: (<a href="#" onclick="return toggleDisplay(this,'.vs$vsctr', 'show all', 'show less');">show all</a>)<ul>
|
<li class="vs$vsctr"><a target="_blank" href="https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=$enc.url($vuln.matchedCPE)">$enc.html($vuln.matchedCPE)</a> #if($vuln.hasMatchedAllPreviousCPE()) and all previous versions#end</li>
|
||||||
<li class="vs$vsctr"><a target="_blank" href="https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=$enc.url($vuln.matchedCPE)">$enc.html($vuln.matchedCPE)</a> #if($vuln.hasMatchedAllPreviousCPE()) and all previous versions#end</li>
|
<li class="vs$vsctr">...</li>
|
||||||
<li class="vs$vsctr">...</li>
|
#foreach($vs in $vuln.getVulnerableSoftware(true))
|
||||||
#foreach($vs in $vuln.getVulnerableSoftware(true))
|
<li class="vs$vsctr hidden"><a target="_blank" href="https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=$enc.url($vs.name)">$enc.html($vs.name)</a> #if($vs.hasPreviousVersion()) and all previous versions#end</li>
|
||||||
<li class="vs$vsctr hidden"><a target="_blank" href="https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=$enc.url($vs.name)">$enc.html($vs.name)</a> #if($vs.hasPreviousVersion()) and all previous versions#end</li>
|
|
||||||
#end
|
|
||||||
</ul></p>
|
|
||||||
#end
|
#end
|
||||||
#elseif ($vuln.getSource().name().equals("NSP"))
|
</ul></p>
|
||||||
<p>Vulnerable Software & Versions:
|
|
||||||
<ul>
|
|
||||||
#foreach($vs in $vuln.getVulnerableSoftware())
|
|
||||||
<li class="vs$vsctr">$enc.html($vs.name)</li>
|
|
||||||
#end
|
|
||||||
</ul>
|
|
||||||
</p>
|
|
||||||
#end
|
#end
|
||||||
#end
|
#end
|
||||||
</div>
|
</div>
|
||||||
@@ -950,8 +929,8 @@ Getting Help: <a href="https://groups.google.com/forum/#!forum/dependency-check"
|
|||||||
<li>$enc.html($related.DisplayFileName)
|
<li>$enc.html($related.DisplayFileName)
|
||||||
<ul>
|
<ul>
|
||||||
<li>File Path: $enc.html($related.FilePath)</li>
|
<li>File Path: $enc.html($related.FilePath)</li>
|
||||||
<li>SHA1: #if($related.Sha1sum)$enc.html($related.Sha1sum)#end</li>
|
<li>SHA1: $enc.html($related.Sha1sum)</li>
|
||||||
<li>MD5: #if($related.Md5sum)$enc.html($related.Md5sum)#end</li>
|
<li>MD5: $enc.html($related.Md5sum)</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
#end
|
#end
|
||||||
@@ -1007,11 +986,7 @@ Getting Help: <a href="https://groups.google.com/forum/#!forum/dependency-check"
|
|||||||
<div id="content$cnt" class="subsectioncontent standardsubsection">
|
<div id="content$cnt" class="subsectioncontent standardsubsection">
|
||||||
#foreach($vuln in $dependency.getSuppressedVulnerabilities())
|
#foreach($vuln in $dependency.getSuppressedVulnerabilities())
|
||||||
#set($vsctr=$vsctr+1)
|
#set($vsctr=$vsctr+1)
|
||||||
#if($vuln.getSource().name().equals("NVD"))
|
<p><b><a target="_blank" href="http://web.nvd.nist.gov/view/vuln/detail?vulnId=$enc.url($vuln.name)">$enc.html($vuln.name)</a></b> <span class="suppressedLabel" >suppressed</span></p>
|
||||||
<p><b><a target="_blank" href="http://web.nvd.nist.gov/view/vuln/detail?vulnId=$enc.url($vuln.name)">$enc.html($vuln.name)</a></b> <span class="suppressedLabel" >suppressed</span></p>
|
|
||||||
#elseif($vuln.getSource().name().equals("NSP"))
|
|
||||||
<p><b><a target="_blank" href="https://nodesecurity.io/advisories/$enc.url($vuln.name)">NSP-$enc.html($vuln.name)</a></b> <span class="suppressedLabel" >suppressed</span></p>
|
|
||||||
#end
|
|
||||||
<p>Severity:
|
<p>Severity:
|
||||||
#if ($vuln.cvssScore<4.0)
|
#if ($vuln.cvssScore<4.0)
|
||||||
Low
|
Low
|
||||||
@@ -1060,11 +1035,6 @@ Getting Help: <a href="https://groups.google.com/forum/#!forum/dependency-check"
|
|||||||
## END SUPPRESSED VULNERABILITIES
|
## END SUPPRESSED VULNERABILITIES
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div><br/><br/>This report contains data retrieved from the <a href="http://nvd.nist.gov">National Vulnerability Database</a>.</div>
|
||||||
<br/><br/>
|
|
||||||
This report contains data retrieved from the <a href="https://nvd.nist.gov">National Vulnerability Database</a>.
|
|
||||||
<br/>
|
|
||||||
This report may contain data retrieved from the <a href="https://nodesecurity.io">Node Security Platform</a>.
|
|
||||||
</div>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -131,7 +131,7 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
|||||||
table.lined tr:nth-child(even) {
|
table.lined tr:nth-child(even) {
|
||||||
background-color: #fbfbfb;
|
background-color: #fbfbfb;
|
||||||
}
|
}
|
||||||
th.name {
|
th.cve {
|
||||||
width: 60px;
|
width: 60px;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -200,7 +200,7 @@ have been reported. Additionally, the HTML report provides many features not fou
|
|||||||
#set($cnt=0)
|
#set($cnt=0)
|
||||||
<table id="vulnTable" class="lined">
|
<table id="vulnTable" class="lined">
|
||||||
<thead><tr>
|
<thead><tr>
|
||||||
<th class="name" data-sort="string">NAME</th>
|
<th class="cve" data-sort="string">CVE</th>
|
||||||
<th class="cwe" data-sort="string">CWE</th>
|
<th class="cwe" data-sort="string">CWE</th>
|
||||||
<th class="severity" data-sort="severity">Severity (CVSS)</th>
|
<th class="severity" data-sort="severity">Severity (CVSS)</th>
|
||||||
<th class="dependency" data-sort="string">Dependency</th>
|
<th class="dependency" data-sort="string">Dependency</th>
|
||||||
@@ -210,13 +210,7 @@ have been reported. Additionally, the HTML report provides many features not fou
|
|||||||
#if($dependency.getVulnerabilities().size()>0)
|
#if($dependency.getVulnerabilities().size()>0)
|
||||||
#foreach($vuln in $dependency.getVulnerabilities())
|
#foreach($vuln in $dependency.getVulnerabilities())
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td><a target="_blank" href="http://web.nvd.nist.gov/view/vuln/detail?vulnId=$enc.url($vuln.name)">$enc.html($vuln.name)</a></td>
|
||||||
#if($vuln.getSource().name().equals("NVD"))
|
|
||||||
<a target="_blank" href="http://web.nvd.nist.gov/view/vuln/detail?vulnId=$enc.url($vuln.name)">$enc.html($vuln.name)</a>
|
|
||||||
#elseif($vuln.getSource().name().equals("NSP"))
|
|
||||||
<a target="_blank" href="https://nodesecurity.io/advisories/$enc.url($vuln.name)">NSP-$enc.html($vuln.name)</a>
|
|
||||||
#end
|
|
||||||
</td>
|
|
||||||
<td>
|
<td>
|
||||||
#if ($vuln.cwe)
|
#if ($vuln.cwe)
|
||||||
$vuln.cwe
|
$vuln.cwe
|
||||||
@@ -247,11 +241,6 @@ have been reported. Additionally, the HTML report provides many features not fou
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<p>
|
<p><br/><br/>This report contains data retrieved from the <a href="http://nvd.nist.gov">National Vulnerability Database</a>.</p>
|
||||||
<br/><br/>
|
|
||||||
This report contains data retrieved from the <a href="https://nvd.nist.gov">National Vulnerability Database</a>.
|
|
||||||
<br/>
|
|
||||||
This report may contain data retrieved from the <a href="https://nodesecurity.io">Node Security Platform</a>.
|
|
||||||
</p>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -41,7 +41,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
<version>$enc.xml($version)</version>
|
<version>$enc.xml($version)</version>
|
||||||
#end
|
#end
|
||||||
<reportDate>$scanDateXML</reportDate>
|
<reportDate>$scanDateXML</reportDate>
|
||||||
<credits>This report contains data retrieved from the National Vulnerability Database: https://nvd.nist.gov and from the Node Security Platform: https://nodesecurity.io</credits>
|
<credits>This report contains data retrieved from the National Vulnerability Database: http://nvd.nist.gov</credits>
|
||||||
</projectInfo>
|
</projectInfo>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
#foreach($dependency in $dependencies)
|
#foreach($dependency in $dependencies)
|
||||||
@@ -61,18 +61,15 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
#foreach($related in $dependency.getRelatedDependencies())
|
#foreach($related in $dependency.getRelatedDependencies())
|
||||||
<relatedDependency>
|
<relatedDependency>
|
||||||
<filePath>$enc.xml($related.FilePath)</filePath>
|
<filePath>$enc.xml($related.FilePath)</filePath>
|
||||||
<sha1>#if($related.Sha1sum)$enc.xml($related.Sha1sum)#end</sha1>
|
<sha1>$enc.xml($related.Sha1sum)</sha1>
|
||||||
<md5>#if($related.Md5sum)$enc.xml($related.Md5sum)#end</md5>
|
<md5>$enc.xml($related.Md5sum)</md5>
|
||||||
#foreach($id in $related.getIdentifiers())
|
#foreach($id in $related.getIdentifiers())
|
||||||
#if ($id.type=="maven" || $id.type=="npm")
|
#if ($id.type=="maven")
|
||||||
<identifier type="$enc.xml($id.type)">
|
<identifier type="$enc.xml($id.type)">
|
||||||
<name>$enc.xml($id.value)</name>
|
<name>($id.value)</name>
|
||||||
#if( $id.url )
|
#if( $id.url )
|
||||||
<url>$enc.xml($id.url)</url>
|
<url>$enc.xml($id.url)</url>
|
||||||
#end
|
#end
|
||||||
#if( $id.description )
|
|
||||||
<description>$enc.xml($id.description)</description>
|
|
||||||
#end
|
|
||||||
#if ($id.notes)
|
#if ($id.notes)
|
||||||
<notes>$enc.xml($id.notes)</notes>
|
<notes>$enc.xml($id.notes)</notes>
|
||||||
#end
|
#end
|
||||||
@@ -142,14 +139,14 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
<vulnerabilities>
|
<vulnerabilities>
|
||||||
#foreach($vuln in $dependency.getVulnerabilities())
|
#foreach($vuln in $dependency.getVulnerabilities())
|
||||||
<vulnerability>
|
<vulnerability>
|
||||||
<name>#if($vuln.getSource().name().equals("NSP"))NSP-#end$enc.xml($vuln.name)</name>
|
<name>$enc.xml($vuln.name)</name>
|
||||||
<cvssScore>$vuln.cvssScore</cvssScore>
|
<cvssScore>$vuln.cvssScore</cvssScore>
|
||||||
<cvssAccessVector>#if($vuln.cvssAccessVector)$enc.xml($vuln.cvssAccessVector)#end</cvssAccessVector>
|
<cvssAccessVector>$enc.xml($vuln.cvssAccessVector)</cvssAccessVector>
|
||||||
<cvssAccessComplexity>#if($vuln.cvssAccessComplexity)$enc.xml($vuln.cvssAccessComplexity)#end</cvssAccessComplexity>
|
<cvssAccessComplexity>$enc.xml($vuln.cvssAccessComplexity)</cvssAccessComplexity>
|
||||||
<cvssAuthenticationr>#if($vuln.cvssAuthentication)$enc.xml($vuln.cvssAuthentication)#end</cvssAuthenticationr>
|
<cvssAuthenticationr>$enc.xml($vuln.cvssAuthentication)</cvssAuthenticationr>
|
||||||
<cvssConfidentialImpact>#if($vuln.cvssConfidentialityImpact)$enc.xml($vuln.cvssConfidentialityImpact)#end</cvssConfidentialImpact>
|
<cvssConfidentialImpact>$enc.xml($vuln.cvssConfidentialityImpact)</cvssConfidentialImpact>
|
||||||
<cvssIntegrityImpact>#if($vuln.cvssIntegrityImpact)$enc.xml($vuln.cvssIntegrityImpact)#end</cvssIntegrityImpact>
|
<cvssIntegrityImpact>$enc.xml($vuln.cvssIntegrityImpact)</cvssIntegrityImpact>
|
||||||
<cvssAvailabilityImpact>#if($vuln.cvssAvailabilityImpact)$enc.xml($vuln.cvssAvailabilityImpact)#end</cvssAvailabilityImpact>
|
<cvssAvailabilityImpact>$enc.xml($vuln.cvssAvailabilityImpact)</cvssAvailabilityImpact>
|
||||||
#if ($vuln.cvssScore<4.0)
|
#if ($vuln.cvssScore<4.0)
|
||||||
<severity>Low</severity>
|
<severity>Low</severity>
|
||||||
#elseif ($vuln.cvssScore>=7.0)
|
#elseif ($vuln.cvssScore>=7.0)
|
||||||
@@ -17,9 +17,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.owasp.dependencycheck;
|
package org.owasp.dependencycheck;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -60,31 +59,21 @@ public class EngineIT extends BaseDBTestCase {
|
|||||||
try {
|
try {
|
||||||
instance.analyzeDependencies();
|
instance.analyzeDependencies();
|
||||||
} catch (ExceptionCollection ex) {
|
} catch (ExceptionCollection ex) {
|
||||||
Set<String> allowedMessages = new HashSet<>();
|
if (ex.getExceptions().size() == 1
|
||||||
allowedMessages.add("bundle-audit");
|
&& (ex.getExceptions().get(0).getMessage().contains("bundle-audit")
|
||||||
allowedMessages.add("AssemblyAnalyzer");
|
|| ex.getExceptions().get(0).getMessage().contains("AssemblyAnalyzer"))) {
|
||||||
//allowedMessages.add("Unable to connect to");
|
//this is fine to ignore
|
||||||
for (Throwable t : ex.getExceptions()) {
|
} else if (ex.getExceptions().size() == 2
|
||||||
boolean isOk = false;
|
&& ((ex.getExceptions().get(0).getMessage().contains("bundle-audit")
|
||||||
if (t.getMessage()!=null) {
|
&& ex.getExceptions().get(1).getMessage().contains("AssemblyAnalyzer"))
|
||||||
for (String msg : allowedMessages) {
|
|| (ex.getExceptions().get(1).getMessage().contains("bundle-audit")
|
||||||
if (t.getMessage().contains(msg)) {
|
&& ex.getExceptions().get(0).getMessage().contains("AssemblyAnalyzer")))) {
|
||||||
isOk=true;
|
//this is fine to ignore
|
||||||
break;
|
} else {
|
||||||
}
|
throw ex;
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!isOk) {
|
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DatabaseProperties prop = null;
|
instance.writeReports("dependency-check sample", new File("./target/"), "ALL");
|
||||||
try (CveDB cve = CveDB.getInstance()) {
|
|
||||||
prop = cve.getDatabaseProperties();
|
|
||||||
}
|
|
||||||
ReportGenerator rg = new ReportGenerator("DependencyCheck", instance.getDependencies(), instance.getAnalyzers(), prop);
|
|
||||||
rg.generateReports("./target/", "ALL");
|
|
||||||
instance.cleanup();
|
instance.cleanup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,81 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 Steve Springett. All Rights Reserved.
|
|
||||||
*/
|
|
||||||
package org.owasp.dependencycheck.data.nsp;
|
|
||||||
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.owasp.dependencycheck.BaseTest;
|
|
||||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
|
||||||
import org.owasp.dependencycheck.utils.Settings;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import javax.json.Json;
|
|
||||||
import javax.json.JsonObject;
|
|
||||||
import javax.json.JsonObjectBuilder;
|
|
||||||
import javax.json.JsonReader;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.List;
|
|
||||||
import static org.junit.Assume.assumeFalse;
|
|
||||||
import org.owasp.dependencycheck.utils.URLConnectionFailureException;
|
|
||||||
|
|
||||||
public class NspSearchTest extends BaseTest {
|
|
||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(NspSearchTest.class);
|
|
||||||
private NspSearch searcher;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setUp() throws Exception {
|
|
||||||
String url = Settings.getString(Settings.KEYS.ANALYZER_NSP_URL);
|
|
||||||
LOGGER.debug(url);
|
|
||||||
searcher = new NspSearch(new URL(url));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testNspSearchPositive() throws Exception {
|
|
||||||
InputStream in = BaseTest.getResourceAsStream(this, "nsp/package.json");
|
|
||||||
try (JsonReader jsonReader = Json.createReader(in)) {
|
|
||||||
final JsonObject packageJson = jsonReader.readObject();
|
|
||||||
final JsonObject sanitizedJson = SanitizePackage.sanitize(packageJson);
|
|
||||||
final JsonObjectBuilder builder = Json.createObjectBuilder();
|
|
||||||
final JsonObject nspPayload = builder.add("package", sanitizedJson).build();
|
|
||||||
final List<Advisory> advisories = searcher.submitPackage(nspPayload);
|
|
||||||
Assert.assertTrue(advisories.size() > 0);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
assumeFalse(ex instanceof URLConnectionFailureException
|
|
||||||
&& ex.getMessage().contains("Unable to connect to "));
|
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = AnalysisException.class)
|
|
||||||
public void testNspSearchNegative() throws Exception {
|
|
||||||
InputStream in = BaseTest.getResourceAsStream(this, "nsp/package.json");
|
|
||||||
try (JsonReader jsonReader = Json.createReader(in)) {
|
|
||||||
final JsonObject packageJson = jsonReader.readObject();
|
|
||||||
final JsonObject sanitizedJson = SanitizePackage.sanitize(packageJson);
|
|
||||||
searcher.submitPackage(sanitizedJson);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
assumeFalse(ex instanceof URLConnectionFailureException
|
|
||||||
&& ex.getMessage().contains("Unable to connect to "));
|
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 Steve Springett. All Rights Reserved.
|
|
||||||
*/
|
|
||||||
package org.owasp.dependencycheck.data.nsp;
|
|
||||||
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
|
||||||
import javax.json.Json;
|
|
||||||
import javax.json.JsonObject;
|
|
||||||
import javax.json.JsonObjectBuilder;
|
|
||||||
|
|
||||||
public class SanitizePackageTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSanitizer() throws Exception {
|
|
||||||
JsonObjectBuilder builder = Json.createObjectBuilder();
|
|
||||||
builder
|
|
||||||
.add("name", "my app")
|
|
||||||
.add("version", "1.0.0")
|
|
||||||
.add("description", "my app does amazing things")
|
|
||||||
.add("keywords", "best, app, ever")
|
|
||||||
.add("homepage", "http://example.com")
|
|
||||||
.add("bugs", "http://example.com/bugs")
|
|
||||||
.add("license", "Apache-2.0")
|
|
||||||
.add("main", "myscript")
|
|
||||||
.add("dependencies", "{ \"foo\" : \"1.0.0 - 2.9999.9999\"}")
|
|
||||||
.add("devDependencies", "{ \"foo\" : \"1.0.0 - 2.9999.9999\"}")
|
|
||||||
.add("peerDependencies", "{ \"foo\" : \"1.0.0 - 2.9999.9999\"}")
|
|
||||||
.add("bundledDependencies", "{ \"foo\" : \"1.0.0 - 2.9999.9999\"}")
|
|
||||||
.add("optionalDependencies", "{ \"foo\" : \"1.0.0 - 2.9999.9999\"}");
|
|
||||||
|
|
||||||
JsonObject packageJson = builder.build();
|
|
||||||
JsonObject sanitized = SanitizePackage.sanitize(packageJson);
|
|
||||||
|
|
||||||
Assert.assertTrue(sanitized.containsKey("name"));
|
|
||||||
Assert.assertTrue(sanitized.containsKey("version"));
|
|
||||||
Assert.assertTrue(sanitized.containsKey("dependencies"));
|
|
||||||
Assert.assertTrue(sanitized.containsKey("devDependencies"));
|
|
||||||
Assert.assertTrue(sanitized.containsKey("peerDependencies"));
|
|
||||||
Assert.assertTrue(sanitized.containsKey("bundledDependencies"));
|
|
||||||
Assert.assertTrue(sanitized.containsKey("optionalDependencies"));
|
|
||||||
|
|
||||||
Assert.assertFalse(sanitized.containsKey("description"));
|
|
||||||
Assert.assertFalse(sanitized.containsKey("keywords"));
|
|
||||||
Assert.assertFalse(sanitized.containsKey("homepage"));
|
|
||||||
Assert.assertFalse(sanitized.containsKey("bugs"));
|
|
||||||
Assert.assertFalse(sanitized.containsKey("license"));
|
|
||||||
Assert.assertFalse(sanitized.containsKey("main"));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -25,15 +25,12 @@ import javax.xml.transform.stream.StreamSource;
|
|||||||
import javax.xml.validation.Schema;
|
import javax.xml.validation.Schema;
|
||||||
import javax.xml.validation.SchemaFactory;
|
import javax.xml.validation.SchemaFactory;
|
||||||
import javax.xml.validation.Validator;
|
import javax.xml.validation.Validator;
|
||||||
import static org.junit.Assert.fail;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.owasp.dependencycheck.BaseDBTestCase;
|
import org.owasp.dependencycheck.BaseDBTestCase;
|
||||||
import org.owasp.dependencycheck.BaseTest;
|
import org.owasp.dependencycheck.BaseTest;
|
||||||
import org.owasp.dependencycheck.Engine;
|
import org.owasp.dependencycheck.Engine;
|
||||||
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
|
||||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
||||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
|
|
||||||
import org.owasp.dependencycheck.exception.ExceptionCollection;
|
import org.owasp.dependencycheck.exception.ExceptionCollection;
|
||||||
import org.owasp.dependencycheck.exception.ReportException;
|
import org.owasp.dependencycheck.exception.ReportException;
|
||||||
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
||||||
@@ -47,67 +44,6 @@ import static org.junit.Assert.fail;
|
|||||||
*/
|
*/
|
||||||
public class ReportGeneratorIT extends BaseDBTestCase {
|
public class ReportGeneratorIT extends BaseDBTestCase {
|
||||||
|
|
||||||
/**
|
|
||||||
* Test of generateReport method, of class ReportGenerator.
|
|
||||||
*
|
|
||||||
* @throws Exception is thrown when an exception occurs.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testGenerateReport() throws Exception {
|
|
||||||
// String templateName = "HtmlReport";
|
|
||||||
// File f = new File("target/test-reports");
|
|
||||||
// if (!f.exists()) {
|
|
||||||
// f.mkdir();
|
|
||||||
// }
|
|
||||||
// String writeTo = "target/test-reports/Report.html";
|
|
||||||
// Map<String, Object> properties = new HashMap<String, Object>();
|
|
||||||
// Dependency d = new Dependency();
|
|
||||||
// d.setFileName("FileName.jar");
|
|
||||||
// d.setActualFilePath("lib/FileName.jar");
|
|
||||||
// d.addCPEentry("cpe://a:/some:cpe:1.0");
|
|
||||||
//
|
|
||||||
// List<Dependency> dependencies = new ArrayList<Dependency>();
|
|
||||||
// d.getProductEvidence().addEvidence("jar","filename","<test>test", Confidence.HIGH);
|
|
||||||
// d.getProductEvidence().addEvidence("manifest","vendor","<test>test", Confidence.HIGH);
|
|
||||||
//
|
|
||||||
// for (Evidence e : d.getProductEvidence().iterator(Confidence.HIGH)) {
|
|
||||||
// String t = e.getValue();
|
|
||||||
// }
|
|
||||||
// dependencies.add(d);
|
|
||||||
//
|
|
||||||
// Dependency d2 = new Dependency();
|
|
||||||
// d2.setFileName("Another.jar");
|
|
||||||
// d2.setActualFilePath("lib/Another.jar");
|
|
||||||
// d2.addCPEentry("cpe://a:/another:cpe:1.0");
|
|
||||||
// d2.addCPEentry("cpe://a:/another:cpe:1.1");
|
|
||||||
// d2.addCPEentry("cpe://a:/another:cpe:1.2");
|
|
||||||
// d2.getProductEvidence().addEvidence("jar","filename","another.jar", Confidence.HIGH);
|
|
||||||
// d2.getProductEvidence().addEvidence("manifest","vendor","Company A", Confidence.MEDIUM);
|
|
||||||
//
|
|
||||||
// for (Evidence e : d2.getProductEvidence().iterator(Confidence.HIGH)) {
|
|
||||||
// String t = e.getValue();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// dependencies.add(d2);
|
|
||||||
//
|
|
||||||
// Dependency d3 = new Dependency();
|
|
||||||
// d3.setFileName("Third.jar");
|
|
||||||
// d3.setActualFilePath("lib/Third.jar");
|
|
||||||
// d3.getProductEvidence().addEvidence("jar","filename","third.jar", Confidence.HIGH);
|
|
||||||
//
|
|
||||||
// for (Evidence e : d3.getProductEvidence().iterator(Confidence.HIGH)) {
|
|
||||||
// String t = e.getValue();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// dependencies.add(d3);
|
|
||||||
//
|
|
||||||
// properties.put("dependencies",dependencies);
|
|
||||||
//
|
|
||||||
// ReportGenerator instance = new ReportGenerator();
|
|
||||||
// instance.generateReport(templateName, writeTo, properties);
|
|
||||||
//assertTrue("need to add a real check here", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates an XML report containing known vulnerabilities and realistic
|
* Generates an XML report containing known vulnerabilities and realistic
|
||||||
* data and validates the generated XML document against the XSD.
|
* data and validates the generated XML document against the XSD.
|
||||||
@@ -115,7 +51,7 @@ public class ReportGeneratorIT extends BaseDBTestCase {
|
|||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testGenerateXMLReport() {
|
public void testGenerateReport() {
|
||||||
try {
|
try {
|
||||||
String templateName = "XmlReport";
|
String templateName = "XmlReport";
|
||||||
|
|
||||||
@@ -123,7 +59,7 @@ public class ReportGeneratorIT extends BaseDBTestCase {
|
|||||||
if (!f.exists()) {
|
if (!f.exists()) {
|
||||||
f.mkdir();
|
f.mkdir();
|
||||||
}
|
}
|
||||||
String writeTo = "target/test-reports/Report.xml";
|
File writeTo = new File("target/test-reports/Report.xml");
|
||||||
File suppressionFile = BaseTest.getResourceAsFile(this, "incorrectSuppressions.xml");
|
File suppressionFile = BaseTest.getResourceAsFile(this, "incorrectSuppressions.xml");
|
||||||
|
|
||||||
Settings.setString(Settings.KEYS.SUPPRESSION_FILE, suppressionFile.getAbsolutePath());
|
Settings.setString(Settings.KEYS.SUPPRESSION_FILE, suppressionFile.getAbsolutePath());
|
||||||
@@ -135,29 +71,20 @@ public class ReportGeneratorIT extends BaseDBTestCase {
|
|||||||
//File jetty = new File(this.getClass().getClassLoader().getResource("org.mortbay.jetty.jar").getPath());
|
//File jetty = new File(this.getClass().getClassLoader().getResource("org.mortbay.jetty.jar").getPath());
|
||||||
File jetty = BaseTest.getResourceAsFile(this, "org.mortbay.jetty.jar");
|
File jetty = BaseTest.getResourceAsFile(this, "org.mortbay.jetty.jar");
|
||||||
|
|
||||||
boolean autoUpdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE);
|
|
||||||
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, false);
|
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, false);
|
||||||
Engine engine = new Engine();
|
Engine engine = new Engine();
|
||||||
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
|
|
||||||
|
|
||||||
engine.scan(struts);
|
engine.scan(struts);
|
||||||
engine.scan(axis);
|
engine.scan(axis);
|
||||||
engine.scan(jetty);
|
engine.scan(jetty);
|
||||||
engine.analyzeDependencies();
|
engine.analyzeDependencies();
|
||||||
|
engine.writeReports("Test Report", "org.owasp", "dependency-check-core", "1.4.7", writeTo, "XML");
|
||||||
CveDB cveDB = CveDB.getInstance();
|
|
||||||
DatabaseProperties dbProp = cveDB.getDatabaseProperties();
|
|
||||||
|
|
||||||
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();
|
engine.cleanup();
|
||||||
|
|
||||||
InputStream xsdStream = ReportGenerator.class.getClassLoader().getResourceAsStream("schema/dependency-check.1.5.xsd");
|
InputStream xsdStream = ReportGenerator.class.getClassLoader().getResourceAsStream("schema/dependency-check.1.5.xsd");
|
||||||
StreamSource xsdSource = new StreamSource(xsdStream);
|
StreamSource xsdSource = new StreamSource(xsdStream);
|
||||||
StreamSource xmlSource = new StreamSource(new File(writeTo));
|
StreamSource xmlSource = new StreamSource(writeTo);
|
||||||
SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
|
SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
|
||||||
Schema schema = sf.newSchema(xsdSource);
|
Schema schema = sf.newSchema(xsdSource);
|
||||||
Validator validator = schema.newValidator();
|
Validator validator = schema.newValidator();
|
||||||
|
|||||||
@@ -73,9 +73,6 @@ analyzer.nexus.proxy=true
|
|||||||
analyzer.central.enabled=true
|
analyzer.central.enabled=true
|
||||||
analyzer.central.url=https://search.maven.org/solrsearch/select
|
analyzer.central.url=https://search.maven.org/solrsearch/select
|
||||||
|
|
||||||
# the URL for searching api.nodesecurity.io
|
|
||||||
analyzer.nsp.url=https://api.nodesecurity.io/check
|
|
||||||
|
|
||||||
# the number of nested archives that will be searched.
|
# the number of nested archives that will be searched.
|
||||||
archive.scan.depth=3
|
archive.scan.depth=3
|
||||||
|
|
||||||
@@ -87,7 +84,6 @@ analyzer.experimental.enabled=true
|
|||||||
analyzer.jar.enabled=true
|
analyzer.jar.enabled=true
|
||||||
analyzer.archive.enabled=true
|
analyzer.archive.enabled=true
|
||||||
analyzer.node.package.enabled=true
|
analyzer.node.package.enabled=true
|
||||||
analyzer.nsp.package.enabled=true
|
|
||||||
analyzer.composer.lock.enabled=true
|
analyzer.composer.lock.enabled=true
|
||||||
analyzer.python.distribution.enabled=true
|
analyzer.python.distribution.enabled=true
|
||||||
analyzer.python.package.enabled=true
|
analyzer.python.package.enabled=true
|
||||||
|
|||||||
@@ -1,59 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "owasp-nodejs-goat",
|
|
||||||
"private": true,
|
|
||||||
"version": "1.3.0",
|
|
||||||
"description": "A tool to learn OWASP Top 10 for node.js developers",
|
|
||||||
"main": "server.js",
|
|
||||||
"dependencies": {
|
|
||||||
"bcrypt-nodejs": "0.0.3",
|
|
||||||
"body-parser": "^1.15.1",
|
|
||||||
"consolidate": "^0.14.1",
|
|
||||||
"csurf": "^1.8.3",
|
|
||||||
"dont-sniff-mimetype": "^1.0.0",
|
|
||||||
"express": "^4.13.4",
|
|
||||||
"express-session": "^1.13.0",
|
|
||||||
"forever": "^0.15.1",
|
|
||||||
"helmet": "^2.0.0",
|
|
||||||
"marked": "0.3.5",
|
|
||||||
"mongodb": "^2.1.18",
|
|
||||||
"serve-favicon": "^2.3.0",
|
|
||||||
"swig": "^1.4.2",
|
|
||||||
"underscore": "^1.8.3"
|
|
||||||
},
|
|
||||||
"comments": {
|
|
||||||
"//": "do not upgrade the marked package version it is set by purpose",
|
|
||||||
"//": "to be a vulnerable package to demonstrate an xss introduced through",
|
|
||||||
"//": "a9 insecure components"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": "4.4.x",
|
|
||||||
"npm": "2.15.x"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"start": "node server.js",
|
|
||||||
"test": "node node_modules/grunt-cli/bin/grunt test",
|
|
||||||
"db:seed": "grunt db-reset",
|
|
||||||
"precommit": "grunt precommit"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"async": "^2.0.0-rc.4",
|
|
||||||
"grunt": "^1.0.1",
|
|
||||||
"grunt-cli": "^1.2.0",
|
|
||||||
"grunt-concurrent": "^2.3.0",
|
|
||||||
"grunt-contrib-jshint": "^1.0.0",
|
|
||||||
"grunt-contrib-watch": "^1.0.0",
|
|
||||||
"grunt-env": "latest",
|
|
||||||
"grunt-jsbeautifier": "^0.2.12",
|
|
||||||
"grunt-mocha-test": "^0.12.7",
|
|
||||||
"grunt-nodemon": "^0.4.2",
|
|
||||||
"grunt-if": "https://github.com/binarymist/grunt-if/tarball/master",
|
|
||||||
"grunt-npm-install": "^0.3.0",
|
|
||||||
"grunt-retire": "^0.3.12",
|
|
||||||
"mocha": "^2.4.5",
|
|
||||||
"selenium-webdriver": "^2.53.2",
|
|
||||||
"should": "^8.3.1",
|
|
||||||
"zaproxy": "^0.2.0"
|
|
||||||
},
|
|
||||||
"repository": "https://github.com/OWASP/NodejsGoat",
|
|
||||||
"license": "Apache 2.0"
|
|
||||||
}
|
|
||||||
@@ -123,7 +123,8 @@ public class AggregateMojo extends BaseDependencyCheckMojo {
|
|||||||
outputDir = new File(this.getProject().getBuild().getDirectory());
|
outputDir = new File(this.getProject().getBuild().getDirectory());
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
writeReports(engine, this.getProject(), outputDir);
|
final MavenProject p = this.getProject();
|
||||||
|
engine.writeReports(p.getName(), p.getGroupId(), p.getArtifactId(), p.getVersion(), outputDir, getFormat());
|
||||||
} catch (ReportException ex) {
|
} catch (ReportException ex) {
|
||||||
if (exCol == null) {
|
if (exCol == null) {
|
||||||
exCol = new ExceptionCollection("Error writing aggregate report", ex);
|
exCol = new ExceptionCollection("Error writing aggregate report", ex);
|
||||||
|
|||||||
@@ -1069,35 +1069,6 @@ public abstract class BaseDependencyCheckMojo extends AbstractMojo implements Ma
|
|||||||
return format;
|
return format;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates the reports for a given dependency-check engine.
|
|
||||||
*
|
|
||||||
* @param engine a dependency-check engine
|
|
||||||
* @param p the Maven project
|
|
||||||
* @param outputDir the directory path to write the report(s)
|
|
||||||
* @throws ReportException thrown if there is an error writing the report
|
|
||||||
*/
|
|
||||||
protected void writeReports(Engine engine, MavenProject p, File outputDir) throws ReportException {
|
|
||||||
DatabaseProperties prop = null;
|
|
||||||
try (CveDB cve = CveDB.getInstance()) {
|
|
||||||
prop = cve.getDatabaseProperties();
|
|
||||||
} catch (DatabaseException ex) {
|
|
||||||
//TODO shouldn't this throw an exception?
|
|
||||||
if (getLog().isDebugEnabled()) {
|
|
||||||
getLog().debug("Unable to retrieve DB Properties", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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) {
|
|
||||||
final String msg = String.format("Error generating the report for %s", p.getName());
|
|
||||||
throw new ReportException(msg, ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//<editor-fold defaultstate="collapsed" desc="Methods to fail build or show summary">
|
//<editor-fold defaultstate="collapsed" desc="Methods to fail build or show summary">
|
||||||
/**
|
/**
|
||||||
* Checks to see if a vulnerability has been identified with a CVSS score
|
* Checks to see if a vulnerability has been identified with a CVSS score
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import org.apache.maven.plugins.annotations.LifecyclePhase;
|
|||||||
import org.apache.maven.plugins.annotations.Mojo;
|
import org.apache.maven.plugins.annotations.Mojo;
|
||||||
import org.apache.maven.plugins.annotations.Parameter;
|
import org.apache.maven.plugins.annotations.Parameter;
|
||||||
import org.apache.maven.plugins.annotations.ResolutionScope;
|
import org.apache.maven.plugins.annotations.ResolutionScope;
|
||||||
|
import org.apache.maven.project.MavenProject;
|
||||||
import org.owasp.dependencycheck.Engine;
|
import org.owasp.dependencycheck.Engine;
|
||||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
||||||
import org.owasp.dependencycheck.exception.ExceptionCollection;
|
import org.owasp.dependencycheck.exception.ExceptionCollection;
|
||||||
@@ -99,19 +100,19 @@ public class CheckMojo extends BaseDependencyCheckMojo {
|
|||||||
ExceptionCollection exCol = scanArtifacts(getProject(), engine);
|
ExceptionCollection exCol = scanArtifacts(getProject(), engine);
|
||||||
if (engine.getDependencies().isEmpty()) {
|
if (engine.getDependencies().isEmpty()) {
|
||||||
getLog().info("No dependencies were identified that could be analyzed by dependency-check");
|
getLog().info("No dependencies were identified that could be analyzed by dependency-check");
|
||||||
} else {
|
}
|
||||||
try {
|
try {
|
||||||
engine.analyzeDependencies();
|
engine.analyzeDependencies();
|
||||||
} catch (ExceptionCollection ex) {
|
} catch (ExceptionCollection ex) {
|
||||||
if (this.isFailOnError() && ex.isFatal()) {
|
if (this.isFailOnError() && ex.isFatal()) {
|
||||||
throw new MojoExecutionException("One or more exceptions occurred during analysis", ex);
|
throw new MojoExecutionException("One or more exceptions occurred during analysis", ex);
|
||||||
}
|
|
||||||
exCol = ex;
|
|
||||||
}
|
}
|
||||||
|
exCol = ex;
|
||||||
}
|
}
|
||||||
if (exCol == null || !exCol.isFatal()) {
|
if (exCol == null || !exCol.isFatal()) {
|
||||||
try {
|
try {
|
||||||
writeReports(engine, getProject(), getCorrectOutputDirectory());
|
final MavenProject p = this.getProject();
|
||||||
|
engine.writeReports(p.getName(), p.getGroupId(), p.getArtifactId(), p.getVersion(), getCorrectOutputDirectory(), getFormat());
|
||||||
} catch (ReportException ex) {
|
} catch (ReportException ex) {
|
||||||
if (this.isFailOnError()) {
|
if (this.isFailOnError()) {
|
||||||
if (exCol != null) {
|
if (exCol != null) {
|
||||||
|
|||||||
@@ -258,14 +258,6 @@ public final class Settings {
|
|||||||
* enabled.
|
* enabled.
|
||||||
*/
|
*/
|
||||||
public static final String ANALYZER_NODE_PACKAGE_ENABLED = "analyzer.node.package.enabled";
|
public static final String ANALYZER_NODE_PACKAGE_ENABLED = "analyzer.node.package.enabled";
|
||||||
/**
|
|
||||||
* The properties key for whether the Node Security Platform (nsp) analyzer is enabled.
|
|
||||||
*/
|
|
||||||
public static final String ANALYZER_NSP_PACKAGE_ENABLED = "analyzer.nsp.package.enabled";
|
|
||||||
/**
|
|
||||||
* The properties key for whether the Nexus analyzer is enabled.
|
|
||||||
*/
|
|
||||||
public static final String ANALYZER_NSP_URL = "analyzer.nsp.url";
|
|
||||||
/**
|
/**
|
||||||
* The properties key for whether the composer lock file analyzer is
|
* The properties key for whether the composer lock file analyzer is
|
||||||
* enabled.
|
* enabled.
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ To setup a centralized database the following generalized steps can be used:
|
|||||||
<ol><li>Create the database and tables using either <a href="https://github.com/jeremylong/DependencyCheck/blob/master/dependency-check-core/src/main/resources/data/initialize.sql">initialize.sql</a>
|
<ol><li>Create the database and tables using either <a href="https://github.com/jeremylong/DependencyCheck/blob/master/dependency-check-core/src/main/resources/data/initialize.sql">initialize.sql</a>
|
||||||
or one of the other initialization scripts <a href="https://github.com/jeremylong/DependencyCheck/tree/master/dependency-check-core/src/main/resources/data">found here</a>.</li>
|
or one of the other initialization scripts <a href="https://github.com/jeremylong/DependencyCheck/tree/master/dependency-check-core/src/main/resources/data">found here</a>.</li>
|
||||||
<li>The account that the clients will connect using must have select granted on the tables.
|
<li>The account that the clients will connect using must have select granted on the tables.
|
||||||
<ul><li>Note, if the clients performing the scans should run with the noupdate setting. A single
|
<ul><li>Note, the clients performing the scans should run with the noupdate setting. A single
|
||||||
instance of the dependency-check client should be setup with update enabled and the account
|
instance of the dependency-check client should be setup with updates enabled and the account
|
||||||
used during the update process will need to be granted update rights on the tables.
|
used during the update process will need to be granted update rights on the tables.
|
||||||
</li></ul>
|
</li></ul>
|
||||||
</li><li>Dependency-check clients running scans will need to be configured to use the central database:
|
</li><li>Dependency-check clients running scans will need to be configured to use the central database:
|
||||||
|
|||||||
Reference in New Issue
Block a user