Invariant Properties

  • rss
  • Home

Creating Vulnerability Assessment Artifacts Using Maven Assembly

Bear Giles | October 5, 2013

This article will discuss using Maven Assembly to create artifacts that can be provided to third-party vulnerability assessment sites (e.g., Veracode) for review.

Static Analysis for Bugs vs. Vulnerability Assessments

At this point everyone is aware of findbugs and uses it religiously, right?

Right?

Findbugs uses static analysis to find bugs. More precisely, it uses static analysis to find bugs that can be found by static analysis. For instance I’ve seen a common pattern of

  1. public void foo(Object obj) {
  2.     if (obj != null) {
  3.         obj.doSomething();
  4.     }
  5.  
  6.     // lots of obscuring code
  7.  
  8.     obj.doSomethingElse()
  9. }
public void foo(Object obj) {
    if (obj != null) {
        obj.doSomething();
    }

    // lots of obscuring code

    obj.doSomethingElse()
}

Should we check for null a second time? Did we need to check the first time? Should we have returned from the ‘if’ clause?

Why do we also need vulnerability assessment?

What is vulnerability assessment? How is it different from bugs?

The key concept is that vulnerable code is superficially bug-free but is still vulnerable to misuse to attack this site or its users.

An example of vulnerable code is using unsanitized user-provided values. Anyone working on the front-end should know the importance of sanitizing these values.

But what happens when user-provided data is passed out of the front-end, e.g., when it’s written to the database? Will everyone who pulls data from the database know that it might contain unsanitized user-provided data? What about malicious data put into the database via SQL injection?

Static analysis for vulnerability assessment looks a lot like static analysis to find bugs, just a lot more through. Whereas findbugs may take 5 minutes to run Veracode may take a few hours!

(Dynamic analysis takes this a step further and runs the tests against a live system. You can do a light version of this using integration tests.)

Artifacts for Vulnerability Assessment

What do we need to provide for vulnerability assessments? The short answer is three things:

  • our compiled code (e.g., java or scala)
  • our scripted code (e.g., jsp)
  • every jar file we depend on, recursively

We don’t need to provide our source code or resources. The compiled code does need to include debug systems so it can give meaningful error messages – knowing only that there’s 19 defects in a library containing 79 classes isn’t very helpful!

A good format is a tarball containing:

  • our jar and wars at the top level, sans version number
  • our dependencies under “/lib”, with version number

The version numbers are stripped or retained for tracking purposes. Our code has a continuity across multiple runs. Our dependencies can change at any time and don’t have any continuity beyond what’s explicitly indicated in the version numbers.

Our war files should be stripped of embedded jars since they’ll be present under the ‘lib’ directory. “Thick” war files just increase the size of the uploaded artifact.

We can build this with two maven assembly descriptors.

va-war.xml (vulnerability assessment skinny war)

The first assembly creates a stripped down .war file. I don’t want to call it a skinny war since the intended purpose is different but they have a lot in common.

  1. <assembly
  2.    xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
  3.    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4.    xsi:schemaLocation=
  5.       "http://maven.apache.org/plugins/maven/assembly-plugin/assembly/1.1.2
  6.        http://maven.apache.org/xsd/assembly-1.1.2.xsd">
  7.  
  8.     <id>va-war</id>
  9.     <formats>
  10.         <format>war</format>
  11.     </formats>
  12.  
  13.     <includeBaseDirectory>false</includeBaseDirectory>
  14.  
  15.     <fileSets>
  16.         <!-- grab everything except any jars -->
  17.         <fileSet>
  18.             <directory>target/${project.artifactId}-${project.version}</directory>
  19.             <outputDirectory>/</outputDirectory>
  20.             <includes />
  21.             <excludes>
  22.                 <exclude>**/*.jar</exclude>
  23.             </excludes>
  24.         </fileSet>
  25.     </fileSets>
  26. </assembly>
<assembly
    xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation=
       "http://maven.apache.org/plugins/maven/assembly-plugin/assembly/1.1.2
        http://maven.apache.org/xsd/assembly-1.1.2.xsd">

    <id>va-war</id>
    <formats>
        <format>war</format>
    </formats>

    <includeBaseDirectory>false</includeBaseDirectory>

    <fileSets>
        <!-- grab everything except any jars -->
        <fileSet>
            <directory>target/${project.artifactId}-${project.version}</directory>
            <outputDirectory>/</outputDirectory>
            <includes />
            <excludes>
                <exclude>**/*.jar</exclude>
            </excludes>
        </fileSet>
    </fileSets>
</assembly>

You can exclude additional files if you have sensitive information or a lot of large artifacts:

  1.             <excludes>
  2.                 <exclude>**/*.jar</exclude>
  3.                 <exclude>**/*.jks</exclude>
  4.                 <exclude>**/*.p12</exclude>
  5.                 <exclude>**/*.jpg</exclude>
  6.                 <exclude>**/db.properties</exclude>
  7.             </excludes>
            <excludes>
                <exclude>**/*.jar</exclude>
                <exclude>**/*.jks</exclude>
                <exclude>**/*.p12</exclude>
                <exclude>**/*.jpg</exclude>
                <exclude>**/db.properties</exclude>
            </excludes>

You need to be careful though – you need to include anything that’s scripted, e.g., jsp files or velocity templates.

va-artifact.xml (vulnerability assessment artifact)

The second artifact collects all of the dependencies and stripped down wars into a single tarball. Our jars and wars are at the top level of the tarball, all dependencies are in a ‘lib’ directory. This makes it easy to distinguish between our artifacts and our dependencies.

  1. <assembly
  2.    xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
  3.    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4.    xsi:schemaLocation=
  5.       "http://maven.apache.org/plugins/maven/assembly-plugin/assembly/1.1.2
  6.        http://maven.apache.org/xsd/assembly-1.1.2.xsd">
  7.  
  8.     <id>va-artifact</id>
  9.     <formats>
  10.         <format>tar.gz</format>
  11.     </formats>
  12.  
  13.     <includeBaseDirectory>false</includeBaseDirectory>
  14.     <dependencySets>
  15.  
  16.         <!-- ******************************************* -->
  17.         <!-- Our code should not include version numbers -->
  18.         <!-- ******************************************* -->
  19.         <dependencySet>
  20.             <includes>
  21.                 <include>${project.groupId}:*:jar</include>
  22.                 <include>${project.groupId}:*:va-war</include>
  23.  
  24.                 <!-- we could also include subprojects -->
  25.                 <include>${project.groupId}.**:*:jar</include>
  26.             </includes>
  27.  
  28.             <!-- we might have sensitive resources -->
  29.             <excludes>
  30.                 <exclude>${project.groupId}:*-properties</exclude>
  31.             <excludes>
  32.             <outputFileNameMapping>${artifact.artifactId}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
  33.         </dependencySet>
  34.  
  35.         <!-- *********************************************** -->
  36.         <!-- Our dependencies should include version numbers -->
  37.         <!-- *********************************************** -->
  38.         <dependencySet>
  39.             <outputDirectory>lib</outputDirectory>
  40.             <includes />
  41.  
  42.             <excludes>
  43.                 <exclude>${project.groupId}:*</exclude>
  44.                 <exclude>*.pom</exclude>
  45.  
  46.                 <!-- exclude standard APIs -->
  47.                 <exclude>javax.*:*</exclude>
  48.                 <exclude>dom4j:*</exclude>
  49.                 <exclude>jaxen:*</exclude>
  50.                 <exclude>jdom:*</exclude>
  51.                 <exclude>xml-apis:*</exclude>
  52.             </excludes>
  53.         </dependencySet>
  54.     </dependencySets>
  55. </assembly>
<assembly
    xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation=
       "http://maven.apache.org/plugins/maven/assembly-plugin/assembly/1.1.2
        http://maven.apache.org/xsd/assembly-1.1.2.xsd">

    <id>va-artifact</id>
    <formats>
        <format>tar.gz</format>
    </formats>

    <includeBaseDirectory>false</includeBaseDirectory>
    <dependencySets>

        <!-- ******************************************* -->
        <!-- Our code should not include version numbers -->
        <!-- ******************************************* -->
        <dependencySet>
            <includes>
                <include>${project.groupId}:*:jar</include>
                <include>${project.groupId}:*:va-war</include>

                <!-- we could also include subprojects -->
                <include>${project.groupId}.**:*:jar</include>
            </includes>

            <!-- we might have sensitive resources -->
            <excludes>
                <exclude>${project.groupId}:*-properties</exclude>
            <excludes>
            <outputFileNameMapping>${artifact.artifactId}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
        </dependencySet>

        <!-- *********************************************** -->
        <!-- Our dependencies should include version numbers -->
        <!-- *********************************************** -->
        <dependencySet>
            <outputDirectory>lib</outputDirectory>
            <includes />

            <excludes>
                <exclude>${project.groupId}:*</exclude>
                <exclude>*.pom</exclude>

                <!-- exclude standard APIs -->
                <exclude>javax.*:*</exclude>
                <exclude>dom4j:*</exclude>
                <exclude>jaxen:*</exclude>
                <exclude>jdom:*</exclude>
                <exclude>xml-apis:*</exclude>
            </excludes>
        </dependencySet>
    </dependencySets>
</assembly>

Building the Artifacts

The assembly descriptors are only half of the story. We still need to call maven assembly and we do not want to do it for every build.

This is an ideal time for profiles – we will only build artifacts when a specific profile is specified.

pom.xml for war modules

The necessary addition to the pom.xml file for war modules is modest. We need to call our assembly descriptor but we don’t need to explicitly add dependencies.

  1. <profiles>
  2.     <profile>
  3.         <id>vulnerability-assessment</id>
  4.         <build>
  5.             <plugins>
  6.                 <plugin>
  7.                     <artifactId>maven-assembly-plugin</artifactId>
  8.                     <configuration>
  9.                         <descriptors>
  10.                             <descriptor>src/main/assembly/va-war.xml</descriptor>
  11.                         </descriptors>
  12.                     </configuration>
  13.                     <executions>
  14.                         <execution>
  15.                             <id>make-assembly</id>
  16.                             <phase>package</phase>
  17.                             <goals>
  18.                                 <goal>single</goal>
  19.                             </goals>
  20.                         </execution>
  21.                     </executions>
  22.                 </plugin>
  23.             </plugins>
  24.         </build>
  25.     </profile>
  26. </profiles>
<profiles>
    <profile>
        <id>vulnerability-assessment</id>
        <build>
            <plugins>
                <plugin>
                    <artifactId>maven-assembly-plugin</artifactId>
                    <configuration>
                        <descriptors>
                            <descriptor>src/main/assembly/va-war.xml</descriptor>
                        </descriptors>
                    </configuration>
                    <executions>
                        <execution>
                            <id>make-assembly</id>
                            <phase>package</phase>
                            <goals>
                                <goal>single</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    </profile>
</profiles>

pom.xml for top-level modules

The necessary addition to the pom.xml file for the top-level module is more complex, especially when the distribution assembly is created in a submodule instead of the root module. In this case we need to explicitly add a dependency on both pom files and lite war files. If we don’t specify the former we’ll lose most dependencies, if we don’t specify the latter we’ll lose the .war files.

  1. <profiles>
  2.     <profile>
  3.         <id>vulnerability-assessment</id>
  4.         <build>
  5.             <plugins>
  6.                 <plugin>
  7.                     <artifactId>maven-assembly-plugin</artifactId>
  8.                     <configuration>
  9.                         <descriptors>
  10.                             <descriptor>src/main/assembly/va-artifact.xml</descriptor>
  11.                         </descriptors>
  12.                     </configuration>
  13.                     <executions>
  14.                         <execution>
  15.                             <id>make-assembly</id>
  16.                             <phase>package</phase>
  17.                             <goals>
  18.                                 <goal>single</goal>
  19.                             </goals>
  20.                         </execution>
  21.                     </executions>
  22.                 </plugin>
  23.             </plugins>
  24.         </build>
  25.  
  26.         <dependencies>
  27.             <!-- specify parent pom -->
  28.             <dependency>
  29.                 <groupId>${project.groupId}</groupId>
  30.                 <artifactId>parent</artifactId> <!-- FIXME -->
  31.                 <version>${project.version}</version>
  32.                 <type>pom</type>
  33.             </dependency>
  34.  
  35.             <!-- specify each war file and corresponding pom file -->
  36.             <dependency>
  37.                 <groupId>${project.groupId}</groupId>
  38.                 <artifactId>webapp-1</artifactId> <!-- FIXME -->
  39.                 <version>${project.version}</version>
  40.                 <type>war</type>
  41.                 <classifier>va-war</classifier>
  42.             </dependency>
  43.             <dependency>
  44.                 <groupId>${project.groupId}</groupId>
  45.                 <artifactId>webapp-1</artifactId> <!-- FIXME -->
  46.                 <version>${project.version}</version>
  47.                 <type>pom</type>
  48.             </dependency>
  49.  
  50.             <!-- second... -->
  51.             <dependency>
  52.                 <groupId>${project.groupId}</groupId>
  53.                 <artifactId>webapp-2</artifactId> <!-- FIXME -->
  54.                 <version>${project.version}</version>
  55.                 <type>war</type>
  56.                 <classifier>va-war</classifier>
  57.             </dependency>
  58.             <dependency>
  59.                 <groupId>${project.groupId}</groupId>
  60.                 <artifactId>webapp-2</artifactId> <!-- FIXME -->
  61.                 <version>${project.version}</version>
  62.                 <type>pom</type>
  63.             </dependency>
  64.  
  65.             <!-- and so on... -->
  66.  
  67.         </dependencies>
  68.     </profile>
  69. </profiles>
<profiles>
    <profile>
        <id>vulnerability-assessment</id>
        <build>
            <plugins>
                <plugin>
                    <artifactId>maven-assembly-plugin</artifactId>
                    <configuration>
                        <descriptors>
                            <descriptor>src/main/assembly/va-artifact.xml</descriptor>
                        </descriptors>
                    </configuration>
                    <executions>
                        <execution>
                            <id>make-assembly</id>
                            <phase>package</phase>
                            <goals>
                                <goal>single</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>

        <dependencies>
            <!-- specify parent pom -->
            <dependency>
                <groupId>${project.groupId}</groupId>
                <artifactId>parent</artifactId> <!-- FIXME -->
                <version>${project.version}</version>
                <type>pom</type>
            </dependency>

            <!-- specify each war file and corresponding pom file -->
            <dependency>
                <groupId>${project.groupId}</groupId>
                <artifactId>webapp-1</artifactId> <!-- FIXME -->
                <version>${project.version}</version>
                <type>war</type>
                <classifier>va-war</classifier>
            </dependency>
            <dependency>
                <groupId>${project.groupId}</groupId>
                <artifactId>webapp-1</artifactId> <!-- FIXME -->
                <version>${project.version}</version>
                <type>pom</type>
            </dependency>

            <!-- second... -->
            <dependency>
                <groupId>${project.groupId}</groupId>
                <artifactId>webapp-2</artifactId> <!-- FIXME -->
                <version>${project.version}</version>
                <type>war</type>
                <classifier>va-war</classifier>
            </dependency>
            <dependency>
                <groupId>${project.groupId}</groupId>
                <artifactId>webapp-2</artifactId> <!-- FIXME -->
                <version>${project.version}</version>
                <type>pom</type>
            </dependency>

            <!-- and so on... -->

        </dependencies>
    </profile>
</profiles>

One small gotcha!

There is one small gotcha! in this specific approach. It is possible that the individual web modules will have dependencies on different versions of common libraries. Nobody wants this but once projects reach a certain size you can’t afford the time and effort required to keep all of the modules in sync.

This information will be lost when we do dependency resolution at a common location.

I don’t consider this a problem for two reasons. First, we can perform vulnerability assessments at a finer granularity – essentially perform the analysis at the .war level instead of the .ear file. This guarantees the libraries will match but will tremendously increase our work load if we have a large number of web modules.

Second, our primary focus is the vulnerabilities in our code, not in specific versions of third-party libraries. Those libraries provide important hints to the assessment tools but we only want a full analysis of our code. We can always run separate assessments of the libraries we depend upon if it’s necessary.

Jenkins Veracode Plugin

Finally I want to point out that there’s a Jenkins plugin for Veracode analysis: Veracode Scanner Plugin. It can be used to schedule scans on a regular basis so you don’t find hundreds of defects when you finally remember to run a scan just days before a release.

Categories
java, security
Comments rss
Comments rss
Trackback
Trackback

« Necessary vs. Essential Staying Sane Between Contracts and Furloughs »

Leave a Reply

Click here to cancel reply.

You must be logged in to post a comment.

Archives

  • May 2020 (1)
  • March 2019 (1)
  • August 2018 (1)
  • May 2018 (1)
  • February 2018 (1)
  • November 2017 (4)
  • January 2017 (3)
  • June 2016 (1)
  • May 2016 (1)
  • April 2016 (2)
  • March 2016 (1)
  • February 2016 (3)
  • January 2016 (6)
  • December 2015 (2)
  • November 2015 (3)
  • October 2015 (2)
  • August 2015 (4)
  • July 2015 (2)
  • June 2015 (2)
  • January 2015 (1)
  • December 2014 (6)
  • October 2014 (1)
  • September 2014 (2)
  • August 2014 (1)
  • July 2014 (1)
  • June 2014 (2)
  • May 2014 (2)
  • April 2014 (1)
  • March 2014 (1)
  • February 2014 (3)
  • January 2014 (6)
  • December 2013 (13)
  • November 2013 (6)
  • October 2013 (3)
  • September 2013 (2)
  • August 2013 (5)
  • June 2013 (1)
  • May 2013 (2)
  • March 2013 (1)
  • November 2012 (1)
  • October 2012 (3)
  • September 2012 (2)
  • May 2012 (6)
  • January 2012 (2)
  • December 2011 (12)
  • July 2011 (1)
  • June 2011 (2)
  • May 2011 (5)
  • April 2011 (6)
  • March 2011 (4)
  • February 2011 (3)
  • October 2010 (6)
  • September 2010 (8)

Recent Posts

  • 8-bit Breadboard Computer: Good Encapsulation!
  • Where are all the posts?
  • Better Ad Blocking Through Pi-Hole and Local Caching
  • The difference between APIs and SPIs
  • Hadoop: User Impersonation with Kerberos Authentication

Meta

  • Log in
  • Entries RSS
  • Comments RSS
  • WordPress.org

Pages

  • About Me
  • Notebook: Common XML Tasks
  • Notebook: Database/Webapp Security
  • Notebook: Development Tips

Syndication

Java Code Geeks

Know Your Rights

Support Bloggers' Rights
Demand Your dotRIGHTS

Security

  • Dark Reading
  • Krebs On Security Krebs On Security
  • Naked Security Naked Security
  • Schneier on Security Schneier on Security
  • TaoSecurity TaoSecurity

Politics

  • ACLU ACLU
  • EFF EFF

News

  • Ars technica Ars technica
  • Kevin Drum at Mother Jones Kevin Drum at Mother Jones
  • Raw Story Raw Story
  • Tech Dirt Tech Dirt
  • Vice Vice

Spam Blocked

53,793 spam blocked by Akismet
rss Comments rss valid xhtml 1.1 design by jide powered by Wordpress get firefox