Skip to content

Instantly share code, notes, and snippets.

@traut
Last active March 8, 2017 02:21
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save traut/00d566aa0843428e3780e137f0944ed4 to your computer and use it in GitHub Desktop.
Save traut/00d566aa0843428e3780e137f0944ed4 to your computer and use it in GitHub Desktop.
JSON API basics

JSON API basic draft

  • TAXII should facilitate CTI content exchange without content type descrimination.
  • TAXII spec should define the base on which products can innovate, meaning it must be clearly defined and extendable.
  • Try not to reinvent the wheel, havily based on JSON API spec - http://jsonapi.org/
  • Implementation of both server and client should be straightforward.
  • The less ambiguity, the better.
  • Idea is to have one endpoint that lists all TAXII API roots designed to cater to different target groups.
  • Current TAXII 2.0 spec suggests usage of DNS record for advertising this endpoint.

Request:

GET <discovery-url>/

Response:

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json

{
    "data": [
        {
            "id": 1,
            "type": "api-roots",
            "attributes": {
                "title": "Trust Group 1",
                "description": "Description of Trust Group 1 TAXII root",
                "contact_details": "Contact information for Trust Group 1"
            },
			"auth": {
				"required": false
			},
            "links": {
                "self": "https://taxii.example.com/group-1/"
            }
        },
        {
            "id": 2,
            "type": "api-roots",
            "attributes": {
                "title": "Trust Group 2",
                "description": "Description of Trust Group 2 TAXII root",
                "contact_details": "Contact information for Trust Group 2"
            },
			"auth": {
				"required": true,
				"methods": [
					{"type": "http-basic"},
					{"type": "jwt", "href": "https://taxii.example/jwt/tokens"}
				]
			},
            "links": {
                "self": "https://taxii.example.com/group-2/"
            }
        }
    ],
    "links": {
        "self": "https://taxii.example.com/"
    }
}
  • returns a list of existing collections
  • contains collections' details as included objects

Request:

GET <api-root>/

Response:

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json

{
    "data": {
        "type": "api-roots",
        "attributes": {
            "title": "Trust Group 1",
            "description": "Description of Trust Group 1 TAXII root",
            "contact_details": "Contact information for Trust Group 1"
        },
        "relationships": {
            "collections": {
                "data": [
                    {
                        "type": "collections",
                        "id": 10
                    },
                    {
                        "type": "collections",
                        "id": 20
                    }
                ]
            }
        }
    },
    "included": [
        {
            "type": "collections",
            "id": 10,
            "attributes": {
                "name": "High Value Indicator Collection",
                "description": "This data collection is for collecting high value IOCs",
                "media_types": [
                    "application/vnd.oasis.stix+json; version=2.0"
                ]
            },
            "links": {
                "self": "https://taxii.example.com/group-1/10"
            },
            "meta": {
                "can_read": true,
                "can_write": false,
                "objects_count": 923
            }
        },
        {
            "type": "collections",
            "id": 20,
            "attributes": {
                "name": "Indicators from the past 24-hours",
                "description": "This data collection is for collecting current IOCs",
                "media_types": [
                    "application/vnd.oasis.stix+json; version=2.0"
                ]
            },
            "links": {
                "self": "https://taxii.example.com/group-1/20"
            },
            "meta": {
                "can_read": true,
                "can_write": true,
                "objects_count": 10
            }
        }
    ],
    "links": {
        "self": "https://taxii.example.com/group-1/"
    }
}
  • returns the details about a collection
  • server MAY include meta.objects_count in the response. It is a calculated field.
  • server MAY include meta.count in an reference object. It is a calculated field.

Request:

GET <api-root>/<collection-id>

Response:

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json

{
    "meta": {
        "can_read": true,
        "can_write": true,
        "objects_count": 10
    },
    "data": {
        "type": "collections",
        "attributes": {
            "name": "Indicators from the past 24-hours",
            "description": "This data collection is for collecting current IOCs",
            "contact_details": "Contact information for this collection in Trust Group 1",
            "media_types": [
                "application/vnd.oasis.stix+json; version=2.0"
            ]
        }
    },
    "links": {
        "self": "https://taxii.example.com/group-1/",
        "objects": {
            "href": "https://taxii.example.com/group-1/20/objects",
            "meta": {
                "count": 10
            }
        }
    }
}
  • returns a list of objects

Request:

GET <api-root>/<collection-id>/objects

Response:

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json

{
    "links": {
        "self": "https://taxii.example.com/group-1/20/objects"
    },
    "data": [
        {
            "type": "objects",
            "id": "1",
            "attributes": {
                "media_type": "application/vnd.oasis.stix+json; version=2.0"
            },
            "links": {
                "self": "https://taxii.example.com/group-1/20/objects/1",
                "data": "https://taxii.example.com/group-1/20/objects/1/data"
            }
        },
        {
            "type": "objects",
            "id": "2",
            "attributes": {
                "media_type": "application/pdf"
            },
            "links": {
                "self": "https://taxii.example.com/group-1/20/objects/2",
                "data": "https://taxii.example.com/group-1/20/objects/2/data"
            }
        }
    ]
}
  • returns object details, including list of versions (pagination for it?)
  • version link points to another ordinary object
  • when new version of the object comes in (new version is pushed in place of an object with specific ID), object is replaced in a collection and old version is added to versions list of that object.
  • may contain collections info as included referenced objects

Request:

GET <api-root>/<collection-id>/objects/1

Response:

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json

{
    "links": {
        "self": "https://taxii.example.com/group-1/20/objects/1"
    },
    "data": {
        "type": "objects",
        "id": "1",
        "attributes": {
            "media_type": "application/vnd.oasis.stix+json; version=2.0",
            "created_at": "2017-02-25T10:10:10.000111"
        },
        "links": {
            "self": "https://taxii.example.com/group-1/20/objects/1",
            "data": "https://taxii.example.com/group-1/20/objects/1/data"
        },
        "meta": {
            "version": "2017-01-23T11:11:21.854236"
        },
        "relationships": {
            "versions": {
                "data": [
                    {
                        "type": "objects",
                        "id": 19,
                        "meta": {
                            "version": "2017-02-20T18:12:22.854236"
                        },
                        "links": {
                            "self": "https://taxii.example.com/group-1/20/objects/19",
                            "data": "https://taxii.example.com/group-1/20/objects/19/data"
                        }
                    },
                    {
                        "type": "objects",
                        "id": 30,
                        "meta": {
                            "version": "2017-01-21T18:12:22.854236"
                        },
                        "links": {
                            "self": "https://taxii.example.com/group-1/20/objects/30",
                            "data": "https://taxii.example.com/group-1/20/objects/30/data"
                        }
                    }
                ]
            },
            "collections": {
                "data": [
                    {
                        "type": "collections",
                        "id": 10
                    },
                    {
                        "type": "collections",
                        "id": 20
                    }
                ]
            }
        }
    }
}
  • serves object body as a blob with some content type

Request:

GET <api-root>/<collection-id>/objects/2/data

Reponse:

HTTP/1.1 200 OK
Content-Type: application/pdf

... binary data ...
  • JSON-API spec description
  • all endpoints that return a list of entities support pagination
  • this spec does not define how pagination should be implemented, it is up to a server
  • if pagination is requested by client or enforced by server, response MUST contains:
    • links.next link that points to next page
    • meta.page object with page details
  • server MAY include meta.page.total counter in the response

Request:

GET <api-root>/<collection-id>/objects?page[limit]=2

Response:

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json

{
    "links": {
        "self": "https://taxii.example.com/group-1/20/objects?page[limit]=2",
        "next": "https://taxii.example.com/group-1/20/objects?page[cursor]=U2VydmVyIGluZm8gcGFnZSAx"
    },
    "meta": {
        "page": {
            "offset": 10,
            "limit": 2,
            "total": 35
        }
    },
    "data": [
        {
            "type": "objects",
            "id": "1",
            "attributes": {
                "media_type": "application/vnd.oasis.stix+json; version=2.0"
            },
            "links": {
                "self": "https://taxii.example.com/group-1/20/objects/1",
                "data": "https://taxii.example.com/group-1/20/objects/1/data"
            }
        },
        {
            "type": "objects",
            "id": "2",
            "attributes": {
                "media_type": "application/pdf"
            },
            "links": {
                "self": "https://taxii.example.com/group-1/20/objects/2",
                "data": "https://taxii.example.com/group-1/20/objects/2/data"
            }
        }
    ]
}
  • Object's media_type value must be a string and a proper MIME type
  • Allows low and high granularity. Examples:
    • application/pdf
    • application/vnd.oasis.stix+json; version=2.0
    • application/vnd.oasis.stix+json; version=2.0; subtype=indicator
    • application/vnd.oasis.stix+json; version=2.0; subtype=ttp
    • application/vnd.oasis.stix+xml; version=1.1.1
    • application/json; producer=eclecticiq
  • all endpoints that return a list of entities support filtering (all fiels or predefined set?)
  • Filtering parameter is defined as filter[<field_name>]=<value>.
    • The condition for each filter value MUST be EQUALS unless it is prefixed with:
      • > (U+003E GREATER-THAN SIGN, ">"), in which case condition MUST be GREATER THAN.
      • < (U+003C LESS-THAN SIGN, "<"), in which case condition MUST be LESS THAN.
      • >= (U+003E GREATER-THAN SIGN, ">" and U+003D EQUALS-SIGN, “=”), in which case condition MUST be GREATER THAN OR EQUALS.
      • <= (U+003C LESS-THAN SIGN, ">" and U+003D EQUALS-SIGN, “=”), in which case condition MUST be LESS THAN OR EQUALS.
    • Match MAY contain one value or multiple comma-separated values. If parameter contains multiple comma-separated (U+002C COMMA, “,”) values, these conditions MUST be joined with OR logical operator.
    • One of more filters MAY be specified. If more than one filters specified, they are joined with AND logical operator.
  • if filtering is requested by client, response MUST contain:
    • meta.filters list with all specified filters

Request:

GET <api-root>/<collection-id>/objects?filter[created_at]=<=2012-10-10&filter[media_type]=application%2Fvnd.oasis.stix%2Bjson%3B+version%3D2.0

Response:

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json

{
    "links": {
        "self": "https://taxii.example.com/group-1/20/objects/?filter[created_at]=<=2012-10-10&filter[media_type]=application%2Fvnd.oasis.stix%2Bjson%3B+version%3D2.0"
    },
    "meta": {
        "filters": [
            {"field": "created_at", "value": "<=2012-10-10"},
            {"field": "media_type", "value": "application/vnd.oasis.stix+json; version=2.0"}
        ]
    },
    "data": [
        {
            "type": "objects",
            "id": "1",
            "attributes": {
                "media_type": "application/vnd.oasis.stix+json; version=2.0",
                "created_at": "2017-02-25T10:10:10.000111"
            },
            "links": {
                "self": "https://taxii.example.com/group-1/20/objects/1",
                "data": "https://taxii.example.com/group-1/20/objects/1/data"
            }
        },
        {
            "type": "objects",
            "id": "3",
            "attributes": {
                "media_type": "application/vnd.oasis.stix+json; version=2.0",
                "created_at": "2017-02-21T11:11:11.000111"
            },
            "links": {
                "self": "https://taxii.example.com/group-1/20/objects/3",
                "data": "https://taxii.example.com/group-1/20/objects/3/data"
            }
        }
    ]
}
  • API root attributes are:
    • title
    • description
    • contact_details
  • API root object MUST contain auth field
    • auth field's value is an object
    • auth.required MUST be present and should be true or false
    • if auth.required is true, object MUST have methods field with a list
      • auth.methods list contains objects representing supported authentication methods
      • supported authentication method object MUST have type string field and MAY have other fields (see example below)
      • see Authentication for more details.

API root entity:

{
    "type": "api-roots",
    "attributes": {
        "title": "Trust Group 1",
        "description": "Description of Trust Group 1 TAXII root",
        "contact_details": "Contact information for Trust Group 1"
    },
    "auth": {
        "required": true,
        "methods": [
            {"type": "http-basic"},
            {"type": "jwt", "href": "https://taxii.example/jwt/tokens"}
        ]
    }
}
  • meta MAY contain can_read, can_write and objects_count fields.
    • can_write/can_read fields are specific to current client session.
    • objects_count is a calculated field.
  • Collection MUST contain a link to objects endpoint in links field
  • Server MAY return details of the collections that have can_write=false and can_read=false.

Collection entity:

{
    "meta": {
        "can_read": true,
        "can_write": true,
        "objects_count": 10
    },
    "data": {
        "type": "collections",
        "attributes": {
            "name": "Indicators from the past 24-hours",
            "description": "This data collection is for collecting current IOCs",
            "contact_details": "Contact information for this collection in Trust Group 1",
            "media_types": [
                "application/vnd.oasis.stix+json; version=2.0"
            ]
        }
    },
    "links": {
        "self": "https://taxii.example.com/group-1/",
        "objects": {
            "href": "https://taxii.example.com/group-1/20/objects",
            "meta": {
                "count": 10
            }
        }
    }
}
  • Object entity MUST contain a link to specific blob endpoint in links.data
{
	"type": "objects",
	"id": "1",
	"attributes": {
		"media_type": "application/vnd.oasis.stix+json; version=2.0",
		"created_at": "2017-02-25T10:10:10.000111"
	},
	"links": {
		"self": "https://taxii.example.com/group-1/20/objects/1",
		"data": "https://taxii.example.com/group-1/20/objects/1/data"
	}
}
  • Authentication methods MAY differ per API root
  • Supported authentication methods are advertised in API root object's auth field
  • Basic set of authentication methods (server MAY extend this with custom methods):
    • {"type": "http-basic"} — HTTP Basic Authentication
    • {"type": "jwt", "href": "JWT-AUTH-ENDPOINT-URL"} — JWT based authentication
  • If server advertises a particular authentication method, it MUST support it.
@jgommers
Copy link

From the limited understanding: perhaps an easy way of showing what authorization is required to fetch a certain collection. So that without TRYING to authorize access, you know if you could. Especially useful in auto-discovery and such. e.g. I would like to see collections (if configured as such) i'm not authorized for. Catalogue vs access.

@traut
Copy link
Author

traut commented Feb 26, 2017

@jgommers excellent point, thanks. I've added a dedicated Authentication block and extended Collection entity a bit, please take a look.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment