mercedes-benz / sechub

SecHub provides a central API to test software with different security tools.
https://mercedes-benz.github.io/sechub/
MIT License
260 stars 63 forks source link

Importer for FindSecurityBugs #1971

Closed Jeeppler closed 1 year ago

Jeeppler commented 1 year ago

Problem

FindSecurityBugs can produce HTML, SARIF and XML reports. However, the SARIF report does not contain most of the details. On the other hand the XML report contains the most information.

The SARIF report is missing the CWE ID, which is necessary for marking false-positives.

Solution

Write an importer for the FindSecurityBugs XML format. The format contains, solutions and references as well as the CWE ID.

Example:

<?xml version="1.0" encoding="UTF-8"?>

<BugCollection version="4.6.0" sequence="0" timestamp="1676665279260" analysisTimestamp="1676665280172" release="">
  <Project projectName="">
    <Jar>/workspace/workspace/f2f3a19c-2a74-4cf7-8f99-05a87716f8ba/upload/extracted/binaries/</Jar>
    <Plugin id="com.h3xstream.findsecbugs" enabled="true"/>
  </Project>
  <BugInstance type="WEAK_MESSAGE_DIGEST_MD5" priority="1" rank="10" abbrev="SECMD5" category="SECURITY" instanceHash="f58ec3923941dea3ade4fadcc8b973f5" instanceOccurrenceNum="0" instanceOccurrenceMax="0" cweid="328">
    <ShortMessage>MD2, MD4 and MD5 are weak hash functions</ShortMessage>
    <LongMessage>This API MD5 (MDX) is not a recommended cryptographic hash function</LongMessage>
    <Class classname="MD5" primary="true">
      <SourceLine classname="MD5" start="4" end="17" sourcefile="MD5.java" sourcepath="MD5.java">
        <Message>At MD5.java:[lines 4-17]</Message>
      </SourceLine>
      <Message>In class MD5</Message>
    </Class>
    <Method classname="MD5" name="main" signature="([Ljava/lang/String;)V" isStatic="true" primary="true">
      <SourceLine classname="MD5" start="8" end="17" startBytecode="0" endBytecode="120" sourcefile="MD5.java" sourcepath="MD5.java"/>
      <Message>In method MD5.main(String[])</Message>
    </Method>
    <SourceLine classname="MD5" primary="true" start="9" end="9" startBytecode="5" endBytecode="5" sourcefile="MD5.java" sourcepath="MD5.java">
      <Message>At MD5.java:[line 9]</Message>
    </SourceLine>
    <String value="MD5">
      <Message>Value MD5</Message>
    </String>
  </BugInstance>
  <BugCategory category="SECURITY">
    <Description>Security</Description>
  </BugCategory>
  <BugPattern type="WEAK_MESSAGE_DIGEST_MD5" abbrev="SECMD5" category="SECURITY" cweid="328">
    <ShortDescription>MD2, MD4 and MD5 are weak hash functions</ShortDescription>
    <Details><![CDATA[

<p>The algorithms MD2, MD4 and MD5 are not a recommended MessageDigest. <b>PBKDF2</b> should be used to hash password for example.</p>

<blockquote>
    "The security of the MD5 hash function is severely compromised. A collision attack exists that can find collisions
    within seconds on a computer with a 2.6 GHz Pentium 4 processor (complexity of 2<sup>24.1</sup>).[1] Further, there is also a
    chosen-prefix collision attack that can produce a collision for two inputs with specified prefixes within hours, using
    off-the-shelf computing hardware (complexity 2<sup>39</sup>).[2]"<br/>
    - <a href="https://en.wikipedia.org/wiki/MD5#Security">Wikipedia: MD5 - Security</a>
</blockquote>

<blockquote>
    "<b>SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224, and SHA-512/256</b>:<br/>
    The use of these hash functions is acceptable for all hash function applications."<br/>
    - <a href="https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar2.pdf">NIST: Transitioning the Use of Cryptographic Algorithms and Key Lengths p.15</a>
</blockquote>
<blockquote>
    "The main idea of a PBKDF is to slow dictionary or brute force attacks on the passwords by increasing the time
    needed to test each password. An attacker with a list of likely passwords can evaluate the PBKDF using the known
    iteration counter and the salt. Since an attacker has to spend a significant amount of computing time for each try,
    it becomes harder to apply the dictionary or brute force attacks."<br/>
- <a href="https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-132.pdf">NIST: Recommendation for Password-Based Key Derivation  p.12</a>
</blockquote>
<br/>
<p>
    <b>Vulnerable Code:</b><br/>
    <pre>MessageDigest md5Digest = MessageDigest.getInstance("MD5");
    md5Digest.update(password.getBytes());
    byte[] hashValue = md5Digest.digest();</pre>
    <br/>
    <pre>byte[] hashValue = DigestUtils.getMd5Digest().digest(password.getBytes());</pre>
</p>
<br/>
<p>
    <b>Solution (Using bouncy castle):</b><br/>
    <pre>public static byte[] getEncryptedPassword(String password, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException {
    PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator(new SHA256Digest());
    gen.init(password.getBytes("UTF-8"), salt.getBytes(), 4096);
    return ((KeyParameter) gen.generateDerivedParameters(256)).getKey();
}</pre>
    <br/>
    <b>Solution (Java 8 and later):</b><br/>
    <pre>public static byte[] getEncryptedPassword(String password, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException {
    KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 4096, 256 * 8);
    SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
    return f.generateSecret(spec).getEncoded();
}</pre>
</p>
<br/>
<p>
<b>References</b><br/>
[1] <a href="https://www.win.tue.nl/hashclash/On%20Collisions%20for%20MD5%20-%20M.M.J.%20Stevens.pdf">On Collisions for MD5</a>: Master Thesis by M.M.J. Stevens<br/>
[2] <a href="https://homepages.cwi.nl/~stevens/papers/stJOC%20-%20Chosen-Prefix%20Collisions%20for%20MD5%20and%20Applications.pdf">Chosen-prefix collisions for MD5 and applications</a>: Paper written by Marc Stevens<br/>
<a href="https://en.wikipedia.org/wiki/MD5">Wikipedia: MD5</a><br/>
<a href="https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar2.pdf">NIST: Transitioning the Use of Cryptographic Algorithms and Key Lengths</a><br/>
<a href="https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-132.pdf">NIST: Recommendation for Password-Based Key Derivation</a><br/>
<a href="https://stackoverflow.com/q/22580853/89769">Stackoverflow: Reliable implementation of PBKDF2-HMAC-SHA256 for Java</a><br/>
<a href="https://cwe.mitre.org/data/definitions/327.html">CWE-327: Use of a Broken or Risky Cryptographic Algorithm</a>
</p>

        ]]></Details>
  </BugPattern>
  <BugCode abbrev="SECMD5">
    <Description>MD2, MD4 and MD5 are weak hash functions</Description>
  </BugCode>
  <Errors errors="0" missingClasses="8">
    <MissingClass>jakarta.servlet.http.HttpServlet</MissingClass>
    <MissingClass>jakarta.servlet.http.HttpServletRequest</MissingClass>
    <MissingClass>jakarta.servlet.http.HttpServletResponse</MissingClass>
    <MissingClass>makeConcatWithConstants</MissingClass>
    <MissingClass>org.apache.catalina.Context</MissingClass>
    <MissingClass>org.apache.catalina.Host</MissingClass>
    <MissingClass>org.apache.catalina.Server</MissingClass>
    <MissingClass>org.apache.catalina.startup.Tomcat</MissingClass>
  </Errors>
  <FindBugsSummary timestamp="Fri, 17 Feb 2023 20:21:19 +0000" total_classes="4" referenced_classes="29" total_bugs="1" total_size="66" num_packages="2" java_version="17.0.6" vm_version="17.0.6+10-Debian-1deb11u1" cpu_seconds="4.29" clock_seconds="1.24" peak_mbytes="233.63" alloc_mbytes="8028.00" gc_seconds="0.00" priority_1="1">
    <FileStats path="MD5.java" bugCount="1" size="13" bugHash="aa21f98e5f97a80e0544d6662e1091d4"/>
    <FileStats path="Sha1.java" bugCount="0" size="13"/>
    <FileStats path="XSS/App.java" bugCount="0" size="40"/>
    <PackageStats package="" total_bugs="1" total_types="2" total_size="26" priority_1="1">
      <ClassStats class="MD5" sourceFile="MD5.java" interface="false" size="13" bugs="1" priority_1="1"/>
      <ClassStats class="Sha1" sourceFile="Sha1.java" interface="false" size="13" bugs="0"/>
    </PackageStats>
    <PackageStats package="XSS" total_bugs="0" total_types="2" total_size="40">
      <ClassStats class="XSS.App" sourceFile="App.java" interface="false" size="20" bugs="0"/>
      <ClassStats class="XSS.App$1" sourceFile="App.java" interface="false" size="20" bugs="0"/>
    </PackageStats>
    <FindBugsProfile>
      <ClassProfile name="edu.umd.cs.findbugs.classfile.engine.ClassInfoAnalysisEngine" totalMilliseconds="278" invocations="501" avgMicrosecondsPerInvocation="555" maxMicrosecondsPerInvocation="13601" standardDeviationMicrosecondsPerInvocation="1257"/>
      <ClassProfile name="edu.umd.cs.findbugs.detect.FieldItemSummary" totalMilliseconds="65" invocations="29" avgMicrosecondsPerInvocation="2264" maxMicrosecondsPerInvocation="13175" standardDeviationMicrosecondsPerInvocation="3317"/>
      <ClassProfile name="edu.umd.cs.findbugs.detect.FindNoSideEffectMethods" totalMilliseconds="53" invocations="29" avgMicrosecondsPerInvocation="1852" maxMicrosecondsPerInvocation="11441" standardDeviationMicrosecondsPerInvocation="2747"/>
      <ClassProfile name="edu.umd.cs.findbugs.classfile.engine.ClassDataAnalysisEngine" totalMilliseconds="44" invocations="506" avgMicrosecondsPerInvocation="88" maxMicrosecondsPerInvocation="2062" standardDeviationMicrosecondsPerInvocation="121"/>
      <ClassProfile name="edu.umd.cs.findbugs.OpcodeStack$JumpInfoFactory" totalMilliseconds="38" invocations="112" avgMicrosecondsPerInvocation="344" maxMicrosecondsPerInvocation="2077" standardDeviationMicrosecondsPerInvocation="389"/>
      <ClassProfile name="edu.umd.cs.findbugs.util.TopologicalSort" totalMilliseconds="28" invocations="450" avgMicrosecondsPerInvocation="63" maxMicrosecondsPerInvocation="1044" standardDeviationMicrosecondsPerInvocation="117"/>
      <ClassProfile name="edu.umd.cs.findbugs.classfile.engine.bcel.JavaClassAnalysisEngine" totalMilliseconds="23" invocations="81" avgMicrosecondsPerInvocation="284" maxMicrosecondsPerInvocation="8434" standardDeviationMicrosecondsPerInvocation="973"/>
      <ClassProfile name="edu.umd.cs.findbugs.detect.NoteDirectlyRelevantTypeQualifiers" totalMilliseconds="21" invocations="29" avgMicrosecondsPerInvocation="735" maxMicrosecondsPerInvocation="5125" standardDeviationMicrosecondsPerInvocation="1098"/>
      <ClassProfile name="edu.umd.cs.findbugs.classfile.engine.bcel.MethodGenFactory" totalMilliseconds="17" invocations="9" avgMicrosecondsPerInvocation="1995" maxMicrosecondsPerInvocation="16550" standardDeviationMicrosecondsPerInvocation="5148"/>
      <ClassProfile name="edu.umd.cs.findbugs.detect.FunctionsThatMightBeMistakenForProcedures" totalMilliseconds="16" invocations="29" avgMicrosecondsPerInvocation="568" maxMicrosecondsPerInvocation="3450" standardDeviationMicrosecondsPerInvocation="891"/>
      <ClassProfile name="edu.umd.cs.findbugs.detect.BuildStringPassthruGraph" totalMilliseconds="15" invocations="29" avgMicrosecondsPerInvocation="545" maxMicrosecondsPerInvocation="4409" standardDeviationMicrosecondsPerInvocation="902"/>
      <ClassProfile name="edu.umd.cs.findbugs.detect.OverridingEqualsNotSymmetrical" totalMilliseconds="13" invocations="29" avgMicrosecondsPerInvocation="459" maxMicrosecondsPerInvocation="4963" standardDeviationMicrosecondsPerInvocation="971"/>
      <ClassProfile name="edu.umd.cs.findbugs.detect.BuildObligationPolicyDatabase" totalMilliseconds="12" invocations="29" avgMicrosecondsPerInvocation="442" maxMicrosecondsPerInvocation="3609" standardDeviationMicrosecondsPerInvocation="703"/>
      <ClassProfile name="edu.umd.cs.findbugs.classfile.engine.bcel.TypeDataflowFactory" totalMilliseconds="12" invocations="11" avgMicrosecondsPerInvocation="1124" maxMicrosecondsPerInvocation="5428" standardDeviationMicrosecondsPerInvocation="1500"/>
      <ClassProfile name="edu.umd.cs.findbugs.detect.CalledMethods" totalMilliseconds="12" invocations="29" avgMicrosecondsPerInvocation="425" maxMicrosecondsPerInvocation="1902" standardDeviationMicrosecondsPerInvocation="519"/>
      <ClassProfile name="edu.umd.cs.findbugs.classfile.engine.bcel.ValueNumberDataflowFactory" totalMilliseconds="11" invocations="11" avgMicrosecondsPerInvocation="1050" maxMicrosecondsPerInvocation="6549" standardDeviationMicrosecondsPerInvocation="1781"/>
    </FindBugsProfile>
  </FindBugsSummary>
  <ClassFeatures></ClassFeatures>
  <History></History>
</BugCollection>
Jeeppler commented 1 year ago

Related: #1906

Jeeppler commented 1 year ago

The solution is not to implement a new XML reporter, instead fix the SARIF generation in SpotBugs (see: https://github.com/spotbugs/spotbugs/issues/2321).