Add api example
Web Security Map API documentation
The Web Security Map frontend is an implementation of the JSON API Backend. This means that it is very easy to create your own front end and to consume the data from an installation.
These are a few simple examples that show you how to create a list of organizations and some finding for each organization.
Overall structure
You need to drill down the following hierarchy: Maps - Map - Organization - Url - Endpoint. On both url and endpoint you will find an (unsorted) list of findings. Each finding has a unique name.
Information is split up into three endpoints:
- Configuration
- Map
- Organization
Iterating through 100 organizations will take a minute or so. By default the latest data is requested, you can also give a ISO date string to get data from previous days.
Data is available under the 'data' directory, for example: https://basisbeveiliging.nl/data
.
There is a lot more data available. A list of all metrics is published here: https://internetcleanup.foundation/project-basisbeveiliging/meetbeleid/
Metrics
An overview of most of the metrics that are published is listed here, which includes the technical names of each metric.
https://internetcleanup.foundation/project-basisbeveiliging/meetbeleid/
Example: setup for all examples:
See: example.py. Requires python 3.9 and the requests library to be installed.
import requests
from typing import List, Dict, Any
WSM_INSTALLATION = "https://basisbeveiliging.nl/data"
Example: get all layers from a country:
def get_layers(country_code: str = "NL") -> List[str]:
config = requests.get(f"{WSM_INSTALLATION}/config/")
return config.json()["country_and_layers"][country_code]["layers"]
Example: get organizations on a layer:
def get_organizations_on_layer(country_code: str = "NL", layer_name: str = "municipality", at_when: str = "0") -> List[Dict[str, Any]]:
map_data = requests.get(f"{WSM_INSTALLATION}/map/{country_code}/{layer_name}/{at_when}/")
return map_data.json()["features"]
Example: get data from a report:
def get_report_data(organization_id: int, country_code: str = "NL", layer_name: str = "municipality", at_when: str = "0") -> Dict[str, Any]:
report_data = requests.get(f"{WSM_INSTALLATION}/report/{country_code}/{layer_name}/{organization_id}/{at_when}/")
return report_data.json()
Example: show all security txt and qualys ratings from Dutch municipalities
This example is based upon all above functions and some filtering.
python3 example.py
# Data is licensed CC-BY-SA 4.0 Internet Cleanup Foundation.
# Geometry (c) Open Street Map contributors, CC-BY-SA 4.0.
# Metrics from Qualys SSL Labs is provided under their license, which requires publication and attribution.
# Location data from Maxmind and Ripe is not allowed for commercial use.
import requests
from typing import List, Dict, Any
WSM_INSTALLATION = "https://basisbeveiliging.nl/data"
def get_layers(country_code: str = "NL") -> List[str]:
config = requests.get(f"{WSM_INSTALLATION}/config/")
return config.json()["country_and_layers"][country_code]["layers"]
def get_organizations_on_layer(country_code: str = "NL", layer_name: str = "municipality", at_when: str = "0") -> List[Dict[str, Any]]:
map_data = requests.get(f"{WSM_INSTALLATION}/map/{country_code}/{layer_name}/{at_when}/")
return map_data.json()["features"]
def get_report_data(organization_id: int, country_code: str = "NL", layer_name: str = "municipality", at_when: str = "0") -> Dict[str, Any]:
report_data = requests.get(f"{WSM_INSTALLATION}/report/{country_code}/{layer_name}/{organization_id}/{at_when}/")
return report_data.json()
def show_filtered_metrics(report_data: Dict[str, Any], metrics: List[str] = None) -> None:
# Metrics contain the following stuff, which might be useful:
# scan, comply or explain, evidence, impact and more.
for url in report_data["calculation"]["organization"]["urls"]:
for url_rating in url["ratings"]:
# note that this will change in a future version to access metrics without iteration
if url_rating["type"] in metrics:
print(f"url: {url['url']}: {url_rating['type']}: {impact(url_rating)} {explained(url_rating)}")
for endpoint in url["endpoints"]:
for ep_rating in endpoint["ratings"]:
if ep_rating["type"] in metrics:
print(f"url: {url['url']}: IPv{endpoint['ip_version']}/{endpoint['protocol']}:{endpoint['port']} {ep_rating['type']}: {impact(ep_rating)} {explained(ep_rating)}")
def get_metrics(country_code: str = "NL", layer_name: str = "municipality", metrics: List[str] = None, at_when: str = "0") -> None:
organizations = get_organizations_on_layer(country_code, layer_name, at_when)
for organization in organizations:
organization_id = organization["properties"]["organization_id"]
print(f'Results for organization {organization["properties"]["organization_name"]}:')
report_data = get_report_data(organization_id, country_code, layer_name, at_when)
show_filtered_metrics(report_data, metrics)
print("")
def impact(metric: dict) -> str:
severities = ["high", "medium", "low", "not_applicable", "not_testable", "error_in_test", "ok"]
return next((severity for severity in severities if metric[severity]), "")
def explained(metric: dict) -> str:
return "(explained)" if metric['is_explained'] else ""
if __name__ == '__main__':
get_metrics("NL", "municipality", ["tls_qualys_encryption_quality", "internet_nl_wsm_web_appsecpriv_securitytxt"])