Compare commits

..

45 Commits

Author SHA1 Message Date
Jeremy Long
094a180935 updated to release version 1.2.1
Former-commit-id: d908eed4538f0928c8b108348d9d46ce6d2f57e0
2014-05-10 08:32:34 -04:00
Jeremy Long
74e9de6370 updated sample report
Former-commit-id: c55ddb623e21f046c90493b0724f7eb34225ea29
2014-05-10 07:25:42 -04:00
Jeremy Long
c7f31b3d79 fixed typo in log statement
Former-commit-id: 08192210f3c5bb322160fba678a56acb36af3198
2014-05-10 07:23:18 -04:00
Jeremy Long
98d0239d03 pmd correction to logger
Former-commit-id: 3c3b26ec8fbf4d2602c681ff02f460fe7e712914
2014-05-10 07:16:50 -04:00
Jeremy Long
ffeab147ce checkstyle corrections
Former-commit-id: f9ae61d41ba01b6931892a339a9b701ae3c91ce2
2014-05-10 07:13:07 -04:00
Jeremy Long
90bdbd6b84 updated version of presentation
Former-commit-id: ec47594f35f5cca92888e6c8578b0d123d31b898
2014-05-10 07:12:56 -04:00
Jeremy Long
e29dd3cd33 added additional test file
Former-commit-id: 8487a2f4ba7287f54f0b5f69bc39e63bee455172
2014-05-10 07:01:24 -04:00
Jeremy Long
23b95178ff updated to remove archive files from the list of dependencies - additionally, if a zip file appears to be a jar it will now make a copy of the zip and scan it as a jar
Former-commit-id: d927daea530abad2d578dbe0ff38b97d044b4775
2014-05-10 07:00:43 -04:00
Jeremy Long
9bde80357f patch to remove additional false positives due to SCM entries in the pom
Former-commit-id: 6101fae1b5957254ddbece5afc2db8edeb7bf9b8
2014-05-10 06:59:34 -04:00
Jeremy Long
1485733715 updated to use displayFileName field instead of FileName when writing information about dependencies
Former-commit-id: bd3383ac4831bc44db6b63083e47802cce04b520
2014-05-10 06:58:51 -04:00
Jeremy Long
d125a7f09d added displayFileName field to the dependency class
Former-commit-id: 248f5397d37ea6e2f333dc0fe357188865bdb446
2014-05-10 06:57:44 -04:00
Jeremy Long
77486dffd4 removed additional false positives as part of patch for issue #93 and #119
Former-commit-id: 86f48b30150f2ba4db99dfc2eb15a0ac50a6e383
2014-05-10 06:56:53 -04:00
Jeremy Long
c84bcb433f fixed spelling error
Former-commit-id: d3aed24d6691b58ef132e00f9827e27fceb9fc73
2014-05-07 19:33:59 -04:00
Jeremy Long
f1e5221257 Merge pull request #122 from colezlaw/master
Fixed logging order of GrokAssembly for bad assemblies. Using resources ...

Former-commit-id: 65a41d23df6ccfa8c4f05235da3d7c613e4290a0
2014-05-07 19:31:59 -04:00
Jeremy Long
b8bf01acc3 added checks before warning that a file could not be deleted
Former-commit-id: 098ea1889b49ade0c73385919906398c86627ab2
2014-05-07 19:31:21 -04:00
Jeremy Long
65aa7bd1de fixed display bug when only one CPE exists for a given CVE
Former-commit-id: 18535dc408a51e516626ec4c43a3e72b01fd28f0
2014-05-07 19:30:45 -04:00
Jeremy Long
6f511444a7 fixed display bug when only one CPE exists for a given CVE
Former-commit-id: 3b791d0a0fbe2587390e048cffc4453567ddf74a
2014-05-07 19:29:52 -04:00
Jeremy Long
ef5174d89f fixed bug causing vulnerabilities to be missed
Former-commit-id: 5c6421ea8475db16f7184340fa5b8b2033d53b29
2014-05-07 07:05:37 -04:00
Jeremy Long
e2a97e75d8 moved duplicated code to a method
Former-commit-id: f6cb80dc56ef86294f2490729bb84658d98e6c9a
2014-05-07 07:03:38 -04:00
Jeremy Long
9fc6e265eb fixed off by one string truncation issue
Former-commit-id: f25894627402e9e2d310b25163dae7d7db1457d9
2014-05-07 07:03:02 -04:00
Will Stranathan
f81c42b1fd Fixed logging order of GrokAssembly for bad assemblies. Using resources for logging
Former-commit-id: 611d665c7f5312462c19c8dcf8e87dc672184f67
2014-05-03 19:12:39 -04:00
Jeremy Long
8594e146eb updates to help resolve issue 119
Former-commit-id: c8778008b91b7999cb8d88382efe8a83ebe87102
2014-05-03 14:46:48 -04:00
Jeremy Long
cda0dfdafe updated test case and related data
Former-commit-id: 513602f48b6d599b43848f0a88537190084e9cbf
2014-05-03 12:30:29 -04:00
Jeremy Long
363568b02c updated to begin fixes for issue #90 and #119
Former-commit-id: 1ceae6236ecd83e15f91ddab549027082e269e0b
2014-05-03 12:30:07 -04:00
Jeremy Long
443ab02788 added local copies of the NVD CVE data to speed up some of the test cases
Former-commit-id: 54a264872bf151034706f6ed52de3a99ed961b04
2014-05-03 11:02:23 -04:00
Jeremy Long
65784d6dc4 updated to use local copy of data files to speedup the test case
Former-commit-id: 5bb1d67156500ba74124ced18bcae599e4c5dc7a
2014-05-03 11:01:31 -04:00
Jeremy Long
da805d037f removed duplicative test
Former-commit-id: e403e85cef541416ccb3cf13704d019f4c2b5f92
2014-05-03 11:00:48 -04:00
Jeremy Long
d383776245 added additional informational log statements
Former-commit-id: 9dfe02f737cffc05838dcffeec1cfca77c3100e1
2014-05-03 11:00:21 -04:00
Jeremy Long
51eba8da73 updated settings cleanup to prevent issue with the update process
Former-commit-id: e883b7d37c583b581b41da368dbe9b8d1bafae89
2014-05-03 10:59:47 -04:00
Jeremy Long
14b4d64244 updated the URL for the NVD CVE external link
Former-commit-id: 18cd71abd7a1f0d94dde8dba2a3076b28405ab00
2014-05-03 10:58:41 -04:00
Jeremy Long
7cb7f68cda updated the URL for the NVD CVE external link
Former-commit-id: 83ad77fb9fe6029fdb95ba7ffc96663d88234631
2014-05-03 10:58:16 -04:00
Jeremy Long
83300d028b updated the URL for the NVD CVE external link
Former-commit-id: 7527c31dab810145d8aebc1225ba302aca9fc80e
2014-05-03 10:57:44 -04:00
Jeremy Long
e891ce39c0 updated settings cleanup to prevent issue with the update process
Former-commit-id: 3452aec55b778224e10879175e1aba8060da4e42
2014-05-03 10:55:56 -04:00
Jeremy Long
e58b7782ac updated settings cleanup to prevent issue with the update process
Former-commit-id: 07122c535d47f3f414659013555fa826ce0e9b9c
2014-05-03 10:55:15 -04:00
Jeremy Long
1ddb468a08 applied part of PR for issue #121 - classpath issue with some invocations of the ant client
Former-commit-id: 129a5fd9cd55c8a0abf393d0ae8405ddec412d51
2014-05-03 09:54:11 -04:00
Jeremy Long
95e3f0e0d9 added additional dependencies for testing
Former-commit-id: 99be1ef0f35f040ca13b204e2a1689cbaa3cf41a
2014-05-03 09:52:57 -04:00
Jeremy Long
0edf017ddc patched for issue #120 - duplicate evidence listed in reports
Former-commit-id: 3cdc1854af586029911b70fb4b8ff54669bac022
2014-05-03 08:52:45 -04:00
Jeremy Long
ad601fd1ee Merge branch 'bkimminich-master'
Former-commit-id: d4f3bd1ebe5237060251b1f81111b26b5f653f65
2014-04-30 19:23:23 -04:00
Jeremy Long
e7eaccb5e0 Merge branch 'master' of github.com:bkimminich/DependencyCheck into bkimminich-master
Former-commit-id: 7fe67ea5fa1b94824d2f2c8df5bd099d89dbaf85
2014-04-30 19:23:13 -04:00
Jeremy Long
6b201da3ff version 1.2.1-SNAPSHOT
Former-commit-id: 62ed08de9077505ef8e5350b0470eb5c61089dc3
2014-04-30 18:30:46 -04:00
Jeremy Long
a85a47bc20 fixed issue #118
Former-commit-id: dceb807f182be921c2d85338c1d8192361dc2c1f
2014-04-30 18:13:04 -04:00
Jeremy Long
69b8f51319 fixed issue #118
Former-commit-id: 6f7b38b0945c6bcf47ffae0b8a6be53b144269cc
2014-04-30 18:10:56 -04:00
Björn Kimminich
0d943ba805 Update AbstractSuppressionAnalyzerTest.java
Former-commit-id: 640d50086e6b5cd9302ca4a24ffed881c614fd54
2014-04-29 14:37:52 +02:00
Björn Kimminich
56fe3b5892 simplified exception testing
Former-commit-id: f43f211c4cc3133e5dfc466a4badfb3606a3be0c
2014-04-29 14:29:46 +02:00
Björn Kimminich
c177f12e1d added test case for classpath suppression file and missing file
Former-commit-id: 975cbe1f480ad52b0e527148c4fd30b76d5baa0e
2014-04-29 11:48:07 +02:00
42 changed files with 25770 additions and 5037 deletions

View File

@@ -21,7 +21,7 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
<parent>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-parent</artifactId>
<version>1.2.0</version>
<version>1.2.1</version>
</parent>
<artifactId>dependency-check-ant</artifactId>

View File

@@ -866,7 +866,7 @@ public class DependencyCheckTask extends Task {
Engine engine = null;
try {
engine = new Engine();
engine = new Engine(DependencyCheckTask.class.getClassLoader());
for (Resource resource : path) {
final FileProvider provider = resource.as(FileProvider.class);
@@ -912,7 +912,7 @@ public class DependencyCheckTask extends Task {
LOGGER.log(Level.SEVERE, "Unable to connect to the dependency-check database; analysis has stopped");
LOGGER.log(Level.FINE, "", ex);
} finally {
Settings.cleanup();
Settings.cleanup(true);
if (engine != null) {
engine.cleanup();
}

View File

@@ -45,7 +45,7 @@ public class DependencyCheckTaskTest extends BuildFileTest {
public void tearDown() {
//no cleanup...
//executeTarget("cleanup");
Settings.cleanup();
Settings.cleanup(true);
}
/**

View File

@@ -21,7 +21,7 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
<parent>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-parent</artifactId>
<version>1.2.0</version>
<version>1.2.1</version>
</parent>
<artifactId>dependency-check-cli</artifactId>

View File

@@ -57,8 +57,13 @@ public class App {
* @param args the command line arguments
*/
public static void main(String[] args) {
final App app = new App();
app.run(args);
try {
Settings.initialize();
final App app = new App();
app.run(args);
} finally {
Settings.cleanup(true);
}
}
/**
@@ -67,8 +72,8 @@ public class App {
* @param args the command line arguments
*/
public void run(String[] args) {
final CliParser cli = new CliParser();
try {
cli.parse(args);
} catch (FileNotFoundException ex) {
@@ -140,7 +145,6 @@ public class App {
LOGGER.log(Level.SEVERE, "Unable to connect to the dependency-check database; analysis has stopped");
LOGGER.log(Level.FINE, "", ex);
} finally {
Settings.cleanup();
if (scanner != null) {
scanner.cleanup();
}
@@ -155,8 +159,6 @@ public class App {
*/
private void populateSettings(CliParser cli) {
Settings.initialize();
final boolean autoUpdate = cli.isAutoUpdate();
final String connectionTimeout = cli.getConnectionTimeout();
final String proxyUrl = cli.getProxyUrl();

View File

@@ -44,7 +44,7 @@ public class CliParserTest {
@AfterClass
public static void tearDownClass() throws Exception {
Settings.cleanup();
Settings.cleanup(true);
}
@Before

View File

@@ -21,7 +21,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
<parent>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-parent</artifactId>
<version>1.2.0</version>
<version>1.2.1</version>
</parent>
<artifactId>dependency-check-core</artifactId>
@@ -662,11 +662,11 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
Additionally, these are only added when using "allTests" to
make the build slightly faster in most cases. -->
<id>False Positive Tests</id>
<!--activation>
<activation>
<property>
<name>allTests</name>
</property>
</activation-->
</activation>
<dependencies>
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
@@ -689,6 +689,34 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.ganyo</groupId>
<artifactId>gcm-server</artifactId>
<version>1.0.2</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.python</groupId>
<artifactId>jython-standalone</artifactId>
<version>2.7-b1</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.jruby</groupId>
<artifactId>jruby-complete</artifactId>
<version>1.7.4</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.jruby</groupId>
<artifactId>jruby</artifactId>
<version>1.6.3</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
</dependencies>
</profile>
</profiles>

View File

@@ -888,7 +888,7 @@ public class DependencyCheckScanAgent {
"Unable to connect to the dependency-check database; analysis has stopped");
LOGGER.log(Level.FINE, "", ex);
} finally {
Settings.cleanup();
Settings.cleanup(true);
if (engine != null) {
engine.cleanup();
}

View File

@@ -27,6 +27,7 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -35,7 +36,9 @@ import java.util.logging.Logger;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.ArchiveInputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import org.apache.commons.compress.archivers.zip.ZipFile;
import org.apache.commons.compress.compressors.CompressorInputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
import org.apache.commons.compress.compressors.gzip.GzipUtils;
@@ -99,6 +102,11 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
*/
private static final Set<String> EXTENSIONS = newHashSet("tar", "gz", "tgz");
/**
* The set of file extensions to remove from the engine's collection of dependencies.
*/
private static final Set<String> REMOVE_FROM_ANALYSIS = newHashSet("zip", "tar", "gz", "tgz"); //TODO add nupkg, apk, sar?
static {
final String additionalZipExt = Settings.getString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS);
if (additionalZipExt != null) {
@@ -178,7 +186,7 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
if (tempFileLocation != null && tempFileLocation.exists()) {
LOGGER.log(Level.FINE, "Attempting to delete temporary files");
final boolean success = FileUtils.delete(tempFileLocation);
if (!success) {
if (!success && tempFileLocation != null & tempFileLocation.exists()) {
LOGGER.log(Level.WARNING, "Failed to delete some temporary files, see the log for more details");
}
}
@@ -199,9 +207,9 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
extractFiles(f, tmpDir, engine);
//make a copy
final List<Dependency> dependencies = new ArrayList<Dependency>(engine.getDependencies());
List<Dependency> dependencies = new ArrayList<Dependency>(engine.getDependencies());
engine.scan(tmpDir);
final List<Dependency> newDependencies = engine.getDependencies();
List<Dependency> newDependencies = engine.getDependencies();
if (dependencies.size() != newDependencies.size()) {
//get the new dependencies
final Set<Dependency> dependencySet = new HashSet<Dependency>();
@@ -229,6 +237,40 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
}
}
}
if (this.REMOVE_FROM_ANALYSIS.contains(dependency.getFileExtension())) {
if ("zip".equals(dependency.getFileExtension()) && isZipFileActuallyJarFile(dependency)) {
final File tdir = getNextTempDirectory();
final String fileName = dependency.getFileName();
LOGGER.info(String.format("The zip file '%s' appears to be a JAR file, making a deep copy and analyzing it as a JAR.", fileName));
final File tmpLoc = new File(tdir, fileName.substring(0, fileName.length() - 3) + "jar");
try {
org.apache.commons.io.FileUtils.copyFile(tdir, tmpLoc);
dependencies = new ArrayList<Dependency>(engine.getDependencies());
engine.scan(tmpLoc);
newDependencies = engine.getDependencies();
if (dependencies.size() != newDependencies.size()) {
//get the new dependencies
final Set<Dependency> dependencySet = new HashSet<Dependency>();
dependencySet.addAll(newDependencies);
dependencySet.removeAll(dependencies);
if (dependencySet.size() != 1) {
LOGGER.info("Deep copy of ZIP to JAR file resulted in more then one dependency?");
}
for (Dependency d : dependencySet) {
//fix the dependency's display name and path
d.setFilePath(dependency.getFilePath());
d.setDisplayFileName(dependency.getFileName());
}
}
} catch (IOException ex) {
final String msg = String.format("Unable to perform deep copy on '%s'", dependency.getActualFile().getPath());
LOGGER.log(Level.FINE, msg, ex);
}
}
engine.getDependencies().remove(dependency);
}
Collections.sort(engine.getDependencies());
}
@@ -411,4 +453,38 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
}
}
}
/**
* Attempts to determine if a zip file is actually a JAR file.
*
* @param dependency the dependency to check
* @return true if the dependency appears to be a JAR file; otherwise false
*/
private boolean isZipFileActuallyJarFile(Dependency dependency) {
boolean isJar = false;
ZipFile zip = null;
try {
zip = new ZipFile(dependency.getActualFilePath());
if (zip.getEntry("META-INF/MANIFEST.MF") != null
|| zip.getEntry("META-INF/maven") != null) {
final Enumeration<ZipArchiveEntry> entries = zip.getEntries();
while (entries.hasMoreElements()) {
final ZipArchiveEntry entry = entries.nextElement();
if (!entry.isDirectory()) {
final String name = entry.getName().toLowerCase();
if (name.endsWith(".class")) {
isJar = true;
break;
}
}
}
}
} catch (IOException ex) {
LOGGER.log(Level.FINE, String.format("Unable to unzip zip file '%s'", dependency.getFilePath()), ex);
} finally {
ZipFile.closeQuietly(zip);
}
return isJar;
}
}

View File

@@ -73,7 +73,7 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
/**
* Logger
*/
private static final Logger LOGGER = Logger.getLogger(AssemblyAnalyzer.class.getName());
private static final Logger LOGGER = Logger.getLogger(AssemblyAnalyzer.class.getName(), "dependencycheck-resources");
/**
* Builds the beginnings of a List for ProcessBuilder
@@ -106,7 +106,7 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
public void analyzeFileType(Dependency dependency, Engine engine)
throws AnalysisException {
if (grokAssemblyExe == null) {
LOGGER.warning("GrokAssembly didn't get deployed");
LOGGER.warning("analyzer.AssemblyAnalyzer.notdeployed");
return;
}
@@ -114,16 +114,30 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
args.add(dependency.getActualFilePath());
final ProcessBuilder pb = new ProcessBuilder(args);
BufferedReader rdr = null;
Document doc = null;
try {
final Process proc = pb.start();
// Try evacuating the error stream
rdr = new BufferedReader(new InputStreamReader(proc.getErrorStream(), "UTF-8"));
String line = null;
while (rdr.ready() && (line = rdr.readLine()) != null) {
LOGGER.log(Level.WARNING, "Error from GrokAssembly: {0}", line);
LOGGER.log(Level.WARNING, "analyzer.AssemblyAnalyzer.grokassembly.stderr", line);
}
int rc = 0;
final Document doc = builder.parse(proc.getInputStream());
doc = builder.parse(proc.getInputStream());
try {
rc = proc.waitFor();
} catch (InterruptedException ie) {
return;
}
if (rc == 3) {
LOGGER.log(Level.FINE, "analyzer.AssemblyAnalyzer.notassembly", dependency.getActualFilePath());
return;
} else if (rc != 0) {
LOGGER.log(Level.WARNING, "analyzer.AssemblyAnalyzer.grokassembly.rc", rc);
}
final XPath xpath = XPathFactory.newInstance().newXPath();
// First, see if there was an error
@@ -150,18 +164,6 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
product, Confidence.HIGH));
}
try {
rc = proc.waitFor();
} catch (InterruptedException ie) {
return;
}
if (rc == 3) {
LOGGER.log(Level.INFO, "{0} is not a valid assembly", dependency.getActualFilePath());
return;
} else if (rc != 0) {
LOGGER.log(Level.WARNING, "Return code {0} from GrokAssembly", rc);
}
} catch (IOException ioe) {
throw new AnalysisException(ioe);
} catch (SAXException saxe) {
@@ -201,9 +203,9 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
grokAssemblyExe = tempFile;
// Set the temp file to get deleted when we're done
grokAssemblyExe.deleteOnExit();
LOGGER.log(Level.FINE, "Extracted GrokAssembly.exe to {0}", grokAssemblyExe.getPath());
LOGGER.log(Level.FINE, "analyzer.AssemblyAnalyzer.grokassembly.deployed", grokAssemblyExe.getPath());
} catch (IOException ioe) {
LOGGER.log(Level.WARNING, "Could not extract GrokAssembly.exe: {0}", ioe.getMessage());
LOGGER.log(Level.WARNING, "analyzer.AssemblyAnalyzer.grokassembly.notdeployed", ioe.getMessage());
throw new AnalysisException("Could not extract GrokAssembly.exe", ioe);
} finally {
if (fos != null) {
@@ -246,9 +248,8 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
if (e instanceof AnalysisException) {
throw (AnalysisException) e;
} else {
LOGGER.warning("An error occured with the .NET AssemblyAnalyzer; "
+ "this can be ignored unless you are scanning .NET DLLs. Please see the log for more details.");
LOGGER.log(Level.FINE, "Could not execute GrokAssembly {0}", e.getMessage());
LOGGER.warning("analyzer.AssemblyAnalyzer.grokassembly.initialization.failed");
LOGGER.log(Level.FINE, "analyzer.AssemblyAnalyzer.grokassembly.initialization.message", e.getMessage());
throw new AnalysisException("An error occured with the .NET AssemblyAnalyzer", e);
}
} finally {
@@ -272,7 +273,7 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
grokAssemblyExe.deleteOnExit();
}
} catch (SecurityException se) {
LOGGER.fine("Can't delete temporary GrokAssembly.exe");
LOGGER.fine("analyzer.AssemblyAnalyzer.grokassembly.notdeleted");
}
}

View File

@@ -57,6 +57,7 @@ import org.owasp.dependencycheck.utils.DependencyVersionUtil;
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class CPEAnalyzer implements Analyzer {
/**
* The Logger.
*/
@@ -90,6 +91,11 @@ public class CPEAnalyzer implements Analyzer {
*/
private CveDB cve;
/**
* The URL to perform a search of the NVD CVE data at NIST.
*/
public static final String NVD_SEARCH_URL = "https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=%s";
/**
* Returns the name of this analyzer.
*
@@ -524,7 +530,9 @@ public class CPEAnalyzer implements Analyzer {
}
if (dbVer == null //special case, no version specified - everything is vulnerable
|| evVer.equals(dbVer)) { //yeah! exact match
final String url = String.format("http://web.nvd.nist.gov/view/vuln/search?cpe=%s", URLEncoder.encode(vs.getName(), "UTF-8"));
//final String url = String.format("http://web.nvd.nist.gov/view/vuln/search?cpe=%s", URLEncoder.encode(vs.getName(), "UTF-8"));
final String url = String.format(NVD_SEARCH_URL, URLEncoder.encode(vs.getName(), "UTF-8"));
final IdentifierMatch match = new IdentifierMatch("cpe", vs.getName(), url, IdentifierConfidence.EXACT_MATCH, conf);
collected.add(match);
} else {
@@ -549,7 +557,7 @@ public class CPEAnalyzer implements Analyzer {
}
}
final String cpeName = String.format("cpe:/a:%s:%s:%s", vendor, product, bestGuess.toString());
final String url = null; //String.format("http://web.nvd.nist.gov/view/vuln/search?cpe=%s", URLEncoder.encode(cpeName, "UTF-8"));
final String url = null;
if (bestGuessConf == null) {
bestGuessConf = Confidence.LOW;
}

View File

@@ -88,6 +88,7 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
removeBadMatches(dependency);
removeWrongVersionMatches(dependency);
removeSpuriousCPE(dependency);
removeDuplicativeEntriesFromJar(dependency, engine);
addFalseNegativeCPEs(dependency);
}
@@ -181,27 +182,6 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
if (coreCPE.matches() && !coreFiles.matches()) {
itr.remove();
}
//replaced with the regex above.
// if (("cpe:/a:sun:java".equals(i.getValue())
// || "cpe:/a:oracle:java".equals(i.getValue())
// || "cpe:/a:ibm:java".equals(i.getValue())
// || "cpe:/a:sun:j2se".equals(i.getValue())
// || "cpe:/a:oracle:j2se".equals(i.getValue())
// || i.getValue().startsWith("cpe:/a:sun:java:")
// || i.getValue().startsWith("cpe:/a:sun:j2se:")
// || i.getValue().startsWith("cpe:/a:sun:java:jre")
// || i.getValue().startsWith("cpe:/a:sun:java:jdk")
// || i.getValue().startsWith("cpe:/a:sun:java_se")
// || i.getValue().startsWith("cpe:/a:oracle:java_se")
// || i.getValue().startsWith("cpe:/a:oracle:java:")
// || i.getValue().startsWith("cpe:/a:oracle:j2se:")
// || i.getValue().startsWith("cpe:/a:oracle:jre")
// || i.getValue().startsWith("cpe:/a:oracle:jdk")
// || i.getValue().startsWith("cpe:/a:ibm:java:"))
// && !dependency.getFileName().toLowerCase().endsWith("rt.jar")) {
// itr.remove();
// }
}
}
@@ -248,16 +228,27 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
//TODO move this startsWith expression to a configuration file?
if ("cpe".equals(i.getType())) {
if ((i.getValue().matches(".*c\\+\\+.*")
|| i.getValue().startsWith("cpe:/a:jquery:jquery")
|| i.getValue().startsWith("cpe:/a:prototypejs:prototype")
|| i.getValue().startsWith("cpe:/a:yahoo:yui")
|| i.getValue().startsWith("cpe:/a:file:file")
|| i.getValue().startsWith("cpe:/a:mozilla:mozilla")
|| i.getValue().startsWith("cpe:/a:cvs:cvs")
|| i.getValue().startsWith("cpe:/a:ftp:ftp")
|| i.getValue().startsWith("cpe:/a:ssh:ssh"))
|| i.getValue().startsWith("cpe:/a:tcp:tcp")
|| i.getValue().startsWith("cpe:/a:ssh:ssh")
|| i.getValue().startsWith("cpe:/a:lookup:lookup"))
&& (dependency.getFileName().toLowerCase().endsWith(".jar")
|| dependency.getFileName().toLowerCase().endsWith("pom.xml"))) {
|| dependency.getFileName().toLowerCase().endsWith("pom.xml")
|| dependency.getFileName().toLowerCase().endsWith(".dll")
|| dependency.getFileName().toLowerCase().endsWith(".exe")
|| dependency.getFileName().toLowerCase().endsWith(".nuspec")
|| dependency.getFileName().toLowerCase().endsWith(".nupkg"))) {
itr.remove();
} else if ((i.getValue().startsWith("cpe:/a:jquery:jquery")
|| i.getValue().startsWith("cpe:/a:prototypejs:prototype")
|| i.getValue().startsWith("cpe:/a:yahoo:yui"))
&& (dependency.getFileName().toLowerCase().endsWith(".jar")
|| dependency.getFileName().toLowerCase().endsWith("pom.xml")
|| dependency.getFileName().toLowerCase().endsWith(".dll")
|| dependency.getFileName().toLowerCase().endsWith(".exe"))) {
itr.remove();
} else if (i.getValue().startsWith("cpe:/a:apache:maven")
&& !dependency.getFileName().toLowerCase().matches("maven-core-[\\d\\.]+\\.jar")) {
@@ -266,7 +257,7 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
&& !dependency.getEvidenceUsed().containsUsedString("m-core")) {
itr.remove();
} else if (i.getValue().startsWith("cpe:/a:jboss:jboss")
&& !dependency.getFileName().toLowerCase().matches("jboss-[\\d\\.]+(GA)?\\.jar")) {
&& !dependency.getFileName().toLowerCase().matches("jboss-?[\\d\\.-]+(GA)?\\.jar")) {
itr.remove();
}
}
@@ -314,6 +305,7 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
* @param dependency the dependency being analyzed
*/
private void addFalseNegativeCPEs(Dependency dependency) {
//TODO move this to the hint analyzer
final Iterator<Identifier> itr = dependency.getIdentifiers().iterator();
while (itr.hasNext()) {
final Identifier i = itr.next();
@@ -329,20 +321,92 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
try {
dependency.addIdentifier("cpe",
newCpe,
String.format("http://web.nvd.nist.gov/view/vuln/search?cpe=%s", URLEncoder.encode(newCpe, "UTF-8")));
String.format(CPEAnalyzer.NVD_SEARCH_URL, URLEncoder.encode(newCpe, "UTF-8")));
dependency.addIdentifier("cpe",
newCpe2,
String.format("http://web.nvd.nist.gov/view/vuln/search?cpe=%s", URLEncoder.encode(newCpe2, "UTF-8")));
String.format(CPEAnalyzer.NVD_SEARCH_URL, URLEncoder.encode(newCpe2, "UTF-8")));
dependency.addIdentifier("cpe",
newCpe3,
String.format("http://web.nvd.nist.gov/view/vuln/search?cpe=%s", URLEncoder.encode(newCpe3, "UTF-8")));
String.format(CPEAnalyzer.NVD_SEARCH_URL, URLEncoder.encode(newCpe3, "UTF-8")));
dependency.addIdentifier("cpe",
newCpe4,
String.format("http://web.nvd.nist.gov/view/vuln/search?cpe=%s", URLEncoder.encode(newCpe4, "UTF-8")));
String.format(CPEAnalyzer.NVD_SEARCH_URL, URLEncoder.encode(newCpe4, "UTF-8")));
} catch (UnsupportedEncodingException ex) {
LOGGER.log(Level.FINE, null, ex);
}
}
}
}
/**
* Removes duplicate entries identified that are contained within JAR files. These occasionally crop up due to POM
* entries or other types of files (such as DLLs and EXEs) being contained within the JAR.
*
* @param dependency the dependency that might be a duplicate
* @param engine the engine used to scan all dependencies
*/
private void removeDuplicativeEntriesFromJar(Dependency dependency, Engine engine) {
if (dependency.getFileName().toLowerCase().endsWith("pom.xml")
|| "dll".equals(dependency.getFileExtension())
|| "exe".equals(dependency.getFileExtension())) {
String parentPath = dependency.getFilePath().toLowerCase();
if (parentPath.contains(".jar")) {
parentPath = parentPath.substring(0, parentPath.indexOf(".jar") + 4);
final Dependency parent = findDependency(parentPath, engine.getDependencies());
if (parent != null) {
boolean remove = false;
for (Identifier i : dependency.getIdentifiers()) {
if ("cpe".equals(i.getType())) {
final String trimmedCPE = trimCpeToVendor(i.getValue());
for (Identifier parentId : parent.getIdentifiers()) {
if ("cpe".equals(parentId.getType()) && parentId.getValue().startsWith(trimmedCPE)) {
remove |= true;
}
}
}
if (!remove) { //we can escape early
return;
}
}
if (remove) {
engine.getDependencies().remove(dependency);
}
}
}
}
}
/**
* Retrieves a given dependency, based on a given path, from a list of dependencies.
*
* @param dependencyPath the path of the dependency to return
* @param dependencies the collection of dependencies to search
* @return the dependency object for the given path, otherwise null
*/
private Dependency findDependency(String dependencyPath, List<Dependency> dependencies) {
for (Dependency d : dependencies) {
if (d.getFilePath().equalsIgnoreCase(dependencyPath)) {
return d;
}
}
return null;
}
/**
* Takes a full CPE and returns the CPE trimmed to include only vendor and product.
*
* @param value the CPE value to trim
* @return a CPE value that only includes the vendor and product
*/
private String trimCpeToVendor(String value) {
//cpe:/a:jruby:jruby:1.0.8
final int pos1 = value.indexOf(":", 7); //right of vendor
final int pos2 = value.indexOf(":", pos1 + 1); //right of product
if (pos2 < 0) {
return value;
} else {
return value.substring(0, pos2);
}
}
}

View File

@@ -138,7 +138,8 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
"include-resource",
"embed-dependency",
"ipojo-components",
"ipojo-extension");
"ipojo-extension",
"eclipse-sourcereferences");
/**
* item in some manifest, should be considered medium confidence.
*/
@@ -690,7 +691,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
&& !dependency.getFileName().toLowerCase().endsWith("-javadoc.jar")
&& !dependency.getFileName().toLowerCase().endsWith("-src.jar")
&& !dependency.getFileName().toLowerCase().endsWith("-doc.jar")) {
LOGGER.log(Level.INFO,
LOGGER.log(Level.FINE,
String.format("Jar file '%s' does not contain a manifest.",
dependency.getFileName()));
}
@@ -764,6 +765,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
&& !key.endsWith("class-path")
&& !key.endsWith("-scm") //todo change this to a regex?
&& !key.startsWith("scm-")
&& !value.trim().startsWith("scm:")
&& !isImportPackage(key, value)
&& !isPackage(key, value)) {

View File

@@ -46,6 +46,7 @@ import org.owasp.dependencycheck.utils.Pair;
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class CveDB {
/**
* The logger.
*/
@@ -733,8 +734,10 @@ public class CveDB {
final boolean isStruts = "apache".equals(vendor) && "struts".equals(product);
final DependencyVersion v = parseDependencyVersion(cpeId);
final boolean prevAffected = previous != null && !previous.isEmpty();
if (identifiedVersion == null || "-".equals(identifiedVersion.toString())) {
if (v == null || "-".equals(v.toString())) {
if (v == null || "-".equals(v.toString())) { //all versions
affected = true;
} else if (identifiedVersion == null || "-".equals(identifiedVersion.toString())) {
if (prevAffected) {
affected = true;
}
} else if (identifiedVersion.equals(v) || (prevAffected && identifiedVersion.compareTo(v) < 0)) {

View File

@@ -178,7 +178,9 @@ public class StandardUpdate {
if (maxUpdates >= 1) { //ensure the modified file date gets written (we may not have actually updated it)
properties.save(updateable.get(MODIFIED));
LOGGER.log(Level.INFO, "Begin database maintenance.");
cveDB.cleanupDatabase();
LOGGER.log(Level.INFO, "End database maintenance.");
}
} finally {
closeDataStores();

View File

@@ -203,7 +203,7 @@ public class CallableDownloadTask implements Callable<Future<ProcessTask>> {
LOGGER.log(Level.WARNING, msg);
LOGGER.log(Level.FINE, "Download Task Failed", ex);
} finally {
Settings.cleanup();
Settings.cleanup(false);
}
return null;
}

View File

@@ -119,7 +119,7 @@ public class ProcessTask implements Callable<ProcessTask> {
} catch (UpdateException ex) {
this.exception = ex;
} finally {
Settings.cleanup();
Settings.cleanup(false);
}
return this;
}

View File

@@ -177,6 +177,33 @@ public class Dependency implements Comparable<Dependency> {
this.filePath = filePath;
}
/**
* The file name to display in reports.
*/
private String displayName = null;
/**
* Sets the file name to display in reports.
*
* @param displayName the name to display
*/
public void setDisplayFileName(String displayName) {
this.displayName = displayName;
}
/**
* Returns the file name to display in reports; if no display file name has been set it will default to the actual
* file name.
*
* @return the file name to display
*/
public String getDisplayFileName() {
if (displayName == null) {
return this.fileName;
}
return this.displayName;
}
/**
* <p>
* Gets the file path of the dependency.</p>
@@ -369,6 +396,15 @@ public class Dependency implements Comparable<Dependency> {
return EvidenceCollection.merge(this.productEvidence, this.vendorEvidence, this.versionEvidence);
}
/**
* Returns the evidence used to identify this dependency.
*
* @return an EvidenceCollection.
*/
public Set<Evidence> getEvidenceForDisplay() {
return EvidenceCollection.mergeForDisplay(this.productEvidence, this.vendorEvidence, this.versionEvidence);
}
/**
* Returns the evidence used to identify this dependency.
*

View File

@@ -220,22 +220,95 @@ public class Evidence implements Comparable<Evidence> {
* @return an integer indicating the ordering of the two objects
*/
public int compareTo(Evidence o) {
if (source.equals(o.source)) {
if (name.equals(o.name)) {
if (value.equals(o.value)) {
if (confidence.equals(o.confidence)) {
if (o == null) {
return 1;
}
if (equalsWithNullCheck(source, o.source)) {
if (equalsWithNullCheck(name, o.name)) {
if (equalsWithNullCheck(value, o.value)) {
if (equalsWithNullCheck(confidence, o.confidence)) {
return 0; //they are equal
} else {
return confidence.compareTo(o.confidence);
return compareToWithNullCheck(confidence, o.confidence);
}
} else {
return value.compareToIgnoreCase(o.value);
return compareToIgnoreCaseWithNullCheck(value, o.value);
}
} else {
return name.compareToIgnoreCase(o.name);
return compareToIgnoreCaseWithNullCheck(name, o.name);
}
} else {
return source.compareToIgnoreCase(o.source);
return compareToIgnoreCaseWithNullCheck(source, o.source);
}
}
/**
* Equality check with an exhaustive, possibly duplicative, check against nulls.
*
* @param me the value to be compared
* @param other the other value to be compared
* @return true if the values are equal; otherwise false
*/
private boolean equalsWithNullCheck(String me, String other) {
if (me == null && other == null) {
return true;
} else if (me == null || other == null) {
return false;
}
return me.equals(other);
}
/**
* Equality check with an exhaustive, possibly duplicative, check against nulls.
*
* @param me the value to be compared
* @param other the other value to be compared
* @return true if the values are equal; otherwise false
*/
private boolean equalsWithNullCheck(Confidence me, Confidence other) {
if (me == null && other == null) {
return true;
} else if (me == null || other == null) {
return false;
}
return me.equals(other);
}
/**
* Wrapper around {@link java.lang.String#compareToIgnoreCase(java.lang.String) String.compareToIgnoreCase} with an
* exhaustive, possibly duplicative, check against nulls.
*
* @param me the value to be compared
* @param other the other value to be compared
* @return true if the values are equal; otherwise false
*/
private int compareToIgnoreCaseWithNullCheck(String me, String other) {
if (me == null && other == null) {
return 0;
} else if (me == null) {
return -1; //the other string is greater then me
} else if (other == null) {
return 1; //me is greater then the other string
}
return me.compareToIgnoreCase(other);
}
/**
* Wrapper around {@link java.lang.Enum#compareTo(java.lang.Enum) Enum.compareTo} with an exhaustive, possibly
* duplicative, check against nulls.
*
* @param me the value to be compared
* @param other the other value to be compared
* @return true if the values are equal; otherwise false
*/
private int compareToWithNullCheck(Confidence me, Confidence other) {
if (me == null && other == null) {
return 0;
} else if (me == null) {
return -1; //the other string is greater then me
} else if (other == null) {
return 1; //me is greater then the other string
}
return me.compareTo(other);
}
}

View File

@@ -311,6 +311,26 @@ public class EvidenceCollection implements Iterable<Evidence> {
return ret;
}
/**
* Merges multiple EvidenceCollections together; flattening all of the evidence items by removing the confidence.
*
* @param ec One or more EvidenceCollections
* @return new set of evidence resulting from merging the evidence in the collections
*/
public static Set<Evidence> mergeForDisplay(EvidenceCollection... ec) {
final Set<Evidence> ret = new TreeSet<Evidence>();
for (EvidenceCollection col : ec) {
for (Evidence e : col) {
if (e.isUsed()) {
final Evidence newEvidence = new Evidence(e.getSource(), e.getName(), e.getValue(), null);
newEvidence.setUsed(true);
ret.add(newEvidence);
}
}
}
return ret;
}
/**
* Returns a string of evidence 'values'.
*

View File

@@ -77,19 +77,19 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
if (cpeName != null && cpeName.length() > 7) {
final String[] data = cpeName.substring(7).split(":");
if (data.length >= 1) {
this.setVendor(URLDecoder.decode(data[0].replace("+", "%2B"), "UTF-8"));
this.setVendor(urlDecode(data[0]));
}
if (data.length >= 2) {
this.setProduct(URLDecoder.decode(data[1].replace("+", "%2B"), "UTF-8"));
this.setProduct(urlDecode(data[1]));
}
if (data.length >= 3) {
version = URLDecoder.decode(data[2].replace("+", "%2B"), "UTF-8");
version = urlDecode(data[2]);
}
if (data.length >= 4) {
revision = URLDecoder.decode(data[3].replace("+", "%2B"), "UTF-8");
revision = urlDecode(data[3]);
}
if (data.length >= 5) {
edition = URLDecoder.decode(data[4].replace("+", "%2B"), "UTF-8");
edition = urlDecode(data[4]);
}
}
}
@@ -341,4 +341,25 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
public void setEdition(String edition) {
this.edition = edition;
}
/**
* Replaces '+' with '%2B' and then URL Decodes the string attempting first UTF-8, then ASCII, then default.
*
* @param string the string to URL Decode
* @return the URL Decoded string
*/
private String urlDecode(String string) {
final String text = string.replace("+", "%2B");
String result;
try {
result = URLDecoder.decode(text, "UTF-8");
} catch (UnsupportedEncodingException ex) {
try {
result = URLDecoder.decode(text, "ASCII");
} catch (UnsupportedEncodingException ex1) {
result = URLDecoder.decode(text);
}
}
return result;
}
}

View File

@@ -247,9 +247,11 @@ public final class Settings {
/**
* Cleans up resources to prevent memory leaks.
*
* @param deleteTemporary flag indicating whether any temporary directories generated should be removed
*/
public static void cleanup() {
if (tempDirectory != null && tempDirectory.exists()) {
public static void cleanup(boolean deleteTemporary) {
if (deleteTemporary && tempDirectory != null && tempDirectory.exists()) {
FileUtils.delete(tempDirectory);
}
try {

View File

@@ -0,0 +1,10 @@
analyzer.AssemblyAnalyzer.notdeployed=GrokAssembly didn't get deployed
analyzer.AssemblyAnalyzer.grokassembly.stderr=Error from GrokAssembly: {0}
analyzer.AssemblyAnalyzer.notassembly={0} is not a .NET assembly or executable and as such cannot be analyzed by dependency-check
analyzer.AssemblyAnalyzer.grokassembly.rc=Return code {0} from GrokAssembly
analyzer.AssemblyAnalyzer.grokassembly.deployed=Extracted GrokAssembly.exe to {0}
analyzer.AssemblyAnalyzer.grokassembly.notdeployed=Could not extract GrokAssembly.exe: {0}
analyzer.AssemblyAnalyzer.grokassembly.initlization.failed=An error occurred with the .NET AssemblyAnalyzer; \
this can be ignored unless you are scanning .NET DLLs. Please see the log for more details.
analyzer.AssemblyAnalyzer.grokassembly.initialization.message=Could not execute GrokAssembly {0}
analyzer.AssemblyAnalyzer.grokassembly.notdeleted=Can't delete temporary GrokAssembly.exe

View File

@@ -532,11 +532,11 @@ arising out of or in connection with the use of this tool, the analysis performe
#foreach($dependency in $dependencies)
#set($lnkcnt=$lnkcnt+1)
<li class="#if($dependency.getVulnerabilities().size()==0)notvulnerable#else vulnerable#end">
<a href="#l${lnkcnt}_$enc.html($enc.url($dependency.Sha1sum))">$enc.html($dependency.FileName)</a>
<a href="#l${lnkcnt}_$enc.html($enc.url($dependency.Sha1sum))">$enc.html($dependency.DisplayFileName)</a>
#if($dependency.getRelatedDependencies().size()>0)
<ul>
#foreach($related in $dependency.getRelatedDependencies())
<li>$enc.html($related.FileName)</li>
<li>$enc.html($related.DisplayFileName)</li>
#end
</ul>
#end
@@ -549,7 +549,7 @@ arising out of or in connection with the use of this tool, the analysis performe
#set($vsctr=0) ##counter to create unique groups for vulnerable software
#foreach($dependency in $dependencies)
#set($lnkcnt=$lnkcnt+1)
<h3 class="subsectionheader standardsubsection#if($dependency.getVulnerabilities().size()==0) notvulnerable#end"><a name="l${lnkcnt}_$enc.html($dependency.Sha1sum)"></a>$enc.html($dependency.FileName)</h3>
<h3 class="subsectionheader standardsubsection#if($dependency.getVulnerabilities().size()==0) notvulnerable#end"><a name="l${lnkcnt}_$enc.html($dependency.Sha1sum)"></a>$enc.html($dependency.DisplayFileName)</h3>
<div class="subsectioncontent#if($dependency.getVulnerabilities().size()==0) notvulnerable#end">
#if ($dependency.description)
<p><b>Description:</b>&nbsp;$enc.html($dependency.description)<br/></p>
@@ -571,7 +571,7 @@ arising out of or in connection with the use of this tool, the analysis performe
<div id="content$cnt" class="subsectioncontent standardsubsection hidden">
<table class="lined fullwidth" border="0">
<tr><th class="left" style="width:10%;">Source</th><th class="left" style="width:20%;">Name</th><th class="left" style="width:70%;">Value</th></tr>
#foreach($evidence in $dependency.getEvidenceUsed())
#foreach($evidence in $dependency.getEvidenceForDisplay())
<tr><td>$enc.html($evidence.getSource())</td><td>$enc.html($evidence.getName())</td><td>$enc.html($evidence.getValue())</td></tr>
#end
</table>
@@ -582,7 +582,7 @@ arising out of or in connection with the use of this tool, the analysis performe
<div id="content$cnt" class="subsectioncontent standardsubsection hidden">
<ul>
#foreach($related in $dependency.getRelatedDependencies())
<li>$enc.html($related.FileName)
<li>$enc.html($related.DisplayFileName)
<ul>
<li>File Path:&nbsp;$enc.html($related.FilePath)</li>
<li>SHA1:&nbsp;$enc.html($related.Sha1sum)</li>
@@ -612,7 +612,7 @@ arising out of or in connection with the use of this tool, the analysis performe
#end
#end
<h4 id="header$cnt" class="subsectionheader white">Identifiers</h4>
##:&nbsp;<a href="http://web.nvd.nist.gov/view/vuln/search-results?cpe=$enc.url($cpevalue)" target="_blank">$enc.html($cpevalue)</a></h4>
##:&nbsp;<a href="https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=$enc.url($cpevalue)" target="_blank">$enc.html($cpevalue)</a></h4>
<div id="content$cnt" class="subsectioncontent standardsubsection">
#if ($dependency.getIdentifiers().size()==0)
<ul><li><b>None</b></li></ul>
@@ -668,13 +668,20 @@ arising out of or in connection with the use of this tool, the analysis performe
</ul>
#end
</p>
<p>Vulnerable Software &amp; Versions:&nbsp;(<a href="#" onclick="toggleDisplay(this,'.vs$vsctr'); return false;">show all</a>)<ul>
<li class="vs$vsctr"><a target="_blank" href="http://web.nvd.nist.gov/view/vuln/search-results?cpe=$enc.url($vuln.matchedCPE)">$enc.html($vuln.matchedCPE)</a> #if($vuln.hasMatchedAllPreviousCPE()) and all previous versions#end</li>
<li class="vs$vsctr">...</li>
#foreach($vs in $vuln.getVulnerableSoftware())
<li class="vs$vsctr hidden"><a target="_blank" href="http://web.nvd.nist.gov/view/vuln/search-results?cpe=$enc.url($vs.name)">$enc.html($vs.name)</a> #if($vs.hasPreviousVersion()) and all previous versions#end</li>
#if ($vuln.getVulnerableSoftware().size()<2)
<p>Vulnerable Software &amp; 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>
</ul></p>
#else
<p>Vulnerable Software &amp; Versions:&nbsp;(<a href="#" onclick="toggleDisplay(this,'.vs$vsctr'); return false;">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">...</li>
#foreach($vs in $vuln.getVulnerableSoftware())
<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
</ul></p>
#end
</div>
#end
@@ -692,7 +699,7 @@ arising out of or in connection with the use of this tool, the analysis performe
#foreach($dependency in $dependencies)
#if ($dependency.getSuppressedIdentifiers().size()>0 || $dependency.getSuppressedVulnerabilities().size()>0)
#set($lnkcnt=$lnkcnt+1)
<h3 class="subsectionheader standardsubsection">$enc.html($dependency.FileName)</h3>
<h3 class="subsectionheader standardsubsection">$enc.html($dependency.DisplayFileName)</h3>
<div class="subsectioncontent">
#if ($dependency.description)
<p><b>Description:</b>&nbsp;$enc.html($dependency.description)<br/></p>
@@ -714,7 +721,7 @@ arising out of or in connection with the use of this tool, the analysis performe
<div id="content$cnt" class="subsectioncontent standardsubsection hidden">
<table class="lined fullwidth" border="0">
<tr><th class="left" style="width:10%;">Source</th><th class="left" style="width:20%;">Name</th><th class="left" style="width:70%;">Value</th></tr>
#foreach($evidence in $dependency.getEvidenceUsed())
#foreach($evidence in $dependency.getEvidenceForDisplay())
<tr><td>$enc.html($evidence.getSource())</td><td>$enc.html($evidence.getName())</td><td>$enc.html($evidence.getValue())</td></tr>
#end
</table>
@@ -725,7 +732,7 @@ arising out of or in connection with the use of this tool, the analysis performe
<div id="content$cnt" class="subsectioncontent standardsubsection hidden">
<ul>
#foreach($related in $dependency.getRelatedDependencies())
<li>$enc.html($related.FileName)
<li>$enc.html($related.DisplayFileName)
<ul>
<li>File Path:&nbsp;$enc.html($related.FilePath)</li>
<li>SHA1:&nbsp;$enc.html($related.Sha1sum)</li>
@@ -744,7 +751,7 @@ arising out of or in connection with the use of this tool, the analysis performe
#end
#end
<h4 id="header$cnt" class="subsectionheader white">Suppressed Identifiers</h4>
##:&nbsp;<a href="http://web.nvd.nist.gov/view/vuln/search-results?cpe=$enc.url($cpevalue)" target="_blank">$enc.html($cpevalue)</a></h4>
##:&nbsp;<a href="https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=$enc.url($cpevalue)" target="_blank">$enc.html($cpevalue)</a></h4>
<div id="content$cnt" class="subsectioncontent standardsubsection">
#if ($dependency.getSuppressedIdentifiers().size()==0)
<ul><li><b>None</b></li></ul>
@@ -796,13 +803,19 @@ arising out of or in connection with the use of this tool, the analysis performe
</ul>
#end
</p>
<p>Vulnerable Software &amp; Versions:&nbsp;(<a href="#" onclick="toggleDisplay(this,'.vs$vsctr'); return false;">show all</a>)<ul>
<li class="vs$vsctr"><a target="_blank" href="http://web.nvd.nist.gov/view/vuln/search-results?cpe=$enc.url($vuln.matchedCPE)">$enc.html($vuln.matchedCPE)</a> #if($vuln.hasMatchedAllPreviousCPE()) and all previous versions#end</li>
<li class="vs$vsctr">...</li>
#foreach($vs in $vuln.getVulnerableSoftware())
<li class="vs$vsctr hidden"><a target="_blank" href="http://web.nvd.nist.gov/view/vuln/search-results?cpe=$enc.url($vs.name)">$enc.html($vs.name)</a> #if($vs.hasPreviousVersion()) and all previous versions#end</li>
#if ($vuln.getVulnerableSoftware().size()<2)
<p>Vulnerable Software &amp; Versions:<ul>
git st<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>
#else
<p>Vulnerable Software &amp; Versions:&nbsp;(<a href="#" onclick="toggleDisplay(this,'.vs$vsctr'); return false;">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">...</li>
#foreach($vs in $vuln.getVulnerableSoftware())
<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
</ul></p>
#end
</div>
#end

View File

@@ -222,10 +222,10 @@ arising out of or in connection with the use of this tool, the analysis performe
($vuln.cvssScore)
<td>#set($cnt=$cnt+1)
#if($dependency.getRelatedDependencies().size()>0)<span id="header$cnt" class="expandable collapsedList">#end
$enc.html($dependency.FileName)
$enc.html($dependency.DisplayFileName)
#if($dependency.getRelatedDependencies().size()>0)&nbsp;&nbsp;&nbsp;</span><div id="content$cnt" class="hidden">#end
#foreach($related in $dependency.getRelatedDependencies())
$enc.html($related.FileName)<br/>
$enc.html($related.DisplayFileName)<br/>
#end
#if($dependency.getRelatedDependencies().size()>0)</div#end
</td>

View File

@@ -36,7 +36,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
<dependencies>
#foreach($dependency in $dependencies)
<dependency>
<fileName>$enc.xml($dependency.FileName)</fileName>
<fileName>$enc.xml($dependency.DisplayFileName)</fileName>
<filePath>$enc.xml($dependency.FilePath)</filePath>
<md5>$enc.xml($dependency.Md5sum)</md5>
<sha1>$enc.xml($dependency.Sha1sum)</sha1>
@@ -68,7 +68,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
</relatedDependencies>
#end
<evidenceCollected>
#foreach($evidence in $dependency.getEvidenceUsed())
#foreach($evidence in $dependency.getEvidenceForDisplay())
<evidence>
<source>$enc.xml($evidence.getSource())</source>
<name>$enc.xml($evidence.getName())</name>

View File

@@ -32,6 +32,6 @@ public class BaseTest {
@AfterClass
public static void tearDownClass() throws Exception {
Settings.cleanup();
Settings.cleanup(true);
}
}

View File

@@ -17,31 +17,78 @@
*/
package org.owasp.dependencycheck.analyzer;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import org.junit.Before;
import org.junit.Test;
import org.owasp.dependencycheck.BaseTest;
import org.owasp.dependencycheck.Engine;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.suppression.SuppressionParseException;
import org.owasp.dependencycheck.suppression.SuppressionRule;
import org.owasp.dependencycheck.utils.Settings;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
/**
*
* @author Jeremy Long <jeremy.long@owasp.org>
*/
public class AbstractSuppressionAnalyzerTest extends BaseTest {
private AbstractSuppressionAnalyzer instance;
@Before
public void setUp() throws Exception {
public void createObjectUnderTest() throws Exception {
instance = new AbstractSuppressionAnalyzerImpl();
}
/**
* Test of getSupportedExtensions method, of class AbstractSuppressionAnalyzer.
*/
@Test
public void testGetSupportedExtensions() {
Set<String> result = instance.getSupportedExtensions();
assertNull(result);
}
/**
* Test of getRules method, of class AbstractSuppressionAnalyzer for suppression file declared as URL.
*/
@Test
public void testGetRulesFromSuppressionFileFromURL() throws Exception {
setSupressionFileFromURL();
instance.initialize();
int expCount = 5;
List<SuppressionRule> result = instance.getRules();
assertEquals(expCount, result.size());
}
/**
* Test of getRules method, of class AbstractSuppressionAnalyzer for suppression file declared as URL.
*/
@Test
public void testGetRulesFromSuppressionFileInClasspath() throws Exception {
Settings.setString(Settings.KEYS.SUPPRESSION_FILE, "suppressions.xml");
instance.initialize();
int expCount = 5;
List<SuppressionRule> result = instance.getRules();
assertEquals(expCount, result.size());
}
@Test(expected = SuppressionParseException.class)
public void testFailureToLocateSuppressionFileAnywhere() throws Exception {
Settings.setString(Settings.KEYS.SUPPRESSION_FILE, "doesnotexist.xml");
instance.initialize();
}
private void setSupressionFileFromURL() throws Exception {
try {
final String uri = this.getClass().getClassLoader().getResource("suppressions.xml").toURI().toURL().toString();
Settings.setString(Settings.KEYS.SUPPRESSION_FILE, uri);
@@ -52,37 +99,6 @@ public class AbstractSuppressionAnalyzerTest extends BaseTest {
}
}
/**
* Test of getSupportedExtensions method, of class AbstractSuppressionAnalyzer.
*/
@Test
public void testGetSupportedExtensions() {
AbstractSuppressionAnalyzer instance = new AbstractSuppressionAnalyzerImpl();
Set<String> result = instance.getSupportedExtensions();
assertNull(result);
}
/**
* Test of initialize method, of class AbstractSuppressionAnalyzer.
*/
@Test
public void testInitialize() throws Exception {
AbstractSuppressionAnalyzer instance = new AbstractSuppressionAnalyzerImpl();
instance.initialize();
}
/**
* Test of getRules method, of class AbstractSuppressionAnalyzer.
*/
@Test
public void testGetRules() throws Exception {
AbstractSuppressionAnalyzer instance = new AbstractSuppressionAnalyzerImpl();
instance.initialize();
int expCount = 5;
List<SuppressionRule> result = instance.getRules();
assertEquals(expCount, result.size());
}
public class AbstractSuppressionAnalyzerImpl extends AbstractSuppressionAnalyzer {
@Override

View File

@@ -56,6 +56,7 @@ public class FalsePositiveAnalyzerTest {
public void testAnalyze() throws Exception {
Dependency dependency = new Dependency();
dependency.setFileName("pom.xml");
dependency.setFilePath("pom.xml");
dependency.addIdentifier("cpe", "cpe:/a:file:file:1.2.1", "http://some.org/url");
Engine engine = null;
FalsePositiveAnalyzer instance = new FalsePositiveAnalyzer();

View File

@@ -61,19 +61,26 @@ public class VulnerabilitySuppressionAnalyzerIntegrationTest extends AbstractDat
@Test
public void testAnalyze() throws Exception {
File file = new File(this.getClass().getClassLoader().getResource("FileHelpers.2.0.0.0.nupkg").getPath());
File suppression = new File(this.getClass().getClassLoader().getResource("FileHelpers.2.0.0.0.suppression.xml").getPath());
File file = new File(this.getClass().getClassLoader().getResource("commons-fileupload-1.2.1.jar").getPath());
File suppression = new File(this.getClass().getClassLoader().getResource("commons-fileupload-1.2.1.suppression.xml").getPath());
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, false);
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, false);
Engine engine = new Engine();
engine.scan(file);
engine.analyzeDependencies();
Dependency dependency = getDependency(engine, file);
assertTrue(dependency.getVulnerabilities().size() > 0);
int cveSize = dependency.getVulnerabilities().size();
int cpeSize = dependency.getIdentifiers().size();
assertTrue(cveSize > 0);
assertTrue(cpeSize > 0);
Settings.setString(Settings.KEYS.SUPPRESSION_FILE, suppression.getAbsolutePath());
VulnerabilitySuppressionAnalyzer instance = new VulnerabilitySuppressionAnalyzer();
instance.initialize();
instance.analyze(dependency, engine);
assertTrue(dependency.getVulnerabilities().size() == 0);
cveSize = cveSize > 1 ? cveSize - 2 : 0;
cpeSize = cpeSize > 0 ? cpeSize - 1 : 0;
assertTrue(dependency.getVulnerabilities().size() == cveSize);
assertTrue(dependency.getIdentifiers().size() == cpeSize);
engine.cleanup();
}

View File

@@ -17,8 +17,12 @@
*/
package org.owasp.dependencycheck.data.update;
import java.io.File;
import java.util.Calendar;
import org.junit.Before;
import org.junit.Test;
import org.owasp.dependencycheck.BaseTest;
import org.owasp.dependencycheck.utils.Settings;
/**
*
@@ -26,6 +30,32 @@ import org.owasp.dependencycheck.BaseTest;
*/
public class NvdCveUpdaterIntegrationTest extends BaseTest {
@Before
public void setUp() throws Exception {
int year = Calendar.getInstance().get(Calendar.YEAR);
if (year <= 2014) {
File f = new File(NvdCveUpdaterIntegrationTest.class.getClassLoader().getResource("nvdcve-2.0-2014.xml").getPath());
String baseURL = f.toURI().toURL().toString();
String modified12 = baseURL.replace("nvdcve-2.0-2014.xml", "nvdcve-modified.xml");
String modified20 = baseURL.replace("nvdcve-2.0-2014.xml", "nvdcve-2.0-modified.xml");
String full12 = baseURL.replace("nvdcve-2.0-2014.xml", "nvdcve-%d.xml");
String full20 = baseURL.replace("nvdcve-2.0-2014.xml", "nvdcve-2.0-%d.xml");
// cve.url-1.2.modified=http://nvd.nist.gov/download/nvdcve-modified.xml
// cve.url-2.0.modified=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modified.xml
// cve.startyear=2014
// cve.url-2.0.base=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml
// cve.url-1.2.base=http://nvd.nist.gov/download/nvdcve-%d.xml
Settings.setString(Settings.KEYS.CVE_MODIFIED_12_URL, modified12);
Settings.setString(Settings.KEYS.CVE_MODIFIED_20_URL, modified20);
Settings.setString(Settings.KEYS.CVE_SCHEMA_1_2, full12);
Settings.setString(Settings.KEYS.CVE_SCHEMA_2_0, full20);
Settings.setString(Settings.KEYS.CVE_START_YEAR, "2014");
} else {
System.err.println("Consider updating the local data files to make the NvdCveUpdaterIntegrationTest perform faster");
}
}
/**
* Test of update method, of class NvdCveUpdater.
*/

View File

@@ -67,16 +67,16 @@ public class StandardUpdateIntegrationTest extends BaseTest {
result = instance.withinRange(lastRun, current, range);
assertEquals(expResult, result);
}
/**
* Test of update method, of class StandardUpdate.
*/
@Test
public void testUpdate() throws Exception {
StandardUpdate instance = getStandardUpdateTask();
instance.update();
//TODO make this an actual test
}
// test removed as it is duplicative of the EngineIntegrationTest and the NvdCveUpdaterIntergraionTest
// /**
// * Test of update method, of class StandardUpdate.
// */
// @Test
// public void testUpdate() throws Exception {
// StandardUpdate instance = getStandardUpdateTask();
// instance.update();
// //TODO make this an actual test
// }
/**
* Test of updatesNeeded method, of class StandardUpdate.

View File

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<suppressions xmlns="https://www.owasp.org/index.php/OWASP_Dependency_Check_Suppression">
<suppress>
<notes><![CDATA[
file name: FileHelpers.2.0.0.0.nupkg
]]></notes>
<sha1>30FB37D6163CF16E3BA740343BECDD14D5457619</sha1>
<cve>CVE-2007-1536</cve>
</suppress>
</suppressions>

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<suppressions xmlns="https://www.owasp.org/index.php/OWASP_Dependency_Check_Suppression">
<suppress>
<notes><![CDATA[
file name: commons-fileupload-1.2.1.jar
]]></notes>
<sha1>384FAA82E193D4E4B0546059CA09572654BC3970</sha1>
<cpe>cpe:/a:apache:commons_fileupload:1.2.1</cpe>
</suppress>
<suppress>
<notes><![CDATA[
file name: commons-fileupload-1.2.1.jar
]]></notes>
<sha1>384FAA82E193D4E4B0546059CA09572654BC3970</sha1>
<cve>CVE-2014-0050</cve>
</suppress>
<suppress>
<notes><![CDATA[
file name: commons-fileupload-1.2.1.jar
]]></notes>
<sha1>384FAA82E193D4E4B0546059CA09572654BC3970</sha1>
<cve>CVE-2013-0248</cve>
</suppress>
</suppressions>

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-parent</artifactId>
<version>1.2.0</version>
<version>1.2.1</version>
</parent>
<groupId>org.owasp</groupId>

View File

@@ -23,7 +23,7 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
<parent>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-parent</artifactId>
<version>1.2.0</version>
<version>1.2.1</version>
</parent>
<artifactId>dependency-check-maven</artifactId>

View File

@@ -613,7 +613,8 @@ public class DependencyCheckMojo extends AbstractMojo implements MavenMultiPageR
*/
private int writeSiteReportDependencyEvidenceUsed(Dependency d, int collapsibleHeaderCount, Sink sink) {
int cnt = collapsibleHeaderCount;
if (d.getEvidenceUsed() != null && d.getEvidenceUsed().size() > 0) {
final Set<Evidence> evidence = d.getEvidenceForDisplay();
if (evidence != null && evidence.size() > 0) {
cnt += 1;
sink.sectionTitle4();
sink.rawText("Evidence Collected <a href=\"javascript:toggleElement(this, 'evidence" + cnt + "')\">[+]</a>");
@@ -625,7 +626,7 @@ public class DependencyCheckMojo extends AbstractMojo implements MavenMultiPageR
writeTableHeaderCell(sink, "Name");
writeTableHeaderCell(sink, "Value");
sink.tableRow_();
for (Evidence e : d.getEvidenceUsed()) {
for (Evidence e : evidence) {
sink.tableRow();
writeTableCell(sink, e.getSource());
writeTableCell(sink, e.getName());
@@ -952,7 +953,7 @@ public class DependencyCheckMojo extends AbstractMojo implements MavenMultiPageR
"Unable to connect to the dependency-check database; analysis has stopped");
logger.log(Level.FINE, "", ex);
} finally {
Settings.cleanup();
Settings.cleanup(true);
if (engine != null) {
engine.cleanup();
}
@@ -993,7 +994,7 @@ public class DependencyCheckMojo extends AbstractMojo implements MavenMultiPageR
"Unable to connect to the dependency-check database; analysis has stopped");
logger.log(Level.FINE, "", ex);
} finally {
Settings.cleanup();
Settings.cleanup(true);
if (engine != null) {
engine.cleanup();
}

View File

@@ -20,7 +20,7 @@ Copyright (c) 2012 - Jeremy Long
<groupId>org.owasp</groupId>
<artifactId>dependency-check-parent</artifactId>
<version>1.2.0</version>
<version>1.2.1</version>
<packaging>pom</packaging>
<modules>

File diff suppressed because one or more lines are too long