Last active
November 11, 2022 09:13
-
-
Save v1nc/f376000496fd16362b86c0910962284b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
from pathlib import Path | |
import json | |
# list for solutions | |
solutions = [0,0,0,0,0,0,0,0] | |
# iterate over all API files | |
pathlist = Path('openapi-in-the-wild').glob('*.json') | |
for file_path in pathlist: | |
# load API JSON file | |
f = open(str(file_path)) | |
data = json.load(f) | |
# parse results | |
# task 1 | |
# read openapi version | |
if 'openapi' in data and data['openapi'] == '3.1.0': | |
solutions[0]+=1 | |
# task 2 | |
# read openapi version and check if <3 | |
if 'swagger' in data: | |
version = data['swagger'].split('.')[0] | |
# version in 'swagger' should be <3, check anyway | |
try: | |
version = int(version) | |
if version < 3: | |
solutions[1]+=1 | |
except: | |
pass | |
# task 3 | |
# check if length of servers is > 2 | |
if 'servers' in data and len(data['servers']) > 2: | |
solutions[2]+=1 | |
# task 4 | |
if 'paths' in data: | |
found = False | |
# iterate over every path | |
for path in data['paths']: | |
# stop if result was found for this API specification | |
if not found: | |
# iterate over every method of the path | |
for method in data['paths'][path]: | |
# sometimes 'path' is only a string | |
if not found and isinstance(data['paths'][path], dict): | |
# sometimes 'method' value is only a bool | |
if ((isinstance(data['paths'][path][method], dict) | |
or isinstance(data['paths'][path][method], list)) | |
and 'requestBody' in data['paths'][path][method]): | |
# check the content of the request body | |
if 'content' in data['paths'][path][method]['requestBody']: | |
supports_json = False | |
supports_xml = False | |
# check if json + xml is supported for the request | |
for input_type in data['paths'][path][method]['requestBody']['content']: | |
if 'json' in input_type: | |
supports_json = True | |
elif 'xml' in input_type: | |
supports_xml = True | |
if supports_xml and supports_json: | |
solutions[3]+=1 | |
found = True | |
# task 5 + 6 + 7 | |
if 'components' in data and 'securitySchemes' in data['components']: | |
http_found = False | |
api_key_found = False | |
not_best_practice_found = False | |
# check every security scheme | |
for security_scheme in data['components']['securitySchemes']: | |
if 'type' in data['components']['securitySchemes'][security_scheme]: | |
# check if the type of the security scheme is 'http', for task 5 | |
if not http_found and data['components']['securitySchemes'][security_scheme]['type'] == 'http': | |
solutions[4]+=1 | |
# check if the type of the security scheme is 'apiKey', for task 6 | |
elif not api_key_found and data['components']['securitySchemes'][security_scheme]['type'] == 'apiKey': | |
solutions[5]+=1 | |
# if the type is 'apiKey', check if the API key is send with the query (bad practice), for task 7 | |
if not not_best_practice_found and data['components']['securitySchemes'][security_scheme]['in'] == 'query': | |
solutions[6]+=1 | |
# also check if the API key is send with the cookie (not best practice), for task 7 | |
elif not not_best_practice_found and data['components']['securitySchemes'][security_scheme]['in'] == 'cookie': | |
solutions[6]+=1 | |
# task 8 | |
if 'paths' in data: | |
found = False | |
# iterate over every path (again) | |
for path in data['paths']: | |
if not found: | |
# iterate over every method of the path | |
for method in data['paths'][path]: | |
# sometimes 'path' is only a string | |
if not found and isinstance(data['paths'][path], dict): | |
# sometimes 'method' value is only a bool | |
if ((isinstance(data['paths'][path][method], dict) | |
or isinstance(data['paths'][path][method], list))): | |
# check if the top-level authentication schemes are overwritten by the path security | |
# if the 'security' list is empty, authentication is disabled | |
if ('security' in data['paths'][path][method] | |
and len(data['paths'][path][method]['security']) == 0): | |
solutions[7]+=1 | |
found = True | |
# print result | |
print(f'1. How many APIs define OpenAPI 3.1.0? {solutions[0]}') | |
print(f'2. How many APIs define OpenAPI older than 3.0.0? {solutions[1]}') | |
print(f'3. How many APIs define multiple servers? {solutions[2]}') | |
print(f'4. How many APIs do have paths that support both JSON and XML as input in the request? {solutions[3]}') | |
print(f'5. How many APIs support ”HTTP” Authentication? {solutions[4]}') | |
print(f'6. How many APIs support ”API Key” Authentication? {solutions[5]}') | |
print(f'7. How many APIs deviate from the recommended security best current practices regarding API keys? {solutions[6]}') | |
print(f'8. How many APIs do have paths that overwrite the defined top-level authentication scheme(s) and completely disable the authentication? {solutions[7]}') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment