API
Info
Ostorlab added support for Universal Binary JSON encoding. UBJSON provides several performance benefits and adds support for binary data types. For more information about the format and available libraries, check out the following link UBJSON Spec. Support for JSON is still available and either can be specified using the content type header.
Overview
Ostorlab provides a GraphQL API to perform all tasks, from creating scan, access scans progress to listing vulnerabilities.
GraphQL offers several benefits, like performance, reduced number of requests and removes the need for API versioning.
The next section will describe how to use the API, how to experiment and test it.
If you are not familiar with GraphQL, we recommend this tutorial to get familiar with the technology and syntax.
Access
Sandbox
You can use the GraphiQL web application to experiment with the API. GrapiQL is accessible at https://api.ostorlab.co/apis/graphql. The API is accessible to authenticated users only. Make sure you are authenticated at https://api.ostorlab.co/portal/login/ .
Scripts
Typical usage of the API is for automation around deployment pipelines or automating the creation and monitoring of a large number of scans.
For the authentication process, you have two options:
- Token based authentication
- API Key authentication
Token based authentication
The token can be retrieved from
https://api.ostorlab.co/apis/token/
by submitting the username and password. A token linked to the user will be
created. The token is then set in an Authorization header with the value Token {value}
to authenticate subsequent
requests to https://api.ostorlab.co/apis/graphql_token
.
import requests
import json
query = '''
query {
scans {
scans {
id
title
progress
}
}
}
'''
# Retrieve authentication token.
request = requests.post(url='https://api.ostorlab.co/apis/token/',
json={"username":"user1","password":"xxxxxx"})
json_data = json.loads(request.text)
if "token" in json_data:
token = json_data["token"]
# Set token in Authorization header.
headers = {"Authorization": f"Token {token}"}
# Post query request.
request = requests.post(url='https://api.ostorlab.co/apis/graphql_token/',
json={"query": query},
headers=headers)
print(request.json())
TOKEN_RESPONSE=$(curl -X POST https://api.ostorlab.co/apis/token/ --header "Content-Type: application/json" --data '{"username": "user1", "password":"xxxxxx"}')
TOKEN=$(echo $TOKEN_RESPONSE | jq '.token' | tr -d '"')
curl -v -X POST https://api.ostorlab.co/apis/graphql_token \
--header 'Content-Type: application/json' \
--header "Authorization: Token $TOKEN" \
--data '{"query": "query {scans { scans { id title progress }}}"}'
API Key authentication
The API key can be retrieved from your dashboard https://report.ostorlab.co
. You need to click on Library
then API keys
menu.
Click the new button to generate a new key and copy the api key (You can add a name and an expiry date to your key), do not forget to click the save button to save your key.
The API key is used as the value of the header's key the key X-Api-Key
to authenticate subsequent
requests to https://api.ostorlab.co/apis/graphql_token
.
import requests
query = '''
query {
scans {
scans {
id
title
progress
}
}
}
'''
# Set api key in Authorization header.
api_key = "XXXXXXXXXXX"
headers = {"X-Api-Key": f"{api_key}"}
# Post query request.
request = requests.post(url='https://api.ostorlab.co/apis/graphql_token/',
json={"query": query},
headers=headers)
print(request.json())
curl -v -X POST https://api.ostorlab.co/apis/graphql \
--header 'Content-Type: application/json' \
--header "X-Api-Key: $API_KEY" \
--data '{"query": "query {scans { scans { id title progress }}}"}'
Reference
Ostorlab maintains a self documenting scheme, see documentation explorer at the top right corner in the GrapiQL menu. See also the example section for common queries.
Examples
List Scans
To list all the scans owned by the organisation of the current user:
query {
scans {
scans {
id
title
progress
}
}
}
List Scans by Filter
To list scans for a particular Mobile Application, use the target
argument to specify the application package name or bundle id.
{
scans(page: 1, numberElements: 100, target: "com.ubercab.fleet") {
scans {
id
progress
packageName
assetType
}
}
}
The scans API supports other filters like targetAssetTypes
, riskRatings
, progress
and can be ordered and sorted
using orderBy
and sort
arguments:
{
scans(page: 1, numberElements: 100, orderBy: RiskRating) {
scans {
id
progress
riskRating
packageName
assetType
}
}
}
Scan Details
To retrieve the details of a single scan using its id:
query {
scan(scanId: 26095) {
id
title
assetType
createdTime
riskRating
}
}
Vulnerability Details
To retrieve the list and details of vulnerabilities of a scan:
query {
getScan(scanId: 26095) {
vulnerabilities {
vulnerabilities {
detail {
title
description
recommendation
cvssV3Vector
}
customCvssV3BaseScore
}
}
}
}
Scan Progress
To determine scan current progress stage (scheduled, scanning or done):
query {
scans {
scans{
id
packageName
progress
}
}
}
Create New Scan
To create a scan, files are uploaded as a multipart http request.
mutation newMobileScan($title: String!, $assetType: String!, $application: Upload!, $scanProfile: String!) {
createMobileScan(title: $title, assetType:$assetType, application: $application, scanProfile: $scanProfile) {
scan {
id
}
}
}
An example of an Android scan:
import requests
import json
with open('app.apk', 'br') as application:
query = '''mutation newMobileScan($title: String!, $assetType: String!, $application: Upload!, $scanProfile: String!) {
createMobileScan(title: $title, assetType:$assetType, application: $application, scanProfile: $scanProfile) {
scan {
id
}
}
}
'''
data = {
'operations': json.dumps({'query': query,
'variables': {'title': 'fake_title', 'assetType': 'android', 'application': None,
'scanProfile': 'Fast Scan'}}),
'map': json.dumps({
'0': ['variables.application'],
})
}
resp = requests.post('https://api.ostorlab.co/apis/graphql/', data=data, files={'0': application.read(),}, headers={"Authorization": f"Token {token}"})
curl -v -X POST https://api.ostorlab.co/apis/graphql \
--header 'Accept: application/json' \
--header "X-Api-Key: $API_KEY" \
--form 'operations={"query": "mutation newMobileScan($title: String!, $assetType: String!, $application: Upload!, $scanProfile: String!) {
createMobileScan(title: $title, assetType:$assetType, application: $application, scanProfile: $scanProfile) {scan { id } }}",
"variables": {"title": "My application", "assetType": "android", "application": null, "scanProfile": "Fast Scan"}}' \
--form 'map={"0": ["variables.application"]}' \
--form "0=@/path/to/your/app.apk"
Create a new scan with authentication
Creating a scan with a credentials is a two-step process. First, credentials are added to the credentials store and a credential id is returned, and then a scan creation request is sent specifying the ids of the credentials to use in that scan.
For instance to create a simple login password credential. You can use the following:
mutation newTestCredential {
createTestCredentials(testCredentials: {loginPassword: {login: "login1", password: "password1"}}) {
testCredentials {
__typename
... on LoginPasswordTestCredentials {
id
}
}
}
}
Which will return the ID as the following:
{
"data": {
"createTestCredentials": {
"testCredentials": {
"__typename": "LoginPasswordTestCredentials",
"id": "901"
}
}
}
}
To pass the credential Id, you must add the argument credentialIds with the list of Ids:
mutation newMobileScan($title: String!, $assetType: String!, $application: Upload!, $scanProfile: String!) {
createMobileScan(title: $title, assetType: $assetType, application: $application, scanProfile: $scanProfile, credentialIds: [901]) {
scan {
id
}
}
}