mirror of
https://github.com/ysoftdevs/DependencyCheck.git
synced 2026-03-23 09:31:32 +01:00
added functionality to remove some false positives
Former-commit-id: 4de4e94c96a3e65454f7626bee604b9286bd9a9b
This commit is contained in:
@@ -0,0 +1,154 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of DependencyCheck.
|
||||||
|
*
|
||||||
|
* DependencyCheck 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.
|
||||||
|
*
|
||||||
|
* DependencyCheck 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
|
||||||
|
* DependencyCheck. If not, see http://www.gnu.org/licenses/.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
package org.owasp.dependencycheck.analyzer;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import org.owasp.dependencycheck.Engine;
|
||||||
|
import org.owasp.dependencycheck.dependency.Dependency;
|
||||||
|
import org.owasp.dependencycheck.dependency.Identifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This analyzer attempts to remove some well known false positives - specifically
|
||||||
|
* regarding the java runtime.
|
||||||
|
*
|
||||||
|
* @author Jeremy Long (jeremy.long@gmail.com)
|
||||||
|
*/
|
||||||
|
public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The set of file extensions supported by this analyzer.
|
||||||
|
*/
|
||||||
|
private static final Set<String> EXTENSIONS = null; //newHashSet("jar");
|
||||||
|
/**
|
||||||
|
* The name of the analyzer.
|
||||||
|
*/
|
||||||
|
private static final String ANALYZER_NAME = "False Positive Analyzer";
|
||||||
|
/**
|
||||||
|
* The phase that this analyzer is intended to run in.
|
||||||
|
*/
|
||||||
|
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.POST_IDENTIFIER_ANALYSIS;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of file EXTENSIONS supported by this analyzer.
|
||||||
|
*
|
||||||
|
* @return a list of file EXTENSIONS supported by this analyzer.
|
||||||
|
*/
|
||||||
|
public Set<String> getSupportedExtensions() {
|
||||||
|
return EXTENSIONS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the analyzer.
|
||||||
|
*
|
||||||
|
* @return the name of the analyzer.
|
||||||
|
*/
|
||||||
|
public String getName() {
|
||||||
|
return ANALYZER_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether or not this analyzer can process the given extension.
|
||||||
|
*
|
||||||
|
* @param extension the file extension to test for support
|
||||||
|
* @return whether or not the specified file extension is supported by this
|
||||||
|
* analyzer.
|
||||||
|
*/
|
||||||
|
public boolean supportsExtension(String extension) {
|
||||||
|
return true; //EXTENSIONS.contains(extension);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the phase that the analyzer is intended to run in.
|
||||||
|
*
|
||||||
|
* @return the phase that the analyzer is intended to run in.
|
||||||
|
*/
|
||||||
|
public AnalysisPhase getAnalysisPhase() {
|
||||||
|
return ANALYSIS_PHASE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The initialize method does nothing for this Analyzer.
|
||||||
|
*
|
||||||
|
* @throws Exception never thrown by this analyzer
|
||||||
|
*/
|
||||||
|
public void initialize() throws Exception {
|
||||||
|
//do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The close method does nothing for this Analyzer.
|
||||||
|
*
|
||||||
|
* @throws Exception never thrown by this analyzer
|
||||||
|
*/
|
||||||
|
public void close() throws Exception {
|
||||||
|
//do nothing
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* a list of spring versions.
|
||||||
|
*/
|
||||||
|
private List<Identifier> springVersions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param dependency the dependency to analyze.
|
||||||
|
* @param engine the engine that is scanning the dependencies
|
||||||
|
* @throws AnalysisException is thrown if there is an error reading the JAR
|
||||||
|
* file.
|
||||||
|
*/
|
||||||
|
public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
|
||||||
|
removeJreEntries(dependency);
|
||||||
|
removeVersions(dependency);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeVersions(Dependency dependency) {
|
||||||
|
//todo implement this so that the following is corrected?
|
||||||
|
//cpe: cpe:/a:apache:axis2:1.4
|
||||||
|
//cpe: cpe:/a:apache:axis:1.4
|
||||||
|
/* the above was identified from the evidence below:
|
||||||
|
Source Name Value
|
||||||
|
Manifest Bundle-Vendor Apache Software Foundation
|
||||||
|
Manifest Bundle-Version 1.4
|
||||||
|
file name axis2-kernel-1.4.1
|
||||||
|
pom artifactid axis2-kernel
|
||||||
|
pom name Apache Axis2 - Kernel
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes any CPE entries for the JDK/JRE unless the filename ends with rt.jar
|
||||||
|
*
|
||||||
|
* @param dependency the dependency to remove JRE CPEs from
|
||||||
|
*/
|
||||||
|
private void removeJreEntries(Dependency dependency) {
|
||||||
|
List<Identifier> identifiers = dependency.getIdentifiers();
|
||||||
|
Iterator<Identifier> itr = identifiers.iterator();
|
||||||
|
while (itr.hasNext()) {
|
||||||
|
Identifier i = itr.next();
|
||||||
|
if ((i.getValue().startsWith("cpe:/a:sun:java:")
|
||||||
|
|| i.getValue().startsWith("cpe:/a:oracle:jre")
|
||||||
|
|| i.getValue().startsWith("cpe:/a:oracle:jdk"))
|
||||||
|
&& !dependency.getFileName().toLowerCase().endsWith("rt.jar")) {
|
||||||
|
itr.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,7 +30,9 @@ import org.owasp.dependencycheck.dependency.EvidenceCollection;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -38,6 +40,7 @@ import java.util.StringTokenizer;
|
|||||||
import java.util.jar.Attributes;
|
import java.util.jar.Attributes;
|
||||||
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.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipInputStream;
|
import java.util.zip.ZipInputStream;
|
||||||
import javax.xml.bind.JAXBContext;
|
import javax.xml.bind.JAXBContext;
|
||||||
@@ -189,10 +192,7 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
|
|||||||
analyzePackageNames(dependency, addPackagesAsEvidence);
|
analyzePackageNames(dependency, addPackagesAsEvidence);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
throw new AnalysisException("Exception occurred reading the JAR file.", ex);
|
throw new AnalysisException("Exception occurred reading the JAR file.", ex);
|
||||||
} catch (JAXBException ex) {
|
|
||||||
throw new AnalysisException("Exception occurred reading the POM within the JAR file.", ex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -208,10 +208,10 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
|
|||||||
* pom.
|
* pom.
|
||||||
* @return whether or not evidence was added to the dependency
|
* @return whether or not evidence was added to the dependency
|
||||||
*/
|
*/
|
||||||
protected boolean analyzePOM(Dependency dependency) throws IOException, JAXBException, AnalysisException {
|
protected boolean analyzePOM(Dependency dependency) throws IOException, AnalysisException {
|
||||||
boolean foundSomething = false;
|
boolean foundSomething = false;
|
||||||
Properties pomProperties = null;
|
Properties pomProperties = null;
|
||||||
Model pom = null;
|
List<Model> poms = new ArrayList<Model>();
|
||||||
FileInputStream fs = null;
|
FileInputStream fs = null;
|
||||||
try {
|
try {
|
||||||
fs = new FileInputStream(dependency.getActualFilePath());
|
fs = new FileInputStream(dependency.getActualFilePath());
|
||||||
@@ -222,17 +222,28 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
|
|||||||
final String entryName = (new File(entry.getName())).getName().toLowerCase();
|
final String entryName = (new File(entry.getName())).getName().toLowerCase();
|
||||||
|
|
||||||
if (!entry.isDirectory() && "pom.xml".equals(entryName)) {
|
if (!entry.isDirectory() && "pom.xml".equals(entryName)) {
|
||||||
if (pom == null) {
|
final NonClosingStream stream = new NonClosingStream(zin);
|
||||||
final NonClosingStream stream = new NonClosingStream(zin);
|
Model p = null;
|
||||||
|
try {
|
||||||
final JAXBElement obj = (JAXBElement) pomUnmarshaller.unmarshal(stream);
|
final JAXBElement obj = (JAXBElement) pomUnmarshaller.unmarshal(stream);
|
||||||
pom = (Model) obj.getValue();
|
p = (Model) obj.getValue();
|
||||||
zin.closeEntry();
|
} catch (JAXBException ex) {
|
||||||
} else {
|
String msg = String.format("Unable to parse POM '%s' in '%s'",
|
||||||
throw new AnalysisException("JAR file contains multiple pom.xml files - unable to process POM");
|
entry.getName(), dependency.getFilePath());
|
||||||
|
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)) {
|
} 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) {
|
if (pomProperties == null) {
|
||||||
Reader reader = null;
|
Reader reader;
|
||||||
try {
|
try {
|
||||||
reader = new InputStreamReader(zin, "UTF-8");
|
reader = new InputStreamReader(zin, "UTF-8");
|
||||||
pomProperties = new Properties();
|
pomProperties = new Properties();
|
||||||
@@ -243,7 +254,10 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
|
|||||||
zin.closeEntry();
|
zin.closeEntry();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new AnalysisException("JAR file contains multiple pom.properties files - unable to process POM");
|
String msg = "JAR file contains multiple pom.properties files - unable to process POM";
|
||||||
|
AnalysisException ax = new AnalysisException(msg);
|
||||||
|
dependency.getAnalysisExceptions().add(ax);
|
||||||
|
Logger.getLogger(JarAnalyzer.class.getName()).log(Level.INFO, msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,7 +271,7 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pom != null) {
|
for (Model pom : poms) {
|
||||||
//group id
|
//group id
|
||||||
final String groupid = interpolateString(pom.getGroupId(), pomProperties);
|
final String groupid = interpolateString(pom.getGroupId(), pomProperties);
|
||||||
if (groupid != null) {
|
if (groupid != null) {
|
||||||
@@ -576,8 +590,11 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
|
|||||||
} else {
|
} else {
|
||||||
key = key.toLowerCase();
|
key = key.toLowerCase();
|
||||||
|
|
||||||
if (!IGNORE_LIST.contains(key) && !key.endsWith("jdk")
|
if (!IGNORE_LIST.contains(key)
|
||||||
&& !key.contains("lastmodified") && !key.endsWith("package")) {
|
&& !key.endsWith("jdk")
|
||||||
|
&& !key.contains("lastmodified")
|
||||||
|
&& !key.endsWith("package")
|
||||||
|
&& !isImportPackage(key, value)) {
|
||||||
|
|
||||||
foundSomething = true;
|
foundSomething = true;
|
||||||
if (key.contains("version")) {
|
if (key.contains("version")) {
|
||||||
@@ -696,22 +713,23 @@ public class JarAnalyzer extends AbstractAnalyzer implements Analyzer {
|
|||||||
sb.append(text.substring(end + 1));
|
sb.append(text.substring(end + 1));
|
||||||
return interpolateString(sb.toString(), properties); //yes yes, this should be a loop...
|
return interpolateString(sb.toString(), properties); //yes yes, this should be a loop...
|
||||||
}
|
}
|
||||||
// private void addPredefinedData(Dependency dependency) {
|
|
||||||
// Evidence springTest1 = new Evidence("Manifest",
|
/**
|
||||||
// "Implementation-Title",
|
* Determines if the key value pair from the manifest is for an "import" type
|
||||||
// "Spring Framework",
|
* entry for package names.
|
||||||
// Evidence.Confidence.HIGH);
|
* @param key the key from the manifest
|
||||||
//
|
* @param value the value from the manifest
|
||||||
// Evidence springTest2 = new Evidence("Manifest",
|
* @return true or false depending on if it is believed the entry is an "import" entry
|
||||||
// "Implementation-Title",
|
*/
|
||||||
// "org.springframework.core",
|
private boolean isImportPackage(String key, String value) {
|
||||||
// Evidence.Confidence.HIGH);
|
final Pattern packageRx = Pattern.compile("^((([a-zA-Z_#\\$0-9]\\.)+)\\s*\\;\\s*)+$");
|
||||||
//
|
if (packageRx.matcher(value).matches()) {
|
||||||
// Set<Evidence> evidence = dependency.getProductEvidence().getEvidence();
|
if (key.contains("import") || key.contains("include")) {
|
||||||
// if (evidence.contains(springTest1) || evidence.contains(springTest2)) {
|
return true;
|
||||||
// dependency.getProductEvidence().addEvidence("a priori", "product", "springsource_spring_framework", Evidence.Confidence.HIGH);
|
} else {
|
||||||
// dependency.getVendorEvidence().addEvidence("a priori", "vendor", "SpringSource", Evidence.Confidence.HIGH);
|
return false;
|
||||||
// dependency.getVendorEvidence().addEvidence("a priori", "vendor", "vmware", Evidence.Confidence.HIGH);
|
}
|
||||||
// }
|
}
|
||||||
// }
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,5 +2,6 @@ org.owasp.dependencycheck.analyzer.JarAnalyzer
|
|||||||
org.owasp.dependencycheck.analyzer.FileNameAnalyzer
|
org.owasp.dependencycheck.analyzer.FileNameAnalyzer
|
||||||
org.owasp.dependencycheck.analyzer.HintAnalyzer
|
org.owasp.dependencycheck.analyzer.HintAnalyzer
|
||||||
org.owasp.dependencycheck.analyzer.SpringCleaningAnalyzer
|
org.owasp.dependencycheck.analyzer.SpringCleaningAnalyzer
|
||||||
|
org.owasp.dependencycheck.analyzer.FalsePositiveAnalyzer
|
||||||
org.owasp.dependencycheck.data.cpe.CPEAnalyzer
|
org.owasp.dependencycheck.data.cpe.CPEAnalyzer
|
||||||
org.owasp.dependencycheck.data.nvdcve.NvdCveAnalyzer
|
org.owasp.dependencycheck.data.nvdcve.NvdCveAnalyzer
|
||||||
Reference in New Issue
Block a user