IBM Support

Encryption Using the QPyLib Encdec Module

How To


Summary

This tutorial will outline how you can use the QPyLib Encdec module to securely store your app's data.

Environment

QRadar App SDK v2

Steps

This tutorial also requires an IBM X-Force Exchange API key and password, which can be made by following these steps:

  1. Go to IBM X-Force Exchange.
  2. Log in, or make an account if you don't have one.
  3. Go to your settings page.
  4. Generate a new API key and password and copy them, don't lose this as you can't get it again after this point.

Create the App

Create a new directory for the app:

mkdir VulnerabilitiesApp && cd VulnerabilitiesApp

Use the QRadar App SDK to initialise the app code:

qapp create

Write the Manifest

Open the manifest.json file to edit some values to make it more relevant to the app, making it look like this:

{
  "name": "Recent X-Force Vulnerabilities",
  "description": "App showing recent X-Force Exchange vulnerabilities",
  "version": "1.0.0",
  "image": "qradar-app-base:2.0.0",
  "areas": [
    {
      "id": "QRecentVulnerabilities",
      "text": "Recent Vulnerabilities",
      "description": "Area showing 10 most recent X-Force Exchange Vulnerabilities",
      "url": "index",
      "required_capabilities": []
    }
  ],
  "uuid": "<your unique app UUID>"
}

This manifest defines an area called QRecentVulnerabilities that will serve the app user interface.

Write the App Jinja Template

Delete app/templates/hello.html and create a new file app/templates/index.html:

<!DOCTYPE html>
<html>
  <head>
    <title>Recent IBM X-Force Exchange Vulnerabilities</title>
    <script type="text/javascript" src='./static/qjslib/qappfw.min.js'></script>
  </head>
  <body>
    <h1>Recent IBM X-Force Exchange Vulnerabilities</h1>
    {% if xforce_auth_set %}
    <ul>
        {% for vulnerability in vulnerabilities %}
        <li>
            {{vulnerability.type}} - {{vulnerability.title}}
        </li>
        {% endfor %}
    </ul>
    {% else %}
    <p>Error decrypting API key: {{ decryption_error }}</p>
    <h2>No API key, submit one to fetch recent vulnerabilities</h2>
    <input id="api-key-input" type="text" placeholder="IBM X-Force Exchange API Key"/>
    <input id="api-pass-input" type="text" placeholder="IBM X-Force Exchange API Password"/>
    <input id="api-key-submit" type="submit">
    <script>
        // Using QJSLib library to make HTTP request
        var QRadar = window.qappfw.QRadar;

        document.getElementById("api-key-submit").addEventListener("click", function() {
            // Get input values
            var apiKey = document.getElementById("api-key-input").value;
            var apiPass = document.getElementById("api-pass-input").value;

            // POST xforce API details to set-api-key endpoint
            QRadar.fetch("set-api-key", {
                method: "post",
                headers: {
                    "Content-Type": "application/json",
                },
                body: JSON.stringify({
                    key: apiKey,
                    pass: apiPass
                })
            })
                .then(function(response) {
                    if (response.ok) {
                        // Success setting api auth details, refresh
                        window.location.reload(true);
                        return;
                    }
                })
                .catch(function(error) {
                    // Error, display error to user
                    alert(error)
                });
        });
    </script>
    {% endif %}
  </body>
</html>

This Jinja template provides the entire user interface for the app, with two key pieces of functionality. The template handles displaying a list of vulnerabilities if they are provided to the template, and the X-Force API auth is set. If there is no X-Force API auth set it will instead provide a simple form to allow the user to submit an X-Force API key and password.

The submission of the X-Force API auth uses the QJSLib library to make an HTTP POST request to the set-api-key endpoint, populating the body with the API auth details input to the textboxes.

Create the App Endpoints

Add the app HTTP endpoints by editing app/views.py:

import json
import requests
from flask import Blueprint, render_template, request
from qpylib.encdec import Encryption, EncryptionError

# pylint: disable=invalid-name
viewsbp = Blueprint('viewsbp', __name__, url_prefix='/')

# Endpoint that decrypts the xforce api key and password, then uses it to get
# the 10 most recent X-Force Exchange vulnerabilities. If xforce details are
# retrieved successfully it will show the 10 vulnerabilities, if there is an
# error decrypting/reading the xforce secrets it will show an interface for the
# user to provide these details
@viewsbp.route('/')
@viewsbp.route('/index')
def index():
    try:
        # Decrypt the X-Force API Key
        encKey = Encryption({'name': 'xforce_key', 'user': 'shared'})
        key = encKey.decrypt()

        # Decrypt the X-Force Password
        encPass = Encryption({'name': 'xforce_pass', 'user': 'shared'})
        passwd = encPass.decrypt()

        # Get the 10 most recent X-Force Exchange vulnerabilities
        response = requests.get("https://api.xforce.ibmcloud.com/vulnerabilities/?limit=10", auth=(key, passwd))
        vulnerabilities = response.json()

        return render_template('index.html', xforce_auth_set=True, vulnerabilities=vulnerabilities)
    except EncryptionError as err:
        # An error occured, ask the user to input the API details again
        return render_template('index.html', xforce_auth_set=False, decryption_error=str(err))


# Endpoint that takes xforce api auth details, and encrypts and stores them
# using the QPyLib encdec module, if successful returns a 204 no content
# response
@viewsbp.route('/set-api-key', methods=['POST'])
def set_api_key():
    # Load provided API details from JSON
    xforce_data = json.loads(request.data)

    # Encrypt the API Key
    encKey = Encryption({'name': 'xforce_key', 'user': 'shared'})
    encKey.encrypt(xforce_data["key"])

    # Encrypt the API Password
    encPass = Encryption({'name': 'xforce_pass', 'user': 'shared'})
    encPass.encrypt(xforce_data["pass"])

    # Success, return a 204 no content
    return ('', 204)

This sets up the app's two HTTP endpoints, one to serve the templated user interface, injected with the 10 most recent vulnerabilities

Test the App Locally

The app is now ready to test out, which can be done by running the app locally using the QRadar App SDK.

There is one extra step before you can run this app, you must add a line to the qenv.ini file to inject the required QRADAR_APP_UUID environment variable into the app. This is required for the QPyLib Encdec module to work when running a QRadar app locally, it is not required when deployed on a QRadar instance. The qenv.ini file should look like this:

[qradar]
QRADAR_CONSOLE_FQDN=
QRADAR_CONSOLE_IP=

[proxy]
QRADAR_REST_PROXY=

[app]
SEC_ADMIN_TOKEN=
QRADAR_APP_UUID=<your unique app UUID>

Once this has been added, you can run your app with the QRadar App SDK:

qapp run

The QRadar App SDK will report the port that the app is running on, allowing you to access the app at http://localhost:<app port>.

QPyLib Encdec

To find out more about the QPyLib Encdec module, see the Secure Data Storage and Encryption page.

Document Location

Worldwide

[{"Line of Business":{"code":"LOB24","label":"Security Software"},"Business Unit":{"code":"BU059","label":"IBM Software w\/o TPS"},"Product":{"code":"SSBQAC","label":"IBM Security QRadar SIEM"},"ARM Category":[{"code":"a8m0z000000cwt3AAA","label":"QRadar Apps"}],"ARM Case Number":"","Platform":[{"code":"PF025","label":"Platform Independent"}],"Version":"All Version(s)"}]

Document Information

Modified date:
30 March 2021

UID

ibm16437431