Search code examples
securitymaven

How to enforce a strict Maven dependency policy (dependency chain attack)


I would like to enforce a strict Maven dependency policy which goes beyond the basic checksumPolicy=fail approach.

This is an attempt to provide protection against a modified release dependency which still has a valid digest value also known as a "dependency chain attack".

This situation could arise from the following scenarios:

  • the dependency has been updated, but the author has not updated the version number and managed to overwrite the earlier release (or their repo account has been compromised)
  • a man-in-the-middle attack is in place (with on-the-fly rewriting/hashing)
  • the repository itself has been compromised

In discussions with other developers one approach to combat the above is to have a list of known MD5/SHA digests in the pom.xml and have Maven verify that the downloaded dependency has the same digest. This ensures that so long as the source code repository remains secure, any included dependencies that have been compromised will be detected.

Thus my question is twofold:

  1. are there any alternative approaches that would work more efficiently?
  2. are there any existing implementations/plugins that do this job?

Solution

  • If anyone is wrestling with this issue themselves I've created a Maven Enforcer Plugin Rule that deals with it. You can specify a list of artifact URNs that include the expected SHA1 hash value and have the enforcer verify that this is indeed what is being used in the build.

    It is available through Maven Central under MIT license, with source code in GitHub here: https://github.com/gary-rowe/BitcoinjEnforcerRules

    While the project indicates that it is for the Bitcoinj library, it is actually a general purpose solution which could be included in any security conscious build process. It will also scan your existing project and identify any problem area while it automatically builds the whitelist for you.

    Below is an example of the configuration you'd require in your project to use it.

    <build>
      <plugins>
        ...
          <!-- Use the Enforcer to verify build integrity -->
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-enforcer-plugin</artifactId>
            <version>1.2</version>
            <executions>
              <execution>
                <id>enforce</id>
                <phase>verify</phase>
                <goals>
                  <goal>enforce</goal>
                </goals>
                <configuration>
                  <rules>
                    <digestRule implementation="uk.co.froot.maven.enforcer.DigestRule">
    
                      <!-- Create a snapshot to build the list of URNs below -->
                      <buildSnapshot>true</buildSnapshot>
    
                      <!-- List of required hashes -->
                      <!-- Format is URN of groupId:artifactId:version:type:classifier:scope:hash -->
                      <!-- classifier is "null" if not present -->
                      <urns>
    
                        <urn>antlr:antlr:2.7.7:jar:null:compile:83cd2cd674a217ade95a4bb83a8a14f351f48bd0</urn>
                        <urn>dom4j:dom4j:1.6.1:jar:null:compile:5d3ccc056b6f056dbf0dddfdf43894b9065a8f94</urn>
                        <urn>org.bouncycastle:bcprov-jdk15:1.46:jar:null:compile:d726ceb2dcc711ef066cc639c12d856128ea1ef1</urn>
                        <urn>org.hibernate.common:hibernate-commons-annotations:4.0.1.Final:jar:null:compile:78bcf608d997d0529be2f4f781fdc89e801c9e88</urn>
                        <urn>org.hibernate.javax.persistence:hibernate-jpa-2.0-api:1.0.1.Final:jar:null:compile:3306a165afa81938fc3d8a0948e891de9f6b192b</urn>
                        <urn>org.hibernate:hibernate-core:4.1.8.Final:jar:null:compile:82b420eaf9f34f94ed5295454b068e62a9a58320</urn>
                        <urn>org.hibernate:hibernate-entitymanager:4.1.8.Final:jar:null:compile:70a29cc959862b975647f9a03145274afb15fc3a</urn>
                        <urn>org.javassist:javassist:3.15.0-GA:jar:null:compile:79907309ca4bb4e5e51d4086cc4179b2611358d7</urn>
                        <urn>org.jboss.logging:jboss-logging:3.1.0.GA:jar:null:compile:c71f2856e7b60efe485db39b37a31811e6c84365</urn>
                        <urn>org.jboss.spec.javax.transaction:jboss-transaction-api_1.1_spec:1.0.0.Final:jar:null:compile:2ab6236535e085d86f37fd97ddfdd35c88c1a419</urn>
    
                        <!-- A check for the rules themselves -->
                        <urn>uk.co.froot.maven.enforcer:digest-enforcer-rules:0.0.1:jar:null:runtime:16a9e04f3fe4bb143c42782d07d5faf65b32106f</urn>
    
                      </urns>
    
                    </digestRule>
                  </rules>
                </configuration>
              </execution>
            </executions>
    
            <!-- Ensure we download the enforcer rules -->
            <dependencies>
              <dependency>
                <groupId>uk.co.froot.maven.enforcer</groupId>
                <artifactId>digest-enforcer-rules</artifactId>
                <version>0.0.1</version>
              </dependency>
            </dependencies>
    
          </plugin>
        ...
      </plugins>
    </build>