View Javadoc

    1   /*
    2    * This file is part of dependency-check-core.
    3    *
    4    * Dependency-check-core is free software: you can redistribute it and/or modify it
    5    * under the terms of the GNU General Public License as published by the Free
    6    * Software Foundation, either version 3 of the License, or (at your option) any
    7    * later version.
    8    *
    9    * Dependency-check-core is distributed in the hope that it will be useful, but
    10   * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    11   * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
    12   * details.
    13   *
    14   * You should have received a copy of the GNU General Public License along with
    15   * dependency-check-core. If not, see http://www.gnu.org/licenses/.
    16   *
    17   * Copyright (c) 2012 Jeremy Long. All Rights Reserved.
    18   */
    19  package org.owasp.dependencycheck.analyzer;
    20
    21  import java.io.IOException;
    22  import java.sql.SQLException;
    23  import java.util.List;
    24  import java.util.Set;
    25  import org.owasp.dependencycheck.Engine;
    26  import org.owasp.dependencycheck.dependency.Dependency;
    27  import org.owasp.dependencycheck.dependency.Vulnerability;
    28  import org.owasp.dependencycheck.dependency.Identifier;
    29  import org.owasp.dependencycheck.data.nvdcve.CveDB;
    30  import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
    31
    32  /**
    33   * NvdCveAnalyzer is a utility class that takes a project dependency and
    34   * attempts to discern if there is an associated CVEs. It uses the the
    35   * identifiers found by other analyzers to lookup the CVE data.
    36   *
    37   * @author Jeremy Long (jeremy.long@owasp.org)
    38   */
    39  public class NvdCveAnalyzer implements Analyzer {
    40
    41      /**
    42       * The maximum number of query results to return.
    43       */
    44      static final int MAX_QUERY_RESULTS = 100;
    45      /**
    46       * The CVE Index.
    47       */
    48      private CveDB cveDB;
    49
    50      /**
    51       * Opens the data source.
    52       *
    53       * @throws SQLException thrown when there is a SQL Exception
    54       * @throws IOException thrown when there is an IO Exception
    55       * @throws DatabaseException thrown when there is a database exceptions
    56       * @throws ClassNotFoundException thrown if the h2 database driver cannot be
    57       * loaded
    58       */
    59      public void open() throws SQLException, IOException, DatabaseException, ClassNotFoundException {
    60          cveDB = new CveDB();
    61          cveDB.open();
    62      }
    63
    64      /**
    65       * Closes the data source.
    66       */
    67      public void close() {
    68          cveDB.close();
    69          cveDB = null;
    70      }
    71
    72      /**
    73       * Returns the status of the data source - is the database open.
    74       *
    75       * @return true or false.
    76       */
    77      public boolean isOpen() {
    78          return (cveDB != null);
    79      }
    80
    81      /**
    82       * Ensures that the CVE Database is closed.
    83       *
    84       * @throws Throwable when a throwable is thrown.
    85       */
    86      @Override
    87      protected void finalize() throws Throwable {
    88          super.finalize();
    89          if (isOpen()) {
    90              close();
    91          }
    92      }
    93
    94      /**
    95       * Analyzes a dependency and attempts to determine if there are any CPE
    96       * identifiers for this dependency.
    97       *
    98       * @param dependency The Dependency to analyze
    99       * @param engine The analysis engine
    100      * @throws AnalysisException is thrown if there is an issue analyzing the
    101      * dependency
    102      */
    103     public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
    104         for (Identifier id : dependency.getIdentifiers()) {
    105             if ("cpe".equals(id.getType())) {
    106                 try {
    107                     final String value = id.getValue();
    108                     final List<Vulnerability> vulns = cveDB.getVulnerabilities(value);
    109                     dependency.getVulnerabilities().addAll(vulns);
    110 //TODO - remove this comment block after additional testing is completed
    111 //note - valid match functionality has been moved into the CveDB class.
    112 ////                    for (Vulnerability v : vulns) {
    113 ////                        if (isValidMatch(dependency, v)) {
    114 ////                            dependency.addVulnerability(v);
    115 ////                        }
    116 ////                    }
    117                 } catch (DatabaseException ex) {
    118                     throw new AnalysisException(ex);
    119                 }
    120             }
    121         }
    122     }
    123
    124     /**
    125      * Returns true because this analyzer supports all dependency types.
    126      *
    127      * @return true.
    128      */
    129     public Set<String> getSupportedExtensions() {
    130         return null;
    131     }
    132
    133     /**
    134      * Returns the name of this analyzer.
    135      *
    136      * @return the name of this analyzer.
    137      */
    138     public String getName() {
    139         return "NVD CVE Analyzer";
    140     }
    141
    142     /**
    143      * Returns true because this analyzer supports all dependency types.
    144      *
    145      * @param extension the file extension of the dependency being analyzed.
    146      * @return true.
    147      */
    148     public boolean supportsExtension(String extension) {
    149         return true;
    150     }
    151
    152     /**
    153      * Returns the analysis phase that this analyzer should run in.
    154      *
    155      * @return the analysis phase that this analyzer should run in.
    156      */
    157     public AnalysisPhase getAnalysisPhase() {
    158         return AnalysisPhase.FINDING_ANALYSIS;
    159     }
    160
    161     /**
    162      * Opens the NVD CVE Lucene Index.
    163      *
    164      * @throws Exception is thrown if there is an issue opening the index.
    165      */
    166     public void initialize() throws Exception {
    167         this.open();
    168     }
    169 //TODO - remove this comment block after additional testing is completed
    170 // The following check has been moved into the CveDB class.
    171 ////    /**
    172 ////     * <p>Determines if this is a valid vulnerability match for the given
    173 ////     * dependency. Specifically, this is concerned with ensuring the version
    174 ////     * numbers are correct.</p>
    175 ////     * <p>Currently, this is focused on the issues with the versions for Struts
    176 ////     * 1 and Struts 2. In the future this will due better matching on more
    177 ////     * version numbers.</p>
    178 ////     *
    179 ////     * @param dependency the dependency
    180 ////     * @param v the vulnerability
    181 ////     * @return returns true if the vulnerability is for the given dependency
    182 ////     */
    183 ////    private boolean isValidMatch(final Dependency dependency, final Vulnerability v) {
    184 ////        //right now I only know of the issue with Struts1/2
    185 ////        // start with fixing this problem.
    186 ////
    187 ////        //TODO extend this solution to do better version matching for the vulnerable software.
    188 ////        boolean struts1 = false;
    189 ////        boolean struts2 = false;
    190 ////        for (Identifier i : dependency.getIdentifiers()) {
    191 ////            if (i.getValue().startsWith("cpe:/a:apache:struts:")) {
    192 ////                final char version = i.getValue().charAt(21);
    193 ////                if (version == '1') {
    194 ////                    struts1 = true;
    195 ////                }
    196 ////                if (version == '2') {
    197 ////                    struts2 = true;
    198 ////                }
    199 ////            }
    200 ////        }
    201 ////        if (!struts1 && !struts2) {
    202 ////            return true; //we are not looking at struts, so return true.
    203 ////        }
    204 ////        if (struts1 && struts2) {
    205 ////            return true; //there is a mismatch here, but we can't solve it here so we return valid.
    206 ////        }
    207 ////        if (struts1) {
    208 ////            boolean hasStruts1Vuln = false;
    209 ////            boolean hasStruts2PreviousVersion = false;
    210 ////            for (VulnerableSoftware vs : v.getVulnerableSoftware()) {
    211 ////                //TODO FIX THIS
    212 ////                //hasStruts2PreviousVersion |= vs.hasPreviousVersion() && vs.getName().charAt(21) == '2';
    213 ////                //hasStruts1Vuln |= vs.getName().charAt(21) == '1';
    214 ////            }
    215 ////            if (!hasStruts1Vuln && hasStruts2PreviousVersion) {
    216 ////                return false;
    217 ////            }
    218 ////        }
    219 ////
    220 ////        return true;
    221 ////    }
    222 }