Статьи

Создание артефактов оценки уязвимости с помощью сборки Maven

В этой статье будет обсуждаться использование Maven Assembly для создания артефактов, которые могут быть предоставлены сторонним сайтам оценки уязвимостей (например, Veracode ) для проверки.

Статический анализ ошибок и оценок уязвимостей

На данный момент все знают о findbugs и используют его религиозно, верно?

Правильно?

Findbugs использует статический анализ для поиска ошибок. Точнее, он использует статический анализ, чтобы найти ошибки, которые могут быть обнаружены статическим анализом. Например, я видел общую картину

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

Должны ли мы проверить на ноль во второй раз? Мы должны были проверить в первый раз? Должны ли мы вернуться из условия «если»?

Почему мы также нуждаемся в оценке уязвимости?

Что такое оценка уязвимости? Чем он отличается от ошибок?

Ключевой концепцией является то, что уязвимый код не имеет внешних ошибок, но все же уязвим для неправильного использования для атаки на этот сайт или его пользователей.

Примером уязвимого кода является использование неанизированных пользовательских значений. Любой, кто работает в клиентской части, должен знать о важности санации этих ценностей.

Но что происходит, когда предоставленные пользователем данные передаются из внешнего интерфейса, например, когда они записываются в базу данных? Будет ли каждый, кто извлекает данные из базы данных, знает, что она может содержать неанизированные данные, предоставленные пользователем? Как насчет вредоносных данных, помещаемых в базу данных посредством SQL-инъекции?

Статический анализ для оценки уязвимостей во многом похож на статический анализ для поиска ошибок, только намного больше. Принимая во внимание, что поиск ошибок может занять 5 минут, а запуск Veracode может занять несколько часов!

(Динамический анализ делает этот шаг дальше и запускает тесты для работающей системы. Вы можете сделать облегченную версию этого, используя интеграционные тесты.)

Артефакты для оценки уязвимости

Что нам нужно для оценки уязвимости? Короткий ответ — три вещи:

  • наш скомпилированный код (например, Java или Scala)
  • наш скриптовый код (например, JSP)
  • каждый jar-файл, от которого мы зависим, рекурсивно

Нам не нужно предоставлять наш исходный код или ресурсы. Скомпилированный код должен включать в себя системы отладки, чтобы он мог выдавать значимые сообщения об ошибках — знание только того, что в библиотеке, содержащей 79 классов, имеется 19 дефектов, не очень полезно!

Хороший формат — это тарбол, содержащий:

  • наш кувшин и войны на высшем уровне, без номера версии
  • наши зависимости в «/ lib» с номером версии

Номера версий удаляются или сохраняются для целей отслеживания. Наш код имеет непрерывность в нескольких прогонах. Наши зависимости могут измениться в любое время и не иметь никакой преемственности за пределами того, что явно указано в номерах версий.

Наши военные файлы должны быть удалены из встроенных jar-файлов, так как они будут присутствовать в каталоге ‘lib’. «Толстые» военные файлы просто увеличивают размер загружаемого артефакта.

Мы можем построить это с помощью двух дескрипторов maven.

va-war.xml (оценка уязвимости тощей войны)

Первая сборка создает урезанный .war-файл. Я не хочу называть это тощей войной, потому что ее цель отличается, но у них много общего.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<assembly
    xsi:schemaLocation=
 
    <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>

Вы можете исключить дополнительные файлы, если у вас есть конфиденциальная информация или много крупных артефактов:

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

Вы должны быть осторожны — вам нужно включить все, что написано в скриптах, например, jsp файлы или шаблоны скорости.

va-artifact.xml (артефакт оценки уязвимости)

Второй артефакт собирает все зависимости и уничтожает войны в один тарбол. Наши jar и wars находятся на верхнем уровне тарбола, все зависимости находятся в каталоге ‘lib’. Это позволяет легко различать наши артефакты и наши зависимости.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
<assembly
    xsi:schemaLocation=
 
    <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>

Создание артефактов

Дескрипторы сборки — это только половина истории. Нам все еще нужно вызывать сборку maven, и мы не хотим делать это для каждой сборки.

Это идеальное время для профилей — мы будем создавать артефакты только тогда, когда указан конкретный профиль.

pom.xml для военных модулей

Необходимое дополнение к файлу pom.xml для военных модулей является скромным. Нам нужно вызвать наш дескриптор сборки, но нам не нужно явно добавлять зависимости.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<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 для модулей верхнего уровня

Необходимое добавление в файл pom.xml для модуля верхнего уровня является более сложным, особенно когда сборка дистрибутива создается в подмодуле вместо корневого модуля. В этом случае нам нужно явно добавить зависимость как для файлов pom, так и для файлов lite war. Если мы не укажем первое, мы потеряем большинство зависимостей, если мы не укажем второе, мы потеряем файлы .war.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<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>

Одна маленькая ошибка!

Есть одна маленькая ошибка! в этом конкретном подходе. Возможно, что отдельные веб-модули будут зависеть от разных версий общих библиотек. Никто не хочет этого, но как только проекты достигают определенного размера, вы не можете позволить себе потратить время и усилия, необходимые для синхронизации всех модулей.

Эта информация будет потеряна, когда мы сделаем разрешение зависимостей в общем месте.

Я не считаю это проблемой по двум причинам. Во-первых, мы можем выполнить оценку уязвимости с более высокой степенью детализации — по сути, выполнить анализ на уровне .war вместо файла .ear. Это гарантирует, что библиотеки будут совпадать, но значительно увеличит нашу рабочую нагрузку, если у нас будет большое количество веб-модулей.

Во-вторых, наше основное внимание уделяется уязвимостям в нашем коде, а не в конкретных версиях сторонних библиотек. Эти библиотеки предоставляют важные подсказки для инструментов оценки, но нам нужен только полный анализ нашего кода. Мы всегда можем провести отдельные оценки библиотек, от которых мы зависим, если это необходимо.

Дженкинс Veracode плагин

Наконец, я хочу отметить, что есть плагин Jenkins для анализа Veracode : плагин Veracode Scanner . Его можно использовать для регулярного планирования сканирования, чтобы вы не обнаружили сотен дефектов, когда наконец не забыли запустить сканирование всего за несколько дней до выпуска.