1 /* 2 * This file is part of dependency-check-core. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * Copyright (c) 2017 Jeremy Long. All Rights Reserved. 17 */ 18 package org.owasp.dependencycheck.analyzer; 19 20 import java.util.HashSet; 21 import java.util.Objects; 22 import java.util.Set; 23 import javax.annotation.concurrent.ThreadSafe; 24 import org.owasp.dependencycheck.Engine; 25 import org.owasp.dependencycheck.analyzer.exception.AnalysisException; 26 import org.owasp.dependencycheck.dependency.Dependency; 27 import org.owasp.dependencycheck.dependency.Evidence; 28 import org.owasp.dependencycheck.dependency.EvidenceType; 29 import org.owasp.dependencycheck.utils.DependencyVersion; 30 import org.owasp.dependencycheck.utils.Settings; 31 import org.slf4j.Logger; 32 import org.slf4j.LoggerFactory; 33 34 /** 35 * This analyzer attempts to filter out erroneous version numbers collected. 36 * Initially, this will focus on JAR files that contain a POM version number 37 * that matches the file name - if identified all other version information will 38 * be removed. 39 * 40 * @author Jeremy Long 41 */ 42 @ThreadSafe 43 public class VersionFilterAnalyzer extends AbstractAnalyzer { 44 45 /** 46 * The Logger for use throughout the class 47 */ 48 private static final Logger LOGGER = LoggerFactory.getLogger(VersionFilterAnalyzer.class); 49 50 //<editor-fold defaultstate="collapsed" desc="Constants"> 51 /** 52 * Evidence source. 53 */ 54 private static final String FILE = "file"; 55 /** 56 * Evidence source. 57 */ 58 private static final String POM = "pom"; 59 /** 60 * Evidence source. 61 */ 62 private static final String NEXUS = "nexus"; 63 /** 64 * Evidence source. 65 */ 66 private static final String CENTRAL = "central"; 67 /** 68 * Evidence source. 69 */ 70 private static final String MANIFEST = "Manifest"; 71 /** 72 * Evidence name. 73 */ 74 private static final String VERSION = "version"; 75 /** 76 * Evidence name. 77 */ 78 private static final String IMPLEMENTATION_VERSION = "Implementation-Version"; 79 80 /** 81 * The name of the analyzer. 82 */ 83 private static final String ANALYZER_NAME = "Version Filter Analyzer"; 84 /** 85 * The phase that this analyzer is intended to run in. 86 */ 87 private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.POST_INFORMATION_COLLECTION; 88 89 //</editor-fold> 90 //<editor-fold defaultstate="collapsed" desc="Standard implementation of Analyzer"> 91 /** 92 * Returns the name of the analyzer. 93 * 94 * @return the name of the analyzer. 95 */ 96 @Override getName()97 public String getName() { 98 return ANALYZER_NAME; 99 } 100 101 /** 102 * Returns the phase that the analyzer is intended to run in. 103 * 104 * @return the phase that the analyzer is intended to run in. 105 */ 106 @Override getAnalysisPhase()107 public AnalysisPhase getAnalysisPhase() { 108 return ANALYSIS_PHASE; 109 } 110 111 /** 112 * Returns the setting key to determine if the analyzer is enabled. 113 * 114 * @return the key for the analyzer's enabled property 115 */ 116 @Override getAnalyzerEnabledSettingKey()117 protected String getAnalyzerEnabledSettingKey() { 118 return Settings.KEYS.ANALYZER_VERSION_FILTER_ENABLED; 119 } 120 //</editor-fold> 121 122 /** 123 * The HintAnalyzer uses knowledge about a dependency to add additional 124 * information to help in identification of identifiers or vulnerabilities. 125 * 126 * @param dependency The dependency being analyzed 127 * @param engine The scanning engine 128 * @throws AnalysisException is thrown if there is an exception analyzing 129 * the dependency. 130 */ 131 @Override analyzeDependency(Dependency dependency, Engine engine)132 protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException { 133 String fileVersion = null; 134 String pomVersion = null; 135 String manifestVersion = null; 136 for (Evidence e : dependency.getEvidence(EvidenceType.VERSION)) { 137 if (FILE.equals(e.getSource()) && VERSION.equals(e.getName())) { 138 fileVersion = e.getValue(); 139 } else if ((NEXUS.equals(e.getSource()) || CENTRAL.equals(e.getSource()) 140 || POM.equals(e.getSource())) && VERSION.equals(e.getName())) { 141 pomVersion = e.getValue(); 142 } else if (MANIFEST.equals(e.getSource()) && IMPLEMENTATION_VERSION.equals(e.getName())) { 143 manifestVersion = e.getValue(); 144 } 145 } 146 //ensure we have at least two not null 147 if (((fileVersion == null ? 0 : 1) + (pomVersion == null ? 0 : 1) + (manifestVersion == null ? 0 : 1)) > 1) { 148 final DependencyVersion dvFile = new DependencyVersion(fileVersion); 149 final DependencyVersion dvPom = new DependencyVersion(pomVersion); 150 final DependencyVersion dvManifest = new DependencyVersion(manifestVersion); 151 final boolean fileMatch = Objects.equals(dvFile, dvPom) || Objects.equals(dvFile, dvManifest); 152 final boolean manifestMatch = Objects.equals(dvManifest, dvPom) || Objects.equals(dvManifest, dvFile); 153 final boolean pomMatch = Objects.equals(dvPom, dvFile) || Objects.equals(dvPom, dvManifest); 154 if (fileMatch || manifestMatch || pomMatch) { 155 LOGGER.debug("filtering evidence from {}", dependency.getFileName()); 156 final Set<Evidence> remove = new HashSet<>(); 157 for (Evidence e : dependency.getEvidence(EvidenceType.VERSION)) { 158 if (!(pomMatch && VERSION.equals(e.getName()) 159 && (NEXUS.equals(e.getSource()) || CENTRAL.equals(e.getSource()) || POM.equals(e.getSource()))) 160 && !(fileMatch && VERSION.equals(e.getName()) && FILE.equals(e.getSource())) 161 && !(manifestMatch && MANIFEST.equals(e.getSource()) && IMPLEMENTATION_VERSION.equals(e.getName()))) { 162 remove.add(e); 163 } 164 } 165 for (Evidence e : remove) { 166 dependency.removeEvidence(EvidenceType.VERSION, e); 167 } 168 } 169 } 170 } 171 } 172