Security as Documentation
Every developer knows the importance of good documentation regardless of whether you’re working on your first ‘Hello World’ program or a complex corporate monolith. Effective documentation can make or break the experience you have when interacting with someone else’s codebase. And, if you’re being honest, it’s likely come in handy when dusting off the cobwebs to one of the many projects you sent to live on the island of misfit toys over the years.
In addition to greater visibility, good API documentation increases the efficacy associated with automated security testing. Rather than relying on the spider to “discover” your API, pre-seeding the scanner with your OpenAPI spec takes the guesswork out of the process. It also leads to better test results since the scanner can infer how to communicate with your API based on defined inputs.
Good Code Documents Itself
But what if you haven’t yet added an OpenAPI spec to your project? Don’t allow a lack of documentation to keep you from shipping secure code. OpenAPI is widely adopted, and as such there are a lot of tools available to help you get started. And given how easy it is to auto-generate Swagger Docs, not having documentation is no longer an excuse.
SmartBear has free online editor that can be used immediately to start building a OpenAPI file that will work with StackHawk: https://swagger.io/tools/swagger-editor/
For new projects, the industry recommended approach is to create an OpenAPI spec file and employ OpenAPI code-generators to stub out the endpoints for the desired server frameworks.
For existing projects, you may want to explore framework specific utilities:
Auto-Generating Swagger Docs for Django Projects
Let’s walk through adding the drf-yasg – Yet another Swagger generator to our hawkling-api codebase.
Clone the Repository
git clone https://github.com/kaakaww/hawkling-api.git
pip install drf-yasg
Add drf-yasg as an installed app in settings.py
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'rest_framework', 'drf_yasg', ]
In urls.py import
django.urls and add the following under
from rest_framework import permissions
from rest_framework import permissions #---ADD--- from drf_yasg.views import get_schema_view from drf_yasg import openapi schema_view = get_schema_view( openapi.Info( title="Hawkling API", default_version='v1', description="A minimal API", ), public=True, permission_classes=(permissions.AllowAny,), )
Include the following paths in urls.py
re_path(r'^swagger(?P<format>\\.json|\\.yaml)$', schema_view.without_ui(cache_timeout=0), name='schema-json'), re_path(r'^swagger/$', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'), re_path(r'^redoc/$', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'),
And that’s it! If you visit localhost:8000/swagger/ in your browser you should see existing routes have been documented and any new route you add to the API will be automatically included in the documentation.
Configure and Run HawkScan
We’ll now configure our stackhawk.yml file similarly to how we did in Part 3 of Security Testing Authenticated Routes series. The only difference is we’ll now add a section for the scanner to ingest the newly created OpenAPI specification.
We have a couple options for seeding HawkScan with our OpenAPI spec.
Option 1: Specify the relative path to either the .json or .yaml file in your project directory.
Option 2: Specify the relative path to pull the file from the target host.
Option 3: Define your API inline or directly within the stackhawk.yml file itself. This is very useful for initial testing or limiting the scope of the API you want to test.
For this example we’ll chose the Option 2 and add
app.api: /swagger.json to our config file.
app: applicationId: xxXXXXXX-xXXX-xxXX-XXxX-xXXxxXXXXxXX env: Development host: http://localhost:8000 api: /swagger.json. #<--- Add API Config Here authentication: loggedInIndicator: ".*message.*" loggedOutIndicator: ".*detail.*" usernamePassword: type: JSON loginPath: /login/ usernameField: username passwordField: password scanUsername: admin scanPassword: adminpassword tokenExtraction: type: TOKEN_PATH value: "access" tokenAuthorization: type: HEADER value: Authorization tokenType: Bearer testPath: path: /kaakaww/ success: ".*200.*"
Now run HawkScan as before
docker run --rm -v $(pwd):/hawk:rw -it \ -e API_KEY=hawk.xxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxx \ stackhawk/hawkscan:latest
There is a reason that documentation is stressed so heavily during the development process. It has real tangible value both for humans and machines when interacting with your applications. Additionally, auto-generators like
drf-yasg help to take the heavy lifting out of the processes of creating and maintaining documentation, making it easier to automate critical business processes like security testing. Lastly, utilizing Swagger Docs in your security automation delivers test results with greater visibility and a higher degree of efficacy, ensuring confidence in the posture of your code as it’s pushed to production.