From 523cd23b6b7336f8158aaa1147b136058feb3afa Mon Sep 17 00:00:00 2001 From: Jeremy Long Date: Sat, 14 Jan 2017 09:41:34 -0500 Subject: [PATCH] filter version numbers for issue #575 --- .../analyzer/VersionFilterAnalyzer.java | 129 ++++++++++++++++++ ...rg.owasp.dependencycheck.analyzer.Analyzer | 1 + .../main/resources/dependencycheck.properties | 1 + .../analyzer/VersionFilterAnalyzerTest.java | 104 ++++++++++++++ .../owasp/dependencycheck/utils/Settings.java | 4 + 5 files changed, 239 insertions(+) create mode 100644 dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/VersionFilterAnalyzer.java create mode 100644 dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/VersionFilterAnalyzerTest.java diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/VersionFilterAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/VersionFilterAnalyzer.java new file mode 100644 index 000000000..8a5f807c8 --- /dev/null +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/VersionFilterAnalyzer.java @@ -0,0 +1,129 @@ +/* + * This file is part of dependency-check-core. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (c) 2017 Jeremy Long. All Rights Reserved. + */ +package org.owasp.dependencycheck.analyzer; + +import java.util.Iterator; +import org.owasp.dependencycheck.Engine; +import org.owasp.dependencycheck.analyzer.exception.AnalysisException; +import org.owasp.dependencycheck.dependency.Dependency; +import org.owasp.dependencycheck.dependency.Evidence; +import org.owasp.dependencycheck.dependency.EvidenceCollection; +import org.owasp.dependencycheck.utils.DependencyVersion; +import org.owasp.dependencycheck.utils.Settings; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This analyzer attempts to filter out erroneous version numbers collected. + * Initially, this will focus on JAR files that contain a POM version number + * that matches the file name - if identified all other version information will + * be removed. + * + * @author Jeremy Long + */ +public class VersionFilterAnalyzer extends AbstractAnalyzer { + + // + /** + * The name of the analyzer. + */ + private static final String ANALYZER_NAME = "Version Filter Analyzer"; + /** + * The phase that this analyzer is intended to run in. + */ + private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.POST_INFORMATION_COLLECTION; + + /** + * Returns the name of the analyzer. + * + * @return the name of the analyzer. + */ + @Override + public String getName() { + return ANALYZER_NAME; + } + + /** + * Returns the phase that the analyzer is intended to run in. + * + * @return the phase that the analyzer is intended to run in. + */ + @Override + public AnalysisPhase getAnalysisPhase() { + return ANALYSIS_PHASE; + } + + /** + * Returns the setting key to determine if the analyzer is enabled. + * + * @return the key for the analyzer's enabled property + */ + @Override + protected String getAnalyzerEnabledSettingKey() { + return Settings.KEYS.ANALYZER_VERSION_FILTER_ENABLED; + } + // + + /** + * The Logger for use throughout the class + */ + private static final Logger LOGGER = LoggerFactory.getLogger(VersionFilterAnalyzer.class); + + /** + * The HintAnalyzer uses knowledge about a dependency to add additional + * information to help in identification of identifiers or vulnerabilities. + * + * @param dependency The dependency being analyzed + * @param engine The scanning engine + * @throws AnalysisException is thrown if there is an exception analyzing + * the dependency. + */ + @Override + protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException { + String fileVersion = null; + String pomVersion = null; + for (Evidence e : dependency.getVersionEvidence()) { + if ("file".equals(e.getSource()) && "version".equals(e.getName())) { + fileVersion = e.getValue(Boolean.FALSE); + } else if (("nexus".equals(e.getSource()) || "central".equals(e.getSource()) || "pom".equals(e.getSource())) && "version".equals(e.getName())) { + pomVersion = e.getValue(Boolean.FALSE); + } + } + if (fileVersion != null && pomVersion != null) { + DependencyVersion dvFile = new DependencyVersion(fileVersion); + DependencyVersion dvPom = new DependencyVersion(pomVersion); + if (dvPom.equals(dvFile)) { + LOGGER.debug("filtering evidence from {}", dependency.getFileName()); + EvidenceCollection versionEvidence = dependency.getVersionEvidence(); + synchronized (versionEvidence) { + final Iterator itr = versionEvidence.iterator(); + while (itr.hasNext()) { + Evidence e = itr.next(); + if (!("version".equals(e.getName()) + && ("file".equals(e.getSource()) + || "nexus".equals(e.getSource()) + || "central".equals(e.getSource()) + || "pom".equals(e.getSource())))) { + itr.remove(); + } + } + } + } + } + } +} diff --git a/dependency-check-core/src/main/resources/META-INF/services/org.owasp.dependencycheck.analyzer.Analyzer b/dependency-check-core/src/main/resources/META-INF/services/org.owasp.dependencycheck.analyzer.Analyzer index 41d1e9ce1..f9bb4b811 100644 --- a/dependency-check-core/src/main/resources/META-INF/services/org.owasp.dependencycheck.analyzer.Analyzer +++ b/dependency-check-core/src/main/resources/META-INF/services/org.owasp.dependencycheck.analyzer.Analyzer @@ -25,3 +25,4 @@ org.owasp.dependencycheck.analyzer.RubyBundleAuditAnalyzer org.owasp.dependencycheck.analyzer.ComposerLockAnalyzer org.owasp.dependencycheck.analyzer.CocoaPodsAnalyzer org.owasp.dependencycheck.analyzer.SwiftPackageManagerAnalyzer +org.owasp.dependencycheck.analyzer.VersionFilterAnalyzer \ No newline at end of file diff --git a/dependency-check-core/src/main/resources/dependencycheck.properties b/dependency-check-core/src/main/resources/dependencycheck.properties index a824b7fbc..21db405f5 100644 --- a/dependency-check-core/src/main/resources/dependencycheck.properties +++ b/dependency-check-core/src/main/resources/dependencycheck.properties @@ -114,3 +114,4 @@ analyzer.nvdcve.enabled=true analyzer.vulnerabilitysuppression.enabled=true updater.nvdcve.enabled=true updater.versioncheck.enabled=true +analyzer.versionfilter.enabled=true \ No newline at end of file diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/VersionFilterAnalyzerTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/VersionFilterAnalyzerTest.java new file mode 100644 index 000000000..389b03446 --- /dev/null +++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/VersionFilterAnalyzerTest.java @@ -0,0 +1,104 @@ +/* + * This file is part of dependency-check-core. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (c) 2017 Jeremy Long. All Rights Reserved. + */ +package org.owasp.dependencycheck.analyzer; + +import org.junit.Test; +import static org.junit.Assert.*; +import org.owasp.dependencycheck.BaseTest; +import org.owasp.dependencycheck.dependency.Confidence; +import org.owasp.dependencycheck.dependency.Dependency; +import org.owasp.dependencycheck.dependency.EvidenceCollection; +import org.owasp.dependencycheck.utils.Settings; + +/** + * + * @author jerem + */ +public class VersionFilterAnalyzerTest extends BaseTest { + + /** + * Test of getName method, of class VersionFilterAnalyzer. + */ + @Test + public void testGetName() { + VersionFilterAnalyzer instance = new VersionFilterAnalyzer(); + String expResult = "Version Filter Analyzer"; + String result = instance.getName(); + assertEquals(expResult, result); + } + + /** + * Test of getAnalysisPhase method, of class VersionFilterAnalyzer. + */ + @Test + public void testGetAnalysisPhase() { + VersionFilterAnalyzer instance = new VersionFilterAnalyzer(); + AnalysisPhase expResult = AnalysisPhase.POST_INFORMATION_COLLECTION; + AnalysisPhase result = instance.getAnalysisPhase(); + assertEquals(expResult, result); + } + + /** + * Test of getAnalyzerEnabledSettingKey method, of class + * VersionFilterAnalyzer. + */ + @Test + public void testGetAnalyzerEnabledSettingKey() { + VersionFilterAnalyzer instance = new VersionFilterAnalyzer(); + String expResult = Settings.KEYS.ANALYZER_VERSION_FILTER_ENABLED; + String result = instance.getAnalyzerEnabledSettingKey(); + assertEquals(expResult, result); + } + + /** + * Test of analyzeDependency method, of class VersionFilterAnalyzer. + */ + @Test + public void testAnalyzeDependency() throws Exception { + Dependency dependency = new Dependency(); + EvidenceCollection versions = dependency.getVersionEvidence(); + + versions.addEvidence("util", "version", "33.3", Confidence.HIGHEST); + versions.addEvidence("other", "version", "alpha", Confidence.HIGHEST); + versions.addEvidence("manifest", "implementation-version", "1.2.3", Confidence.HIGHEST); + + VersionFilterAnalyzer instance = new VersionFilterAnalyzer(); + + instance.analyzeDependency(dependency, null); + assertEquals(3, versions.size()); + + versions.addEvidence("pom", "version", "1.2.3", Confidence.HIGHEST); + + instance.analyzeDependency(dependency, null); + assertEquals(4, versions.size()); + + versions.addEvidence("file", "version", "1.2.3", Confidence.HIGHEST); + instance.analyzeDependency(dependency, null); + assertEquals(2, versions.size()); + + versions.addEvidence("nexus", "version", "1.2.3", Confidence.HIGHEST); + versions.addEvidence("other", "version", "alpha", Confidence.HIGHEST); + instance.analyzeDependency(dependency, null); + assertEquals(3, versions.size()); + + versions.addEvidence("central", "version", "1.2.3", Confidence.HIGHEST); + versions.addEvidence("other", "version", "alpha", Confidence.HIGHEST); + instance.analyzeDependency(dependency, null); + assertEquals(4, versions.size()); + } +} diff --git a/dependency-check-utils/src/main/java/org/owasp/dependencycheck/utils/Settings.java b/dependency-check-utils/src/main/java/org/owasp/dependencycheck/utils/Settings.java index 94e2862d6..9d6087c86 100644 --- a/dependency-check-utils/src/main/java/org/owasp/dependencycheck/utils/Settings.java +++ b/dependency-check-utils/src/main/java/org/owasp/dependencycheck/utils/Settings.java @@ -370,6 +370,10 @@ public final class Settings { * The key to determine if the Hint analyzer is enabled. */ public static final String ANALYZER_HINT_ENABLED = "analyzer.hint.enabled"; + /** + * The key to determine if the Version Filter analyzer is enabled. + */ + public static final String ANALYZER_VERSION_FILTER_ENABLED = "analyzer.versionfilter.enabled"; /** * The key to determine if the NVD CVE analyzer is enabled. */