Ain’t nothin’ gonna break my stride
Time to do a STRIDE threat analysis on the system. STRIDE stands for Spoofing, Tampering, Repudiation, Information disclosure, Denial of service and Elevation of privilege. Let’s talk about them one at a time.
First, let’s look at the application infrastructure. We have an Angular frontend, hosted as a Static Web App in Azure, and we have Azure Functions to host our API endpoints. We have one SQL database to handle the Agencies, Users and their relations. Each Agency has a connection string to an agency database, and to start with, all the Agencies share the same database. There’s also a Container app.
Spoofing
Do we authenticate users, how do we make sure the user is who they say they are, how do we handle their credentials etc.
We use external Identity Providers (Microsoft and Google) to handle our login, using OAuth 2. This means we do not store user credentials. We only store the identifier and the e-mail address. We verify that the token is signed by the provider.
Only the Angular App and the Azure Functions are export outside Azure, and the Angular App contains no sensitive information whatsoever. The OAuth token is the weak link, but at least we use Https, and the token expires after a short while, making it harder to spoof.
Tampering
Our architecture does not include any mechanism to secure against tampering, and that is by choice. We do however always server-side validate, the client cannot be trusted. Having your token, you could call the API with made up values, but since we validate both values and permissions server-side, you can’t really do anything you cannot do in the UI.
Going back to our Stressors (part 1, part 2), there are a few that might change the need of implementing some kind of security.
Repudiation
We do not have any information about who changed something, except in the code base where we use Git. We will probably have to implement some kind of audit log in the future.
Information Disclosure
All our API endpoints require a valid auth token, and the user permission is validated. We only allow communication using https.
The database, and the Blob Storage is only accessible from within Azure, or from our office IP. Users are the dev-team, the CTO of the client and the identities used by the Azure Functions and the Container Instances.
This may leave one way to access the database/storage “unauthorized”. Maybe someone from the dev team could use their personal account from another Azure resource to access them. However, they could still just access them from the office, so I really don’t see the point.
A better solution would be setting up private networks inside Azure, by doing that we could allow access only from services inside our Resource Group(s). This, however, drives a lot of costs. It is something to take into account when we get closer to a public release.
Access to the UI is granted or revoked by an Agency admin. We will have to trust them to protect their data.
Denial of Service
Our architecture doesn’t really protect us against targeted attacks right now. The Static Web App handles load really well, since it only serves static files and is globally distributed. The API uses Azure Functions that scale really well, but could drive cost. We can easily activate geo-redundancy for our Azure Function, but will consider some kind of active-active access across regions as we scale.
The main denial of service concern is the limit on number of reserved vCores, but an improvement suggested here will solve that problem.
Elevation of Privilege
Since we validate the user using the auth token, and check permissions against the database, there are two possible ways of changing your access level. Either gain access to a valid token for a user with more privileges, or change the content of the database. Since the database is guarded by a firewall, and with strict access control (no password that can leak), I’d say the token is our weak spot.
So, identify a user with the privileges you need, hack them to access their token, and you’re good to go.
As for now, we do not handle anything sensitive. If (when) we do, one way to mitigate this risk is to ask the user to authenticate again when trying to access or edit sensitive information.