mirror of
https://github.com/ysoftdevs/DependencyCheck.git
synced 2026-01-16 00:33:46 +01:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dea5a6937e | ||
|
|
545c324e56 | ||
|
|
535d1e4aff | ||
|
|
8debea384f | ||
|
|
a0b6b66a5f | ||
|
|
37d165d6cb | ||
|
|
5b6eb13cf6 | ||
|
|
5d68c9f1e1 | ||
|
|
faff34a8c6 | ||
|
|
c31be72c8a | ||
|
|
1f0c13b7cb | ||
|
|
f06f1d1c42 | ||
|
|
2eca1f9702 | ||
|
|
ca6cb8811e | ||
|
|
ff14d8344f | ||
|
|
bfb6373742 | ||
|
|
e3f401debb | ||
|
|
c515afd8eb | ||
|
|
e028641861 | ||
|
|
72f9cb2ab2 | ||
|
|
e8694de6fa | ||
|
|
18d38592d4 | ||
|
|
b9767acd02 | ||
|
|
c9060da46e | ||
|
|
ddbcea7abe |
@@ -3,11 +3,11 @@ Copyright (c) 2012-2013 Jeremy Long. All Rights Reserved.
|
|||||||
|
|
||||||
The licenses for the software listed below can be found in the META-INF/licenses/[dependency name].
|
The licenses for the software listed below can be found in the META-INF/licenses/[dependency name].
|
||||||
|
|
||||||
This product includes software developed by
|
This product includes software developed by The Apache Software Foundation (http://www.apache.org/).
|
||||||
The Apache Software Foundation (http://www.apache.org/).
|
|
||||||
|
|
||||||
This product includes software developed by
|
This product includes software developed by Jquery.com (http://jquery.com/).
|
||||||
Jquery.com (http://jquery.com/).
|
|
||||||
|
This product includs software developed by Jonathan Hedley (jsoup.org)
|
||||||
|
|
||||||
This software contains unmodified binary redistributions for H2 database engine (http://www.h2database.com/), which is dual licensed and available under a modified version of the MPL 1.1 (Mozilla Public License) or under the (unmodified) EPL 1.0 (Eclipse Public License).
|
This software contains unmodified binary redistributions for H2 database engine (http://www.h2database.com/), which is dual licensed and available under a modified version of the MPL 1.1 (Mozilla Public License) or under the (unmodified) EPL 1.0 (Eclipse Public License).
|
||||||
An original copy of the license agreement can be found at: http://www.h2database.com/html/license.html
|
An original copy of the license agreement can be found at: http://www.h2database.com/html/license.html
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
DependencyCheck
|
Dependency-Check
|
||||||
=========
|
=========
|
||||||
|
|
||||||
DependencyCheck is a utility that attempts to detect publicly disclosed vulnerabilities contained within project dependencies. It does this by determining if there is a Common Platform Enumeration (CPE) identifier for a given dependency. If found, it will generate a report linking to the associated CVE entries..
|
Dependency-Check is a utility that attempts to detect publicly disclosed vulnerabilities contained within project dependencies. It does this by determining if there is a Common Platform Enumeration (CPE) identifier for a given dependency. If found, it will generate a report linking to the associated CVE entries.
|
||||||
|
|
||||||
More information can be found on the [wiki].
|
More information can be found on the [wiki].
|
||||||
|
|
||||||
|
|||||||
8
pom.xml
8
pom.xml
@@ -22,7 +22,7 @@ along with DependencyCheck. If not, see <http://www.gnu.org/licenses />.
|
|||||||
|
|
||||||
<groupId>org.owasp</groupId>
|
<groupId>org.owasp</groupId>
|
||||||
<artifactId>dependency-check</artifactId>
|
<artifactId>dependency-check</artifactId>
|
||||||
<version>0.3.2.0</version>
|
<version>0.3.2.2</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>DependencyCheck</name>
|
<name>DependencyCheck</name>
|
||||||
@@ -503,6 +503,12 @@ along with DependencyCheck. If not, see <http://www.gnu.org/licenses />.
|
|||||||
<artifactId>h2</artifactId>
|
<artifactId>h2</artifactId>
|
||||||
<version>1.3.172</version>
|
<version>1.3.172</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jsoup</groupId>
|
||||||
|
<artifactId>jsoup</artifactId>
|
||||||
|
<version>1.7.2</version>
|
||||||
|
<type>jar</type>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- The following dependencies are only scanned during integration testing -->
|
<!-- The following dependencies are only scanned during integration testing -->
|
||||||
<!--<dependency>
|
<!--<dependency>
|
||||||
|
|||||||
@@ -23,8 +23,12 @@ import java.util.HashSet;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.ListIterator;
|
import java.util.ListIterator;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
import org.owasp.dependencycheck.Engine;
|
import org.owasp.dependencycheck.Engine;
|
||||||
import org.owasp.dependencycheck.dependency.Dependency;
|
import org.owasp.dependencycheck.dependency.Dependency;
|
||||||
|
import org.owasp.dependencycheck.utils.DependencyVersion;
|
||||||
|
import org.owasp.dependencycheck.utils.DependencyVersionUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>This analyzer ensures dependencies that should be grouped together, to
|
* <p>This analyzer ensures dependencies that should be grouped together, to
|
||||||
@@ -51,6 +55,10 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
|||||||
* The phase that this analyzer is intended to run in.
|
* The phase that this analyzer is intended to run in.
|
||||||
*/
|
*/
|
||||||
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.PRE_FINDING_ANALYSIS;
|
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.PRE_FINDING_ANALYSIS;
|
||||||
|
/**
|
||||||
|
* A pattern for obtaining the first part of a filename.
|
||||||
|
*/
|
||||||
|
private static final Pattern STARTING_TEXT_PATTERN = Pattern.compile("^[a-zA-Z]*");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of file EXTENSIONS supported by this analyzer.
|
* Returns a list of file EXTENSIONS supported by this analyzer.
|
||||||
@@ -118,7 +126,8 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
|||||||
final Dependency nextDependency = subIterator.next();
|
final Dependency nextDependency = subIterator.next();
|
||||||
|
|
||||||
if (identifiersMatch(dependency, nextDependency)
|
if (identifiersMatch(dependency, nextDependency)
|
||||||
&& hasSameBasePath(dependency, nextDependency)) {
|
&& hasSameBasePath(dependency, nextDependency)
|
||||||
|
&& fileNameMatch(dependency, nextDependency)) {
|
||||||
|
|
||||||
if (isCore(dependency, nextDependency)) {
|
if (isCore(dependency, nextDependency)) {
|
||||||
dependency.addRelatedDependency(nextDependency);
|
dependency.addRelatedDependency(nextDependency);
|
||||||
@@ -179,6 +188,38 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
|||||||
return path.substring(0, pos);
|
return path.substring(0, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the file names (and version if it exists) of the two
|
||||||
|
* dependencies are sufficiently similiar.
|
||||||
|
* @param dependency1 a dependency2 to compare
|
||||||
|
* @param dependency2 a dependency2 to compare
|
||||||
|
* @return true if the identifiers in the two supplied dependencies are equal
|
||||||
|
*/
|
||||||
|
private boolean fileNameMatch(Dependency dependency1, Dependency dependency2) {
|
||||||
|
if (dependency1 == null || dependency1.getFileName() == null
|
||||||
|
|| dependency2 == null || dependency2.getFileName() == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final String fileName1 = dependency1.getFileName();
|
||||||
|
final String fileName2 = dependency2.getFileName();
|
||||||
|
//version check
|
||||||
|
final DependencyVersion version1 = DependencyVersionUtil.parseVersionFromFileName(fileName1);
|
||||||
|
final DependencyVersion version2 = DependencyVersionUtil.parseVersionFromFileName(fileName2);
|
||||||
|
if (version1 != null && version2 != null) {
|
||||||
|
if (!version1.equals(version2)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//filename check
|
||||||
|
final Matcher match1 = STARTING_TEXT_PATTERN.matcher(fileName1);
|
||||||
|
final Matcher match2 = STARTING_TEXT_PATTERN.matcher(fileName2);
|
||||||
|
if (match1.find() && match2.find()) {
|
||||||
|
return match1.group().equals(match2.group());
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the identifiers in the two supplied dependencies are equal.
|
* Returns true if the identifiers in the two supplied dependencies are equal.
|
||||||
* @param dependency1 a dependency2 to compare
|
* @param dependency1 a dependency2 to compare
|
||||||
|
|||||||
@@ -102,6 +102,7 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
|||||||
*/
|
*/
|
||||||
public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
|
public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
|
||||||
removeJreEntries(dependency);
|
removeJreEntries(dependency);
|
||||||
|
removeBadMatches(dependency);
|
||||||
boolean deepScan = false;
|
boolean deepScan = false;
|
||||||
try {
|
try {
|
||||||
deepScan = Settings.getBoolean(Settings.KEYS.PERFORM_DEEP_SCAN);
|
deepScan = Settings.getBoolean(Settings.KEYS.PERFORM_DEEP_SCAN);
|
||||||
@@ -182,7 +183,10 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
|||||||
final Iterator<Identifier> itr = identifiers.iterator();
|
final Iterator<Identifier> itr = identifiers.iterator();
|
||||||
while (itr.hasNext()) {
|
while (itr.hasNext()) {
|
||||||
final Identifier i = itr.next();
|
final Identifier i = itr.next();
|
||||||
|
|
||||||
if ((i.getValue().startsWith("cpe:/a:sun:java:")
|
if ((i.getValue().startsWith("cpe:/a:sun:java:")
|
||||||
|
|| i.getValue().startsWith("cpe:/a:sun:java_se")
|
||||||
|
|| i.getValue().startsWith("cpe:/a:oracle:java_se")
|
||||||
|| i.getValue().startsWith("cpe:/a:oracle:jre")
|
|| i.getValue().startsWith("cpe:/a:oracle:jre")
|
||||||
|| i.getValue().startsWith("cpe:/a:oracle:jdk"))
|
|| i.getValue().startsWith("cpe:/a:oracle:jdk"))
|
||||||
&& !dependency.getFileName().toLowerCase().endsWith("rt.jar")) {
|
&& !dependency.getFileName().toLowerCase().endsWith("rt.jar")) {
|
||||||
@@ -210,4 +214,24 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
|||||||
}
|
}
|
||||||
return cpe;
|
return cpe;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes bad CPE matches for a dependency. Unfortunately, right now
|
||||||
|
* these are hard-coded patches for specific problems identified when
|
||||||
|
* testing this ona LARGE volume of jar files.
|
||||||
|
* @param dependency the dependency to analyze
|
||||||
|
*/
|
||||||
|
private void removeBadMatches(Dependency dependency) {
|
||||||
|
final Set<Identifier> identifiers = dependency.getIdentifiers();
|
||||||
|
final Iterator<Identifier> itr = identifiers.iterator();
|
||||||
|
while (itr.hasNext()) {
|
||||||
|
final Identifier i = itr.next();
|
||||||
|
//TODO move this startswith expression to a configuration file?
|
||||||
|
if (i.getValue().startsWith("cpe:/a:apache:xerces-c++:")
|
||||||
|
&& dependency.getFileName().toLowerCase().endsWith(".jar")) {
|
||||||
|
itr.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,11 +19,11 @@
|
|||||||
package org.owasp.dependencycheck.analyzer;
|
package org.owasp.dependencycheck.analyzer;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import javax.xml.bind.JAXBException;
|
import javax.xml.bind.JAXBException;
|
||||||
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
import org.owasp.dependencycheck.Engine;
|
import org.owasp.dependencycheck.Engine;
|
||||||
import org.owasp.dependencycheck.dependency.Dependency;
|
import org.owasp.dependencycheck.dependency.Dependency;
|
||||||
import org.owasp.dependencycheck.dependency.Evidence;
|
import org.owasp.dependencycheck.dependency.Evidence;
|
||||||
@@ -39,19 +39,28 @@ import java.util.Properties;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import java.util.jar.Attributes;
|
import java.util.jar.Attributes;
|
||||||
|
import java.util.jar.JarEntry;
|
||||||
import java.util.jar.JarFile;
|
import java.util.jar.JarFile;
|
||||||
import java.util.jar.Manifest;
|
import java.util.jar.Manifest;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipInputStream;
|
|
||||||
import javax.xml.bind.JAXBContext;
|
import javax.xml.bind.JAXBContext;
|
||||||
import javax.xml.bind.JAXBElement;
|
import javax.xml.bind.JAXBElement;
|
||||||
import javax.xml.bind.Unmarshaller;
|
import javax.xml.bind.Unmarshaller;
|
||||||
|
import javax.xml.parsers.SAXParser;
|
||||||
|
import javax.xml.parsers.SAXParserFactory;
|
||||||
|
import javax.xml.transform.sax.SAXSource;
|
||||||
|
import org.jsoup.Jsoup;
|
||||||
|
import org.owasp.dependencycheck.analyzer.pom.MavenNamespaceFilter;
|
||||||
import org.owasp.dependencycheck.analyzer.pom.generated.License;
|
import org.owasp.dependencycheck.analyzer.pom.generated.License;
|
||||||
import org.owasp.dependencycheck.analyzer.pom.generated.Model;
|
import org.owasp.dependencycheck.analyzer.pom.generated.Model;
|
||||||
import org.owasp.dependencycheck.analyzer.pom.generated.Organization;
|
import org.owasp.dependencycheck.analyzer.pom.generated.Organization;
|
||||||
import org.owasp.dependencycheck.utils.NonClosingStream;
|
import org.owasp.dependencycheck.utils.NonClosingStream;
|
||||||
import org.owasp.dependencycheck.utils.Settings;
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
import org.xml.sax.InputSource;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
import org.xml.sax.XMLFilter;
|
||||||
|
import org.xml.sax.XMLReader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -99,7 +108,8 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
|
|||||||
"class-path",
|
"class-path",
|
||||||
"tool",
|
"tool",
|
||||||
"bundle-manifestversion",
|
"bundle-manifestversion",
|
||||||
"bundlemanifestversion");
|
"bundlemanifestversion",
|
||||||
|
"include-resource");
|
||||||
/**
|
/**
|
||||||
* The set of file extensions supported by this analyzer.
|
* The set of file extensions supported by this analyzer.
|
||||||
*/
|
*/
|
||||||
@@ -207,6 +217,10 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
|
|||||||
throw new AnalysisException("Exception occurred reading the JAR file.", ex);
|
throw new AnalysisException("Exception occurred reading the JAR file.", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* A pattern to detect HTML within text.
|
||||||
|
*/
|
||||||
|
private static final Pattern HTML_DETECTION_PATTERN = Pattern.compile("\\<[a-z]+.*/?\\>", Pattern.CASE_INSENSITIVE);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to find a pom.xml within the JAR file. If found it extracts
|
* Attempts to find a pom.xml within the JAR file. If found it extracts
|
||||||
@@ -214,157 +228,225 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
|
|||||||
* the strings contained within the pom.properties if one exists.
|
* the strings contained within the pom.properties if one exists.
|
||||||
*
|
*
|
||||||
* @param dependency the dependency being analyzed.
|
* @param dependency the dependency being analyzed.
|
||||||
* @throws IOException is thrown if there is an error reading the zip file.
|
* @throws AnalysisException is thrown if there is an exception parsing the pom.
|
||||||
* @throws AnalysisException is thrown if there is an exception parsing the
|
|
||||||
* pom.
|
|
||||||
* @return whether or not evidence was added to the dependency
|
* @return whether or not evidence was added to the dependency
|
||||||
*/
|
*/
|
||||||
@edu.umd.cs.findbugs.annotations.SuppressWarnings(
|
protected boolean analyzePOM(Dependency dependency) throws AnalysisException {
|
||||||
value = "OS_OPEN_STREAM",
|
|
||||||
justification = "The reader on line 259 is closed by closing the zipEntry")
|
|
||||||
protected boolean analyzePOM(Dependency dependency) throws IOException, AnalysisException {
|
|
||||||
boolean foundSomething = false;
|
boolean foundSomething = false;
|
||||||
Properties pomProperties = null;
|
final JarFile jar;
|
||||||
final List<Model> poms = new ArrayList<Model>();
|
|
||||||
FileInputStream fs = null;
|
|
||||||
try {
|
try {
|
||||||
fs = new FileInputStream(dependency.getActualFilePath());
|
jar = new JarFile(dependency.getActualFilePath());
|
||||||
final ZipInputStream zin = new ZipInputStream(fs);
|
|
||||||
ZipEntry entry = zin.getNextEntry();
|
|
||||||
|
|
||||||
while (entry != null) {
|
|
||||||
final String entryName = (new File(entry.getName())).getName().toLowerCase();
|
|
||||||
|
|
||||||
if (!entry.isDirectory() && "pom.xml".equals(entryName)) {
|
|
||||||
final NonClosingStream stream = new NonClosingStream(zin);
|
|
||||||
Model p = null;
|
|
||||||
try {
|
|
||||||
final JAXBElement obj = (JAXBElement) pomUnmarshaller.unmarshal(stream);
|
|
||||||
p = (Model) obj.getValue();
|
|
||||||
} catch (JAXBException ex) {
|
|
||||||
final String msg = String.format("Unable to parse POM '%s' in '%s'",
|
|
||||||
entry.getName(), dependency.getFilePath());
|
|
||||||
final AnalysisException ax = new AnalysisException(msg, ex);
|
|
||||||
dependency.getAnalysisExceptions().add(ax);
|
|
||||||
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.INFO, msg);
|
|
||||||
}
|
|
||||||
if (p != null) {
|
|
||||||
poms.add(p);
|
|
||||||
}
|
|
||||||
zin.closeEntry();
|
|
||||||
} else if (!entry.isDirectory() && "pom.properties".equals(entryName)) {
|
|
||||||
//TODO what if there is more then one pom.properties?
|
|
||||||
// need to find the POM, then look to see if there is a sibling
|
|
||||||
// pom.properties and use those together.
|
|
||||||
if (pomProperties == null) {
|
|
||||||
Reader reader;
|
|
||||||
try {
|
|
||||||
reader = new InputStreamReader(zin, "UTF-8");
|
|
||||||
pomProperties = new Properties();
|
|
||||||
pomProperties.load(reader);
|
|
||||||
} finally {
|
|
||||||
//zin.closeEntry closes the reader
|
|
||||||
//reader.close();
|
|
||||||
zin.closeEntry();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
final String msg = "JAR file contains multiple pom.properties files - unable to process POM";
|
|
||||||
final AnalysisException ax = new AnalysisException(msg);
|
|
||||||
dependency.getAnalysisExceptions().add(ax);
|
|
||||||
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.INFO, msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
entry = zin.getNextEntry();
|
|
||||||
}
|
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
throw new AnalysisException("Error reading JAR file as zip.", ex);
|
final String msg = String.format("Unable to read JarFile '%s'.", dependency.getActualFilePath());
|
||||||
} finally {
|
final AnalysisException ax = new AnalysisException(msg, ex);
|
||||||
if (fs != null) {
|
dependency.getAnalysisExceptions().add(ax);
|
||||||
fs.close();
|
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.WARNING, msg, ex);
|
||||||
}
|
return foundSomething;
|
||||||
|
}
|
||||||
|
List<String> pomEntries;
|
||||||
|
try {
|
||||||
|
pomEntries = retrievePomListing(jar);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
final String msg = String.format("Unable to read JarEntries in '%s'.", dependency.getActualFilePath());
|
||||||
|
final AnalysisException ax = new AnalysisException(msg, ex);
|
||||||
|
dependency.getAnalysisExceptions().add(ax);
|
||||||
|
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.WARNING, msg, ex);
|
||||||
|
return foundSomething;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Model pom : poms) {
|
for (String path : pomEntries) {
|
||||||
//group id
|
Properties pomProperties = null;
|
||||||
final String groupid = interpolateString(pom.getGroupId(), pomProperties);
|
try {
|
||||||
if (groupid != null) {
|
pomProperties = retrievePomProperties(path, jar);
|
||||||
foundSomething = true;
|
} catch (IOException ex) {
|
||||||
dependency.getVendorEvidence().addEvidence("pom", "groupid", groupid, Evidence.Confidence.HIGH);
|
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.FINEST, "ignore this, failed reading a non-existent pom.properties", ex);
|
||||||
dependency.getProductEvidence().addEvidence("pom", "groupid", groupid, Evidence.Confidence.LOW);
|
|
||||||
}
|
}
|
||||||
//artifact id
|
Model pom = null;
|
||||||
final String artifactid = interpolateString(pom.getArtifactId(), pomProperties);
|
try {
|
||||||
if (artifactid != null) {
|
pom = retrievePom(path, jar);
|
||||||
foundSomething = true;
|
} catch (JAXBException ex) {
|
||||||
dependency.getProductEvidence().addEvidence("pom", "artifactid", artifactid, Evidence.Confidence.HIGH);
|
final String msg = String.format("Unable to parse POM '%s' in '%s'",
|
||||||
dependency.getVendorEvidence().addEvidence("pom", "artifactid", artifactid, Evidence.Confidence.LOW);
|
path, dependency.getFilePath());
|
||||||
|
final AnalysisException ax = new AnalysisException(msg, ex);
|
||||||
|
dependency.getAnalysisExceptions().add(ax);
|
||||||
|
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.WARNING, msg);
|
||||||
|
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.SEVERE, msg, ax);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.SEVERE, null, ex);
|
||||||
}
|
}
|
||||||
//version
|
foundSomething = setPomEvidence(dependency, pom, pomProperties) || foundSomething;
|
||||||
final String version = interpolateString(pom.getVersion(), pomProperties);
|
}
|
||||||
if (version != null) {
|
return foundSomething;
|
||||||
foundSomething = true;
|
}
|
||||||
dependency.getVersionEvidence().addEvidence("pom", "version", version, Evidence.Confidence.HIGH);
|
|
||||||
}
|
/**
|
||||||
// org name
|
* Given a path to a pom.xml within a JarFile, this method attempts to load
|
||||||
final Organization org = pom.getOrganization();
|
* a sibling pom.properties if one exists.
|
||||||
if (org != null && org.getName() != null) {
|
* @param path the path to the pom.xml within the JarFile
|
||||||
foundSomething = true;
|
* @param jar the JarFile to load the pom.properties from
|
||||||
final String orgName = interpolateString(org.getName(), pomProperties);
|
* @return a Properties object or null if no pom.properties was found
|
||||||
dependency.getVendorEvidence().addEvidence("pom", "organization name", orgName, Evidence.Confidence.HIGH);
|
* @throws IOException thrown if there is an exception reading the pom.properties
|
||||||
}
|
*/
|
||||||
//pom name
|
@edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "OS_OPEN_STREAM",
|
||||||
final String pomName = interpolateString(pom.getName(), pomProperties);
|
justification = "The reader is closed by closing the zipEntry")
|
||||||
if (pomName != null) {
|
private Properties retrievePomProperties(String path, final JarFile jar) throws IOException {
|
||||||
foundSomething = true;
|
Properties pomProperties = null;
|
||||||
dependency.getProductEvidence().addEvidence("pom", "name", pomName, Evidence.Confidence.HIGH);
|
final String propPath = path.substring(0, path.length() - 7) + "pom.properies";
|
||||||
dependency.getVendorEvidence().addEvidence("pom", "name", pomName, Evidence.Confidence.HIGH);
|
final ZipEntry propEntry = jar.getEntry(propPath);
|
||||||
|
if (propEntry != null) {
|
||||||
|
final Reader reader = new InputStreamReader(jar.getInputStream(propEntry), "UTF-8");
|
||||||
|
pomProperties = new Properties();
|
||||||
|
pomProperties.load(reader);
|
||||||
|
}
|
||||||
|
return pomProperties;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Searches a JarFile for pom.xml entries and returns a listing of these entries.
|
||||||
|
* @param jar the JarFile to search
|
||||||
|
* @return a list of pom.xml entries
|
||||||
|
* @throws IOException thrown if there is an exception reading a JarEntry
|
||||||
|
*/
|
||||||
|
private List<String> retrievePomListing(final JarFile jar) throws IOException {
|
||||||
|
final List<String> pomEntries = new ArrayList<String>();
|
||||||
|
final Enumeration<JarEntry> entries = jar.entries();
|
||||||
|
while (entries.hasMoreElements()) {
|
||||||
|
final JarEntry entry = entries.nextElement();
|
||||||
|
final String entryName = (new File(entry.getName())).getName().toLowerCase();
|
||||||
|
if (!entry.isDirectory() && "pom.xml".equals(entryName)) {
|
||||||
|
pomEntries.add(entry.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pomEntries;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Retrieves the specified POM from a jar file and converts it to a Model.
|
||||||
|
* @param path the path to the pom.xml file within the jar file
|
||||||
|
* @param jar the jar file to extract the pom from
|
||||||
|
* @return returns a {@link org.owasp.dependencycheck.analyzer.pom.generated.Model} object
|
||||||
|
* @throws JAXBException is thrown if there is an exception parsing the pom
|
||||||
|
* @throws IOException is thrown if there is an exception reading the jar
|
||||||
|
*/
|
||||||
|
private Model retrievePom(String path, JarFile jar) throws JAXBException, IOException {
|
||||||
|
final ZipEntry entry = jar.getEntry(path);
|
||||||
|
if (entry != null) { //should never be null
|
||||||
|
Model m = null;
|
||||||
|
try {
|
||||||
|
final XMLFilter filter = new MavenNamespaceFilter();
|
||||||
|
final SAXParserFactory spf = SAXParserFactory.newInstance();
|
||||||
|
final SAXParser sp = spf.newSAXParser();
|
||||||
|
final XMLReader xr = sp.getXMLReader();
|
||||||
|
filter.setParent(xr);
|
||||||
|
final NonClosingStream stream = new NonClosingStream(jar.getInputStream(entry));
|
||||||
|
final InputStreamReader reader = new InputStreamReader(stream);
|
||||||
|
final InputSource xml = new InputSource(reader);
|
||||||
|
final SAXSource source = new SAXSource(filter, xml);
|
||||||
|
final JAXBElement<Model> el = pomUnmarshaller.unmarshal(source, Model.class);
|
||||||
|
m = el.getValue();
|
||||||
|
} catch (ParserConfigurationException ex) {
|
||||||
|
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.SEVERE, null, ex);
|
||||||
|
} catch (SAXException ex) {
|
||||||
|
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.SEVERE, null, ex);
|
||||||
|
} catch (JAXBException ex) {
|
||||||
|
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.FINEST, "failure reading pom via jaxb path:'"
|
||||||
|
+ path + "' jar:'" + jar.getName() + "'", ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Description
|
return m;
|
||||||
if (pom.getDescription() != null) {
|
}
|
||||||
foundSomething = true;
|
return null;
|
||||||
final String description = interpolateString(pom.getDescription(), pomProperties);
|
}
|
||||||
dependency.setDescription(description);
|
|
||||||
dependency.getProductEvidence().addEvidence("pom", "description", description, Evidence.Confidence.MEDIUM);
|
/**
|
||||||
dependency.getVendorEvidence().addEvidence("pom", "description", description, Evidence.Confidence.MEDIUM);
|
* Sets evidence from the pom on the supplied dependency.
|
||||||
|
* @param dependency the dependency to set data on
|
||||||
|
* @param pom the information from the pom
|
||||||
|
* @param pomProperties the pom properties file (null if none exists)
|
||||||
|
* @return true if there was evidence within the pom that we could use; otherwise false
|
||||||
|
*/
|
||||||
|
private boolean setPomEvidence(Dependency dependency, Model pom, Properties pomProperties) {
|
||||||
|
boolean foundSomething = false;
|
||||||
|
//group id
|
||||||
|
final String groupid = interpolateString(pom.getGroupId(), pomProperties);
|
||||||
|
if (groupid != null) {
|
||||||
|
foundSomething = true;
|
||||||
|
dependency.getVendorEvidence().addEvidence("pom", "groupid", groupid, Evidence.Confidence.HIGH);
|
||||||
|
dependency.getProductEvidence().addEvidence("pom", "groupid", groupid, Evidence.Confidence.LOW);
|
||||||
|
}
|
||||||
|
//artifact id
|
||||||
|
final String artifactid = interpolateString(pom.getArtifactId(), pomProperties);
|
||||||
|
if (artifactid != null) {
|
||||||
|
foundSomething = true;
|
||||||
|
dependency.getProductEvidence().addEvidence("pom", "artifactid", artifactid, Evidence.Confidence.HIGH);
|
||||||
|
dependency.getVendorEvidence().addEvidence("pom", "artifactid", artifactid, Evidence.Confidence.LOW);
|
||||||
|
}
|
||||||
|
//version
|
||||||
|
final String version = interpolateString(pom.getVersion(), pomProperties);
|
||||||
|
if (version != null) {
|
||||||
|
foundSomething = true;
|
||||||
|
dependency.getVersionEvidence().addEvidence("pom", "version", version, Evidence.Confidence.HIGH);
|
||||||
|
}
|
||||||
|
// org name
|
||||||
|
final Organization org = pom.getOrganization();
|
||||||
|
if (org != null && org.getName() != null) {
|
||||||
|
foundSomething = true;
|
||||||
|
final String orgName = interpolateString(org.getName(), pomProperties);
|
||||||
|
dependency.getVendorEvidence().addEvidence("pom", "organization name", orgName, Evidence.Confidence.HIGH);
|
||||||
|
}
|
||||||
|
//pom name
|
||||||
|
final String pomName = interpolateString(pom.getName(), pomProperties);
|
||||||
|
if (pomName != null) {
|
||||||
|
foundSomething = true;
|
||||||
|
dependency.getProductEvidence().addEvidence("pom", "name", pomName, Evidence.Confidence.HIGH);
|
||||||
|
dependency.getVendorEvidence().addEvidence("pom", "name", pomName, Evidence.Confidence.HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Description
|
||||||
|
if (pom.getDescription() != null) {
|
||||||
|
foundSomething = true;
|
||||||
|
String description = interpolateString(pom.getDescription(), pomProperties);
|
||||||
|
|
||||||
|
if (HTML_DETECTION_PATTERN.matcher(description).find()) {
|
||||||
|
description = Jsoup.parse(description).text();
|
||||||
}
|
}
|
||||||
|
|
||||||
//license
|
dependency.setDescription(description);
|
||||||
if (pom.getLicenses() != null) {
|
dependency.getProductEvidence().addEvidence("pom", "description", description, Evidence.Confidence.MEDIUM);
|
||||||
String license = null;
|
dependency.getVendorEvidence().addEvidence("pom", "description", description, Evidence.Confidence.MEDIUM);
|
||||||
for (License lic : pom.getLicenses().getLicense()) {
|
}
|
||||||
String tmp = null;
|
|
||||||
if (lic.getName() != null) {
|
//license
|
||||||
tmp = interpolateString(lic.getName(), pomProperties);
|
if (pom.getLicenses() != null) {
|
||||||
}
|
String license = null;
|
||||||
if (lic.getUrl() != null) {
|
for (License lic : pom.getLicenses().getLicense()) {
|
||||||
if (tmp == null) {
|
String tmp = null;
|
||||||
tmp = interpolateString(lic.getUrl(), pomProperties);
|
if (lic.getName() != null) {
|
||||||
} else {
|
tmp = interpolateString(lic.getName(), pomProperties);
|
||||||
tmp += ": " + interpolateString(lic.getUrl(), pomProperties);
|
}
|
||||||
}
|
if (lic.getUrl() != null) {
|
||||||
}
|
|
||||||
if (tmp == null) {
|
if (tmp == null) {
|
||||||
continue;
|
tmp = interpolateString(lic.getUrl(), pomProperties);
|
||||||
}
|
|
||||||
if (license == null) {
|
|
||||||
license = tmp;
|
|
||||||
} else {
|
} else {
|
||||||
license += "\n" + tmp;
|
tmp += ": " + interpolateString(lic.getUrl(), pomProperties);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (license != null) {
|
if (tmp == null) {
|
||||||
dependency.setLicense(license);
|
continue;
|
||||||
}
|
}
|
||||||
|
if (HTML_DETECTION_PATTERN.matcher(tmp).find()) {
|
||||||
|
tmp = Jsoup.parse(tmp).text();
|
||||||
|
}
|
||||||
|
if (license == null) {
|
||||||
|
license = tmp;
|
||||||
|
} else {
|
||||||
|
license += "\n" + tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (license != null) {
|
||||||
|
dependency.setLicense(license);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return foundSomething;
|
return foundSomething;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Tracks whether the jar being analyzed contains classes.
|
|
||||||
*/
|
|
||||||
private boolean hasClasses = false;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Analyzes the path information of the classes contained within the
|
* Analyzes the path information of the classes contained within the
|
||||||
@@ -380,7 +462,6 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
|
|||||||
*/
|
*/
|
||||||
protected boolean analyzePackageNames(Dependency dependency, boolean addPackagesAsEvidence)
|
protected boolean analyzePackageNames(Dependency dependency, boolean addPackagesAsEvidence)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
hasClasses = false;
|
|
||||||
JarFile jar = null;
|
JarFile jar = null;
|
||||||
try {
|
try {
|
||||||
jar = new JarFile(dependency.getActualFilePath());
|
jar = new JarFile(dependency.getActualFilePath());
|
||||||
@@ -392,7 +473,7 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
|
|||||||
final int count = collectPackageNameInformation(en, level0, level1, level2, level3);
|
final int count = collectPackageNameInformation(en, level0, level1, level2, level3);
|
||||||
|
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
return hasClasses;
|
return false;
|
||||||
}
|
}
|
||||||
final EvidenceCollection vendor = dependency.getVendorEvidence();
|
final EvidenceCollection vendor = dependency.getVendorEvidence();
|
||||||
final EvidenceCollection product = dependency.getProductEvidence();
|
final EvidenceCollection product = dependency.getProductEvidence();
|
||||||
@@ -491,7 +572,7 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
|
|||||||
jar.close();
|
jar.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return hasClasses;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -514,9 +595,15 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
|
|||||||
|
|
||||||
final Manifest manifest = jar.getManifest();
|
final Manifest manifest = jar.getManifest();
|
||||||
if (manifest == null) {
|
if (manifest == null) {
|
||||||
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.SEVERE,
|
//don't log this for javadoc or sources jar files
|
||||||
String.format("Jar file '%s' does not contain a manifest.",
|
if (!dependency.getFileName().toLowerCase().endsWith("-sources.jar")
|
||||||
dependency.getFileName()));
|
&& !dependency.getFileName().toLowerCase().endsWith("-javadoc.jar")
|
||||||
|
&& !dependency.getFileName().toLowerCase().endsWith("-src.jar")
|
||||||
|
&& !dependency.getFileName().toLowerCase().endsWith("-doc.jar")) {
|
||||||
|
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.SEVERE,
|
||||||
|
String.format("Jar file '%s' does not contain a manifest.",
|
||||||
|
dependency.getFileName()));
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
final Attributes atts = manifest.getMainAttributes();
|
final Attributes atts = manifest.getMainAttributes();
|
||||||
@@ -529,7 +616,10 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
|
|||||||
|
|
||||||
for (Entry<Object, Object> entry : atts.entrySet()) {
|
for (Entry<Object, Object> entry : atts.entrySet()) {
|
||||||
String key = entry.getKey().toString();
|
String key = entry.getKey().toString();
|
||||||
final String value = atts.getValue(key);
|
String value = atts.getValue(key);
|
||||||
|
if (HTML_DETECTION_PATTERN.matcher(value).find()) {
|
||||||
|
value = Jsoup.parse(value).text();
|
||||||
|
}
|
||||||
if (key.equals(Attributes.Name.IMPLEMENTATION_TITLE.toString())) {
|
if (key.equals(Attributes.Name.IMPLEMENTATION_TITLE.toString())) {
|
||||||
foundSomething = true;
|
foundSomething = true;
|
||||||
productEvidence.addEvidence(source, key, value, Evidence.Confidence.HIGH);
|
productEvidence.addEvidence(source, key, value, Evidence.Confidence.HIGH);
|
||||||
@@ -566,6 +656,8 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
|
|||||||
&& !key.endsWith("jdk")
|
&& !key.endsWith("jdk")
|
||||||
&& !key.contains("lastmodified")
|
&& !key.contains("lastmodified")
|
||||||
&& !key.endsWith("package")
|
&& !key.endsWith("package")
|
||||||
|
&& !key.endsWith("classpath")
|
||||||
|
&& !key.endsWith("class-path")
|
||||||
&& !isImportPackage(key, value)) {
|
&& !isImportPackage(key, value)) {
|
||||||
|
|
||||||
foundSomething = true;
|
foundSomething = true;
|
||||||
@@ -718,9 +810,8 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
|
|||||||
HashMap<String, Integer> level1, HashMap<String, Integer> level2, HashMap<String, Integer> level3) {
|
HashMap<String, Integer> level1, HashMap<String, Integer> level2, HashMap<String, Integer> level3) {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
while (en.hasMoreElements()) {
|
while (en.hasMoreElements()) {
|
||||||
final java.util.jar.JarEntry entry = (java.util.jar.JarEntry) en.nextElement();
|
final JarEntry entry = (JarEntry) en.nextElement();
|
||||||
if (entry.getName().endsWith(".class")) {
|
if (entry.getName().endsWith(".class")) {
|
||||||
hasClasses = true;
|
|
||||||
String[] path;
|
String[] path;
|
||||||
if (entry.getName().contains("/")) {
|
if (entry.getName().contains("/")) {
|
||||||
path = entry.getName().toLowerCase().split("/");
|
path = entry.getName().toLowerCase().split("/");
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
/**
|
/**
|
||||||
* <html>
|
* <html>
|
||||||
* <head>
|
* <head>
|
||||||
* <title>org.owasp.dependencycheck.scanner</title>
|
* <title>org.owasp.dependencycheck.analyzer</title>
|
||||||
* </head>
|
* </head>
|
||||||
* <body>
|
* <body>
|
||||||
* The scanner package contains the utilities to scan files and directories for
|
* Analyzers are used to inspect the identified dependencies, collect Evidence,
|
||||||
* dependencies. Analyzers are used to inspect the identified dependencies and
|
* and process the dependencies.
|
||||||
* collect Evidence. This evidence is then used to determine if the dependency
|
|
||||||
* has a known CPE.
|
|
||||||
* </body>
|
* </body>
|
||||||
* </html>
|
* </html>
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Dependency-Check.
|
||||||
|
*
|
||||||
|
* Dependency-Check is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, either version 3 of the License, or (at your option) any
|
||||||
|
* later version.
|
||||||
|
*
|
||||||
|
* Dependency-Check is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* Dependency-Check. If not, see http://www.gnu.org/licenses/.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
package org.owasp.dependencycheck.analyzer.pom;
|
||||||
|
|
||||||
|
import org.xml.sax.Attributes;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
import org.xml.sax.helpers.XMLFilterImpl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This filter is used when parsing POM documents. Some POM documents
|
||||||
|
* do not specify the xmlns="http://maven.apache.org/POM/4.0.0". This
|
||||||
|
* filter ensures that the correct namespace is added so that both
|
||||||
|
* types of POMs can be read.
|
||||||
|
* @author Jeremy Long (jeremy.long@gmail.com)
|
||||||
|
*/
|
||||||
|
public class MavenNamespaceFilter extends XMLFilterImpl {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The namespace to add for Maven POMs.
|
||||||
|
*/
|
||||||
|
private static final String NAMESPACE = "http://maven.apache.org/POM/4.0.0";
|
||||||
|
/**
|
||||||
|
* A flag indicating whether or not the namespace (prefix) has been added.
|
||||||
|
*/
|
||||||
|
private boolean namespaceAdded = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called at the start of the document parsing.
|
||||||
|
* @throws SAXException thrown if there is a SAXException
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void startDocument() throws SAXException {
|
||||||
|
super.startDocument();
|
||||||
|
startPrefixMapping("", NAMESPACE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when an element is started.
|
||||||
|
* @param uri the uri
|
||||||
|
* @param localName the localName
|
||||||
|
* @param qName the qualified name
|
||||||
|
* @param atts the attributes
|
||||||
|
* @throws SAXException thrown if there is a SAXException
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
|
||||||
|
super.startElement(NAMESPACE, localName, qName, atts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicatees the start of the document.
|
||||||
|
* @param uri the uri
|
||||||
|
* @param localName the localName
|
||||||
|
* @param qName the qualified name
|
||||||
|
* @throws SAXException thrown if there is a SAXException
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void endElement(String uri, String localName, String qName)
|
||||||
|
throws SAXException {
|
||||||
|
super.endElement(NAMESPACE, localName, qName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when prefix mapping is started.
|
||||||
|
* @param prefix the prefix
|
||||||
|
* @param url the url
|
||||||
|
* @throws SAXException thrown if there is a SAXException
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void startPrefixMapping(String prefix, String url) throws SAXException {
|
||||||
|
if (!this.namespaceAdded) {
|
||||||
|
namespaceAdded = true;
|
||||||
|
super.startPrefixMapping("", NAMESPACE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
/**
|
||||||
|
* <html>
|
||||||
|
* <head>
|
||||||
|
* <title>org.owasp.dependencycheck.analyzer.pom</title>
|
||||||
|
* </head>
|
||||||
|
* <body>
|
||||||
|
* This package contains utility classes used to parse pom.xml files.
|
||||||
|
* </body>
|
||||||
|
* </html>
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.owasp.dependencycheck.analyzer.pom;
|
||||||
@@ -227,9 +227,9 @@ public class CveDB {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the vulnerabilities associated with the specified CPE cpe.
|
* Retrieves the vulnerabilities associated with the specified CPE.
|
||||||
*
|
*
|
||||||
* @param cpeStr the CPE cpe name
|
* @param cpeStr the CPE name
|
||||||
* @return a list of Vulnerabilities
|
* @return a list of Vulnerabilities
|
||||||
* @throws DatabaseException thrown if there is an exception retrieving data
|
* @throws DatabaseException thrown if there is an exception retrieving data
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import org.owasp.dependencycheck.dependency.Dependency;
|
|||||||
import org.owasp.dependencycheck.dependency.Vulnerability;
|
import org.owasp.dependencycheck.dependency.Vulnerability;
|
||||||
import org.owasp.dependencycheck.dependency.Identifier;
|
import org.owasp.dependencycheck.dependency.Identifier;
|
||||||
import org.owasp.dependencycheck.analyzer.Analyzer;
|
import org.owasp.dependencycheck.analyzer.Analyzer;
|
||||||
|
import org.owasp.dependencycheck.dependency.VulnerableSoftware;
|
||||||
/**
|
/**
|
||||||
* NvdCveAnalyzer is a utility class that takes a project dependency and
|
* NvdCveAnalyzer is a utility class that takes a project dependency and
|
||||||
* attempts to discern if there is an associated CVEs. It uses the the
|
* attempts to discern if there is an associated CVEs. It uses the the
|
||||||
@@ -106,7 +107,9 @@ public class NvdCveAnalyzer implements Analyzer {
|
|||||||
final String value = id.getValue();
|
final String value = id.getValue();
|
||||||
final List<Vulnerability> vulns = cveDB.getVulnerabilities(value);
|
final List<Vulnerability> vulns = cveDB.getVulnerabilities(value);
|
||||||
for (Vulnerability v : vulns) {
|
for (Vulnerability v : vulns) {
|
||||||
dependency.addVulnerability(v);
|
if (isValidMatch(dependency, v)) {
|
||||||
|
dependency.addVulnerability(v);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (DatabaseException ex) {
|
} catch (DatabaseException ex) {
|
||||||
throw new AnalysisException(ex);
|
throw new AnalysisException(ex);
|
||||||
@@ -160,4 +163,52 @@ public class NvdCveAnalyzer implements Analyzer {
|
|||||||
public void initialize() throws Exception {
|
public void initialize() throws Exception {
|
||||||
this.open();
|
this.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Determines if this is a valid vulnerability match for the given dependency.
|
||||||
|
* Specifically, this is concerned with ensuring the version numbers are correct.</p>
|
||||||
|
* <p>Currently, this is focused on the issues with the versions for Struts 1 and Struts 2.
|
||||||
|
* In the future this will due better matching on more version numbers.</p>
|
||||||
|
* @param dependency the dependency
|
||||||
|
* @param v the vulnerability
|
||||||
|
* @return returns true if the vulnerability is for the given dependency
|
||||||
|
*/
|
||||||
|
private boolean isValidMatch(final Dependency dependency, final Vulnerability v) {
|
||||||
|
//right now I only know of the issue with Struts1/2
|
||||||
|
// start with fixing this problem.
|
||||||
|
|
||||||
|
//TODO extend this solution to do better version matching for the vulnerable software.
|
||||||
|
boolean struts1 = false;
|
||||||
|
boolean struts2 = false;
|
||||||
|
for (Identifier i : dependency.getIdentifiers()) {
|
||||||
|
if (i.getValue().startsWith("cpe:/a:apache:struts:")) {
|
||||||
|
final char version = i.getValue().charAt(21);
|
||||||
|
if (version == '1') {
|
||||||
|
struts1 = true;
|
||||||
|
}
|
||||||
|
if (version == '2') {
|
||||||
|
struts2 = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!struts1 && !struts2) {
|
||||||
|
return true; //we are not looking at struts, so return true.
|
||||||
|
}
|
||||||
|
if (struts1 && struts2) {
|
||||||
|
return true; //there is a mismatch here, but we can't solve it here so we return valid.
|
||||||
|
}
|
||||||
|
if (struts1) {
|
||||||
|
boolean hasStruts1Vuln = false;
|
||||||
|
boolean hasStruts2PreviousVersion = false;
|
||||||
|
for (VulnerableSoftware vs : v.getVulnerableSoftware()) {
|
||||||
|
hasStruts2PreviousVersion |= vs.hasPreviousVersion() && vs.getName().charAt(21) == '2';
|
||||||
|
hasStruts1Vuln |= vs.getName().charAt(21) == '1';
|
||||||
|
}
|
||||||
|
if (!hasStruts1Vuln && hasStruts2PreviousVersion) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -140,21 +140,23 @@ public class DatabaseUpdater implements CachedWebDataSource {
|
|||||||
} catch (ClassNotFoundException ex) {
|
} catch (ClassNotFoundException ex) {
|
||||||
throw new UpdateException(ex);
|
throw new UpdateException(ex);
|
||||||
} finally {
|
} finally {
|
||||||
|
boolean deleted = false;
|
||||||
try {
|
try {
|
||||||
if (outputPath != null && outputPath.exists()) {
|
if (outputPath != null && outputPath.exists()) {
|
||||||
outputPath.delete();
|
deleted = outputPath.delete();
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (outputPath != null && outputPath.exists()) {
|
if (outputPath != null && (outputPath.exists() || !deleted)) {
|
||||||
outputPath.deleteOnExit();
|
outputPath.deleteOnExit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
deleted = false;
|
||||||
if (outputPath12 != null && outputPath12.exists()) {
|
if (outputPath12 != null && outputPath12.exists()) {
|
||||||
outputPath12.delete();
|
deleted = outputPath12.delete();
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (outputPath12 != null && outputPath12.exists()) {
|
if (outputPath12 != null && (outputPath12.exists() || !deleted)) {
|
||||||
outputPath12.deleteOnExit();
|
outputPath12.deleteOnExit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,6 +111,8 @@ public class ReportGenerator {
|
|||||||
*
|
*
|
||||||
* @return a Velocity Context.
|
* @return a Velocity Context.
|
||||||
*/
|
*/
|
||||||
|
@edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "RV_RETURN_VALUE_IGNORED_INFERRED",
|
||||||
|
justification = "No plan to fix this style issue")
|
||||||
private Context createContext() {
|
private Context createContext() {
|
||||||
final ToolManager manager = new ToolManager();
|
final ToolManager manager = new ToolManager();
|
||||||
final Context c = manager.createContext();
|
final Context c = manager.createContext();
|
||||||
@@ -196,7 +198,10 @@ public class ReportGenerator {
|
|||||||
try {
|
try {
|
||||||
final File outDir = new File(outFileName).getParentFile();
|
final File outDir = new File(outFileName).getParentFile();
|
||||||
if (!outDir.exists()) {
|
if (!outDir.exists()) {
|
||||||
outDir.mkdirs();
|
final boolean created = outDir.mkdirs();
|
||||||
|
if (!created) {
|
||||||
|
throw new Exception("Unable to create directory '" + outDir.getAbsolutePath() + "'.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
outputStream = new FileOutputStream(outFileName);
|
outputStream = new FileOutputStream(outFileName);
|
||||||
|
|||||||
@@ -111,4 +111,35 @@ public class DependencyVersion implements Iterable {
|
|||||||
public String toString() {
|
public String toString() {
|
||||||
return StringUtils.join(versionParts.toArray(), ".");
|
return StringUtils.join(versionParts.toArray(), ".");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares the equality of this object to the one passed in as a parameter.
|
||||||
|
* @param obj the object to compare equality
|
||||||
|
* @return returns true only if the two objects are equal, otherwise false
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final DependencyVersion other = (DependencyVersion) obj;
|
||||||
|
if (this.versionParts != other.versionParts && (this.versionParts == null || !this.versionParts.equals(other.versionParts))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the hashCode for this object.
|
||||||
|
* @return the hashCode
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int hash = 5;
|
||||||
|
hash = 71 * hash + (this.versionParts != null ? this.versionParts.hashCode() : 0);
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
21
src/main/resources/META-INF/licenses/jsoup/LICENSE.txt
Normal file
21
src/main/resources/META-INF/licenses/jsoup/LICENSE.txt
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
The MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2009, 2010, 2011, 2012, 2013 Jonathan Hedley <jonathan@hedley.net>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
Reference in New Issue
Block a user