SAST - Static Application Security Testing

Security problem

During code development it’s easy to unknowingly introduce bugs. As the code base gets bigger and the number of contributors rises, bugs can slip through, even though the team might do thorough code reviews.

Security control proposal

If Static Application Security Testing (SAST) tools are available for your programming language, you should utilize them in CI pipelines. Static analysis of source code can help catch certain coding errors and code smells early on. An added benefit is that developers can learn from recommendations made by these automated tools and be more careful in the future.

Reference implementation

SonarQube

One of the commonly used SAST tools is the SonarQube. The comprehensive documentation will guide you through the tool’s setup and usage.

Below are some Gitlab CI/CD configuration examples taken from SonarQube’s documentation.

YOUR_SONAR_TOKEN should be treated as a secret and set securely in the pipeline execution environment.

image: gradle:alpine
variables:
  SONAR_TOKEN: "${YOUR_SONAR_TOKEN}"
  SONAR_HOST_URL: "http://your-sonarqube-instance.org"
  GIT_DEPTH: 0
sonarqube-check:
  stage: test
  script: gradle sonarqube -Dsonar.qualitygate.wait=true
  allow_failure: true
  only:
    - merge_requests
    - master
image: maven:latest
variables:
  SONAR_TOKEN: "${YOUR_SONAR_TOKEN}"
  SONAR_HOST_URL: "http://your-sonarqube-url"
  GIT_DEPTH: 0
sonarqube-check:
  script:
    - mvn verify sonar:sonar -Dsonar.qualitygate.wait=true
  allow_failure: true
  only:
    - merge_requests
    - master
image:
  name: sonarsource/sonar-scanner-cli:latest
variables:
  SONAR_TOKEN: "${YOUR_SONAR_TOKEN}"
  SONAR_HOST_URL: "http://your-sonarqube-instance.org"
  SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar" # Defines the location of the analysis task cache
  GIT_DEPTH: 0 # Tells git to fetch all the branches of the project, required by the analysis task
cache:
  key: ${CI_JOB_NAME}
  paths:
    - .sonar/cache
sonarqube-check:
  stage: test
  script:
    - sonar-scanner -Dsonar.qualitygate.wait=true
  allow_failure: true
  only:
    - merge_requests
    - master

Practical implementation

SonarQube

In the examples you can find practical implementation of SonarQube scanning for Python3, golang, and node.js projects.

The environment variables listed below with prefix YOUR_ should be set up based on security best practices in the pipeline environment.

  • YOUR_SONAR_PROJECT_NAME - name of the project to be inspected; multiple projects can have the same name.
  • YOUR_SONAR_PROJECT_KEY - a unique string to identify the project. Recommended to be done via uuidgen command.
  • YOUR_SONAR_AUTH_TOKEN - the user token generated in the SonarQube.
sast_push_golang_analysis_to_sonarqube:
  stage: sast
  image: artifactory.tools.in.pan-net.eu/net_mon-images-docker-local/docker-images/docker-sast:latest
  only:
    refs:
    - sast
  variables:
    SONAR_PROJECT_NAME: "${YOUR_SONAR_PROJECT_NAME}"
    SONAR_PROJECT_KEY: "${YOUR_SONAR_PROJECT_KEY}"
    SONAR_GATE_ID: "2"
    SONAR_HOST_URL: "http://sast.security.in.pan-net.eu"
  script:
  - cd source/golang-geo
  # Create project. It's ok, if it already exists, the pipeline will continue
  - curl --user "${YOUR_SONAR_AUTH_TOKEN}:" -X POST ''"${SONAR_HOST_URL}"'/api/projects/create?name='"$SONAR_PROJECT_NAME"'&project='"$SONAR_PROJECT_KEY"'&visibility=private'
  # Set project quality gate - in here I set a simple gate ~ no worse security rating than B
  - curl --user "${YOUR_SONAR_AUTH_TOKEN}:" -X POST ''"${SONAR_HOST_URL}"'/api/qualitygates/select?gateId='"$SONAR_GATE_ID"'&projectKey='"$SONAR_PROJECT_KEY"''
  - sonar-scanner
    -Dsonar.projectKey=$SONAR_PROJECT_KEY
    -Dsonar.sources=.
    -Dsonar.host.url=$SONAR_HOST_URL
    -Dsonar.login=$YOUR_SONAR_AUTH_TOKEN
sast_push_python_analysis_to_sonarqube:
  stage: sast_push_analysis_to_sonarqube
  image: artifactory.tools.in.pan-net.eu/net_mon-images-docker-local/docker-images/docker-sast:latest
  only:
    refs:
    - build
    - sast
  variables:
    SONAR_PROJECT_NAME: "${YOUR_SONAR_PROJECT_NAME}"
    SONAR_PROJECT_KEY: "${YOUR_SONAR_PROJECT_KEY}"
    SONAR_GATE_ID: "2"
    SONAR_HOST_URL: "https://sast.security.in.pan-net.eu"
  script:
  - cd source/sg-miner-bot
  # Run bandit. If it finds any issues it will exit with 1, which stops the pipeline -> hence the || true
  - bandit -r -f json -o bandit-report.json . || true
  # Create project. It's ok, if it already exists, the pipeline will continue
  - curl --user "${YOUR_SONAR_AUTH_TOKEN}:" -X POST ''"${SONAR_HOST_URL}"'/api/projects/create?name='"$SONAR_PROJECT_NAME"'&project='"$SONAR_PROJECT_KEY"'&visibility=private'
  # Set project quality gate - in here I set a simple gate ~ no worse security rating than B
  - curl --user "${YOUR_SONAR_AUTH_TOKEN}:" -X POST ''"${SONAR_HOST_URL}"'/api/qualitygates/select?gateId='"$SONAR_GATE_ID"'&projectKey='"$SONAR_PROJECT_KEY"''
  - sonar-scanner
    -Dsonar.projectKey=$SONAR_PROJECT_KEY
    -Dsonar.sources=.
    -Dsonar.host.url=$SONAR_HOST_URL
    -Dsonar.login=$YOUR_SONAR_AUTH_TOKEN
    -Dsonar.python.bandit.reportPaths=bandit-report.json
sast_push_node_analysis_to_sonarqube:
  stage: sast
  image: artifactory.tools.in.pan-net.eu/net_mon-images-docker-local/docker-images/docker-sast:latest
  only:
    refs:
    - schedules
    variables:
    - $ACTION == "static application security testing"
  variables:
    SONAR_PROJECT_NAME: "${YOUR_SONAR_PROJECT_NAME}"
    SONAR_PROJECT_KEY: "${YOUR_SONAR_PROJECT_KEY}"
    SONAR_GATE_ID: "2"
    SONAR_HOST_URL: "https://sast.security.in.pan-net.eu"
  script:
  - cd source/node-hello
  - npm install
  # Create project. It's ok, if it already exists, the pipeline will continue
  - curl --user "${YOUR_SONAR_AUTH_TOKEN}:" -X POST ''"${SONAR_HOST_URL}"'/api/projects/create?name='"$SONAR_PROJECT_NAME"'&project='"$SONAR_PROJECT_KEY"'&visibility=private'
  # Set project quality gate - in here I set a simple gate ~ no worse security rating than B
  - curl --user "${YOUR_SONAR_AUTH_TOKEN}:" -X POST ''"${SONAR_HOST_URL}"'/api/qualitygates/select?gateId='"$SONAR_GATE_ID"'&projectKey='"$SONAR_PROJECT_KEY"''
  - sonar-scanner
    -Dsonar.projectKey=$SONAR_PROJECT_KEY
    -Dsonar.sources=.
    -Dsonar.host.url=$SONAR_HOST_URL
    -Dsonar.login=$YOUR_SONAR_AUTH_TOKEN