-
Notifications
You must be signed in to change notification settings - Fork 11
call_api Documentation
There are two types of API’s that are available. The first are those that do not require any authentication and are free to use in any non-commercial product without a license but is limited to ten queries per second from any IP address.
The second type of API has both an API key as well as a secret key that is used to access the data that the API services. The maximum limit for a query is 10,000 results. The limit is due to how the underlying search engine (OpenSearch) is implemented.
There are details about each API separately to include which type each one is. This document goes through some of the basic testing API’s that are available for those API’s that require keys and secrets.
Here are two programs, one in Python and one in Perl to help with the execution and accessing the data through the API's:
- Perl API Program: call-api.pl
- Python API Program: call-api.py
For either of these programs to function, they expect a file called ~/.shadowserver.api
to exist and to contain your API key and secret. As an example:
[api]
key = <<API-KEY>>
secret = <<SECRET>>
uri = https://transform.shadowserver.org/api2/
If an error like this occurs, it means that the query is going through a lot of data and the timeout in the program should be increased:
$ ./call-api.py reports/query '{"report":"united-states", \
"date":"2020-10-27", \
"query":{"city":"ashburn"}, "limit":3}' pretty
API Exception: The read operation timed out
On all the other API documentation pages, all examples will be used using these programs and not curl
. Curl is only used on this page as an example of an alternative way of accessing the API's.
The API requires that the client send their apikey as well as a hash based message authentication code (HMAC) of the request data created with a secret given to each client. Recalculating and comparing the hash allows the server to authenticate the user and to ensure that the request has not been tampered with.
- All API URLs listed are relative to https://transform.shadowserver.org/api2/.
- For example, the /test/ping API call is reachable at https://transform.shadowserver.org/api2/test/ping.
The API is mostly RESTful with the following stipulations:
- API calls must be made with HTTP POST.
- All requests are JSON objects.
- Each request requires an API key and HMAC header.
- Any non-200 HTTP response is an error. Error details will be included in the response object.
Here is an example call using curl:
$ echo -n '{ "apikey": "0123456789" }' > req
$ hmac=`openssl sha256 -hmac 'secret' -hex < req | awk '{print $2}'`
$ curl -s -X POST -H HMAC2:$hmac --data-binary @req https://transform.shadowserver.org/api2/test/ping
{ "pong": "2014-08-12 23:14:20" }
And an example using the call-api program:
$ ./call-api.py test/ping {} pretty
{
"pong": "2020-10-28 21:38:49"
}
Note that in the curl example above, for each query you will need to regenerate the HMAC code. Al the curl
examples have been made to look pretty when they will actually be transferred via a single line of JSON. Only because there is a pretty mode in the call-api code is it auto formatted to be human readable.
Check your connection to the API server.
Fields:
apikey : string : your api key
Response:
pong : string : current timestamp in UTC
Example:
$ ./call-api.py test/ping {} pretty
{
"pong": "2020-10-28 21:38:49"
}
Returns details about your apikey.
Fields:
apikey : string : your api key
Response:
user : string : user name
label : string : key label
domain : string : request source domain, IP, or CIDR
access : list : list of access group names
status : string : key status
query_count : int : current query count
query_limit : int : maximum number of queries per month
expiration : string : expiration date (YYYY-MM-DD [HH:MM:SS] in UTC)`
Example:
$ ./call-api.py key/info {} pretty
[
{
"apikey": "<<API-KEY>>",
"query_limit": "0",
"label": "The Shadowserver Foundation",
"user": "[email protected]",
"access": [
"reports"
],
"status": "active",
"query_count": "0"
}
]
Each query argument is combined with AND by default.
This will return results that match both asn:64512
and geo:US
:
{ "query": { "asn": 64512, "geo": "US" } }
Example:
$ ./call-api.py reports/query '{"query":{"asn":64512,"geo":"US","date":"2023-02-14"},"limit":1}' pretty
[
{
"timestamp": "2023-02-14 01:41:51Z",
"ip": "192.168.1.1",
"protocol": "tcp",
"port": "443",
"asn": "64512",
"geo": "US",
"type": "scan",
"infection": "ssl",
"tag": [
"http-favicon"
]
}
]
The pipe (|) operator is used in place of OR. This will return results that match type:sinkhole
or type:honeypot
:
{ "query": { "type": [ "|sinkhole", "|honeypot" ] } }
Example:
$ ./call-api.py reports/query '{"query":{"geo":"US", "type":["|sinkhole","|honeypot"],"date":"2023-02-14"},"limit":1}' pretty
[
{
"timestamp": "2023-02-14 00:02:24Z"
"ip": "192.168.1.2",
"protocol": "tcp",
"port": "1579",
"asn": "64512",
"geo": "US",
"type": "honeypot",
"infection": "masterblaster",
"tag": [
"masterblaster"
]
}
]
The exclamation (!) operator is used in place of NOT. This will return results that match asn:64512
and not geo:US
:
{ "query": { "asn": 64512, "geo": "!US" } }
The asterix (*) operator can match zero or more characters, including an empty one.
This would match dhcp
or dhcpd
or dhcpdiscover
:
{ "query": { "tag": "dhcp*" } }
Example:
$ ./call-api.py reports/query '{"query":{"geo":"US", "tag":"dhcp*","date":"2023-02-14"},"limit":1}' pretty
[
{
"timestamp": "2023-02-14 01:47:31Z",
"ip": "192.168.1.3",
"protocol": "udp",
"asn": "64512",
"geo": "US",
"type": "honeypot",
"infection": "ddos-amplification",
"tag": [
"dhcpdiscover"
]
}
]
The question mark (?) operator matches any single character.
This would match smtp
or snmp
:
{ "query": { "tag": "s??p" } }
Example:
$ ./call-api.py reports/query '{"query":{"geo":"US", "tag":"s??p","date":"2023-02-14"},"limit":1}' pretty
[
{
"timestamp": "2023-02-14 00:14:17Z",
"ip": "192.168.1.4",
"protocol": "tcp",
"port": "25",
"asn": "64512",
"geo": "US",
"type": "scan",
"infection": "smtp",
"tag": [
"smtp"
]
}
]
Only fields specifically noted in the API documentation support regular expressions.
A regular expression is bracketed between percent (%) characters:
{ "query": { "tag": "%(snmp|smtp)%" } }
The regular expression must match the entire string.
The following operators are reserved and need to be escaped with a preceding backslash (\):
. ? + * | { } [ ] ( ) " \
- The period (.) operator matches any character.
- The question mark (?) operator matches any single character.
- The plus (+) operator matches the preceding character one or more times.
- The asterix (*) operator matches the preceding character zero or more times.
- The curly brackets ({}) define the minimum and maximum time the preceding character can repeat.
- The pipe (|) operator will match the longest pattern on either the left side OR the right side.
- The parenthesis ( ... ) form a group to treat part of an expression as a single character.
- The brackets [ ... ] define a character set. Inside brackets the - indicates a range unless the - is the first character or escaped. A ^ character in the bracket negates the character or range.
Most of the API's have a help feature that will list out all the possible fields that are available to use in a query for that API. Eventually detailed descriptions will be added to the help over time.
Example:
$ ./call-api.py reports/query '{ "help":true }' pretty
[
"agent",
"application",
"asn",
"asn_name",
"banner",
"city",
"county_fips",
"county_name",
...
"source_url",
"tag",
"text",
"timestamp",
"tld",
"type",
"version"
]