O que é Dependency Track?
Dependency Track é uma ferramenta desenvolvida pela OWASP com o intuito de ajudar a monitorar os componentes (dependências), de maneira proativa, da organização. Ela é uma ferramenta de SBOM (Software Bill of Material- um inventário com as principais informações sobre os componentes. Essas informações podem ser: número da versão, licenciamento, detalhes do fornecedor)
Overview sobre a vulnerabilidade:
Isso é muito importante, pois quando temos muitas aplicações, nem sempre analisamos as dependências dela. Principalmente, quando os devs estão desenvolvendo novas funcionalidades para aplicação. Geralmente, eles só analisam as dependências quando há alguma quebra em uma feature ou no início do desenvolvimento do projeto.
Para isso, com essa ferramenta, de maneira proativa, o dev pode acessar o sistema do Dependency Track e saber se há alguma vulnerabilidade/CVE para aquela biblioteca em que se encontra no projeto. Como também, ele pode ser adicionado em uma ferramenta de CI/CD, como no GitHub actions, através dessa action aqui:
uses: DependencyTrack/gh-upload-sbom@v3
with:
serverHostname: 'example.com'
apiKey: ${{ secrets.DEPENDENCYTRACK_APIKEY }}
projectName: 'Example Project'
projectVersion: 'master'
bomFilename: "/path/to/bom.xml"
autoCreate: true
Seguem as instruções para instalar o Dependency Track
- Primeira vez que logar terá usuário e senha default: admin/admin
- Instale o docker na máquina
docker-compose.yml
#####################################################
# This Docker Compose file contains two services
# Dependency-Track API Server
# Dependency-Track FrontEnd
#####################################################
volumes:
dependency-track:
services:
dtrack-apiserver:
image: dependencytrack/apiserver
# environment:
# The Dependency-Track container can be configured using any of the
# available configuration properties defined in:
# https://docs.dependencytrack.org/getting-started/configuration/
# All properties are upper case with periods replaced by underscores.
#
# Database Properties
# - ALPINE_DATABASE_MODE=external
# - ALPINE_DATABASE_URL=jdbc:postgresql://postgres10:5432/dtrack
# - ALPINE_DATABASE_DRIVER=org.postgresql.Driver
# - ALPINE_DATABASE_USERNAME=dtrack
# - ALPINE_DATABASE_PASSWORD=changeme
# - ALPINE_DATABASE_POOL_ENABLED=true
# - ALPINE_DATABASE_POOL_MAX_SIZE=20
# - ALPINE_DATABASE_POOL_MIN_IDLE=10
# - ALPINE_DATABASE_POOL_IDLE_TIMEOUT=300000
# - ALPINE_DATABASE_POOL_MAX_LIFETIME=600000
#
# Optional LDAP Properties
# - ALPINE_LDAP_ENABLED=true
# - ALPINE_LDAP_SERVER_URL=ldap://ldap.example.com:389
# - ALPINE_LDAP_BASEDN=dc=example,dc=com
# - ALPINE_LDAP_SECURITY_AUTH=simple
# - ALPINE_LDAP_BIND_USERNAME=
# - ALPINE_LDAP_BIND_PASSWORD=
# - ALPINE_LDAP_AUTH_USERNAME_FORMAT=%s@example.com
# - ALPINE_LDAP_ATTRIBUTE_NAME=userPrincipalName
# - ALPINE_LDAP_ATTRIBUTE_MAIL=mail
# - ALPINE_LDAP_GROUPS_FILTER=(&(objectClass=group)(objectCategory=Group))
# - ALPINE_LDAP_USER_GROUPS_FILTER=(member:1.2.840.113556.1.4.1941:={USER_DN})
# - ALPINE_LDAP_GROUPS_SEARCH_FILTER=(&(objectClass=group)(objectCategory=Group)(cn=*{SEARCH_TERM}*))
# - ALPINE_LDAP_USERS_SEARCH_FILTER=(&(objectClass=user)(objectCategory=Person)(cn=*{SEARCH_TERM}*))
# - ALPINE_LDAP_USER_PROVISIONING=false
# - ALPINE_LDAP_TEAM_SYNCHRONIZATION=false
#
# Optional OpenID Connect (OIDC) Properties
# - ALPINE_OIDC_ENABLED=true
# - ALPINE_OIDC_ISSUER=https://auth.example.com/auth/realms/example
# - ALPINE_OIDC_CLIENT_ID=
# - ALPINE_OIDC_USERNAME_CLAIM=preferred_username
# - ALPINE_OIDC_TEAMS_CLAIM=groups
# - ALPINE_OIDC_USER_PROVISIONING=true
# - ALPINE_OIDC_TEAM_SYNCHRONIZATION=true
#
# Optional HTTP Proxy Settings
# - ALPINE_HTTP_PROXY_ADDRESS=proxy.example.com
# - ALPINE_HTTP_PROXY_PORT=8888
# - ALPINE_HTTP_PROXY_USERNAME=
# - ALPINE_HTTP_PROXY_PASSWORD=
# - ALPINE_NO_PROXY=
#
# Optional HTTP Outbound Connection Timeout Settings. All values are in seconds.
# - ALPINE_HTTP_TIMEOUT_CONNECTION=30
# - ALPINE_HTTP_TIMEOUT_SOCKET=30
# - ALPINE_HTTP_TIMEOUT_POOL=60
#
# Optional Cross-Origin Resource Sharing (CORS) Headers
# - ALPINE_CORS_ENABLED=true
# - ALPINE_CORS_ALLOW_ORIGIN=*
# - ALPINE_CORS_ALLOW_METHODS=GET, POST, PUT, DELETE, OPTIONS
# - ALPINE_CORS_ALLOW_HEADERS=Origin, Content-Type, Authorization, X-Requested-With, Content-Length, Accept, Origin, X-Api-Key, X-Total-Count, *
# - ALPINE_CORS_EXPOSE_HEADERS=Origin, Content-Type, Authorization, X-Requested-With, Content-Length, Accept, Origin, X-Api-Key, X-Total-Count
# - ALPINE_CORS_ALLOW_CREDENTIALS=true
# - ALPINE_CORS_MAX_AGE=3600
#
# Optional logging configuration
# - LOGGING_LEVEL=INFO
# - LOGGING_CONFIG_PATH=logback.xml
#
# Optional metrics properties
# - ALPINE_METRICS_ENABLED=true
# - ALPINE_METRICS_AUTH_USERNAME=
# - ALPINE_METRICS_AUTH_PASSWORD=
#
# Optional environmental variables to enable default notification publisher templates override and set the base directory to search for templates
# - DEFAULT_TEMPLATES_OVERRIDE_ENABLED=false
# - DEFAULT_TEMPLATES_OVERRIDE_BASE_DIRECTORY=/data
#
# Optional configuration for the Snyk analyzer
# - SNYK_THREAD_BATCH_SIZE=10
#
# Optional environmental variables to provide more JVM arguments to the API Server JVM, i.e. "-XX:ActiveProcessorCount=8"
# - EXTRA_JAVA_OPTIONS=
deploy:
resources:
limits:
memory: 12288m
reservations:
memory: 8192m
restart_policy:
condition: on-failure
ports:
- '8081:8080'
volumes:
- 'dependency-track:/data'
restart: unless-stopped
dtrack-frontend:
image: dependencytrack/frontend
depends_on:
- dtrack-apiserver
environment:
# The base URL of the API server.
# NOTE:
# * This URL must be reachable by the browsers of your users.
# * The frontend container itself does NOT communicate with the API server directly, it just serves static files.
# * When deploying to dedicated servers, please use the external IP or domain of the API server.
- API_BASE_URL=http://localhost:8081
# - "OIDC_ISSUER="
# - "OIDC_CLIENT_ID="
# - "OIDC_SCOPE="
# - "OIDC_FLOW="
# - "OIDC_LOGIN_BUTTON_TEXT="
# volumes:
# - "/host/path/to/config.json:/app/static/config.json"
ports:
- "8080:8080"
restart: unless-stopped
Comando:
docker-compose up
URL da ferramenta: http://127.0.0.1:8080/
Após acessar a ferramenta, crie um time para que possa ter a API KEY para que possa usar na action descrita anteriormente ou através do script que disponibilizarei abaixo
O principal ponto é adicionar a permissão de BOM_UPLOAD. Assim, você conseguirá ter permissão na API KEY para enviar o arquivo bom.json com as informações das dependências do seu projeto (SBOM). Ele funciona com quase todas as linguagens. Eu utilizei o Python como exemplo abaixo.
Para criar bom.json
pip3 install cyclonedx-bom
Na pasta aonde se encontra os arquivos de dependências — requirements.txt — utilize o comando:
cyclonedx-py requirements -o bom.json
Após isso, você pode manualmente fazer o upload do bom.json no Dependency Track ou usar o script
Script test.py
import argparse
import sys
import requests
parser = argparse.ArgumentParser(prog = 'dt_sbom_uploader',description = 'Upload a sbom to Dependency Track')
parser.add_argument('-s', '--sbom', help='Path to the SBOM file to upload')
parser.add_argument('-n', '--name', help='Dependency Track project name')
parser.add_argument('-v', '--version', help='Dependency Track project version')
parser.add_argument('-u', '--url', help='Dependency Track base URL like http://localhost:8080')
parser.add_argument('-k', '--key', help='Dependency Track API Key')
args = parser.parse_args()
if (args.sbom is None or args.name is None or args.version is None or args.url is None or args.key is None):
parser.print_help()
sys.exit(1)
try:
data = open(args.sbom, 'rb').read()
except:
print ('Error: could not open file '+args.sbom+' for reading')
sys.exit(1)
# Build the POST request
post_data = {}
post_data['projectName'] = args.name
post_data['projectVersion'] = args.version
post_data['autoCreate'] = 'true'
bomFile = {'bom': data}
api_key_header = {'X-Api-Key': args.key}
r = requests.post(url=args.url+'/api/v1/bom', files=bomFile, data=post_data, headers=api_key_header)
print (r)
print (r.text)
Comando:
python3 test.py -s bom.json -n Nome_do_Projeto -v 0.0.1 -u http://localhost:8081 -k API_KEY
Projeto importado 😊
- É possível ver que existe uma vulnerabilidade alta no projeto "Vuln App"
O projeto é interessante pois te ajuda a manter atualizado sobre as bibliotecas e que com esse sistema, você gera autonomia para o dev analisar as aplicações que ele desenvolve e verificar as vulnerabilidades sobre essas aplicações. Como também, é um item importante de auditoria, pois ajuda a manter um controle sobre as bibliotecas e as novas CVEs que podem aparecer nas bibliotecas do projeto e das aplicações de maneira geral.
Assim, como o dashboard abaixo, é possível analisar todas as bibliotecas vulneráveis e filtrar pela severidade, por exemplo.
Como também, é possível realizar uma análise e justificar se aquela biblioteca não é vulnerável. Dependendo do contexto, pode ser que você não use a função da biblioteca que a torna vulnerável e para a sua organização, isso possa ser considerado como falso positivo.
Espero que tenham gostado 😎