Encryption Using the QPyLib Encdec Module
You can use the QPyLib Encdec module to securely store your app’s data.
Follow these steps to set up a simple QRadar app that will provide a list of the 10 most recent vulnerabilities published on the IBM X-Force Exchange (XFE). To facilitate this, the app must support storing an XFE API key in a secure way that it can retrieve when needed.
Prerequisites
- QRadar App SDK v2
This tutorial also requires an IBM X-Force Exchange API key and password. If you do not have one, you can create an API key on X-Force Exchange:
- Go to IBM X-Force Exchange.
- Log in, or make an account if you don’t have one.
- Go to your settings page.
- Generate a new API key and password and copy them.
Important: Don’t lose this information. You cannot retrieve it later.
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. The completed file should 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
using the following code:
<!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>
<p>Error decrypting API key: </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>
</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, and the X-Force API authorization is set. If there is no X-Force API authorization set, the app 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 authorization details that the user provides.
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 locally using the QRadar App SDK.
Important: 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 the app is deployed on QRadar. The completed 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>
After you add this line, you can run your app with the QRadar App SDK:
qapp run
The QRadar App SDK reports the port that the app is running on so you can access the app at http://localhost:<_app port_>
.
QPyLib Encdec
To find out more about the QPyLib Encdec module, see Secure data storage and encryption.