At AppNexus, we’re proud of the innovative solutions we come up with to tackle our complex problems. But sometimes the most important solutions aren’t the bleeding edge ones that the engineer next to me thinks of between his oatmeal and coffee in the morning. Sometimes they are the age-old, time-tested solutions we’ve all read about in class and subsequently forgot because they’re not convenient. It’s one of those solutions– specifically the principle of least privilege– that I want to highlight today.
Earlier this week we released a new feature called “AppNexus Apps.” It’s a really exciting new feature that allows third parties to build tools that can be displayed and used within the AppNexus Console — the web application that serves as the front end of our platform. I’ll save most of the fun details for someone who worked on the more interesting parts of the project, but at a high level apps work by making calls to our API on behalf of Console users, just like the AppNexus Console itself.
Almost.
When users authenticate to our API, they get back a token that can either be stored in a cookie or passed in the header of subsequent requests so we know who they are and what they are allowed to do. When a user logs into Console, Console keeps track of this token and uses it to make calls for the user. That gives the AppNexus Console a lot of power; any call a user can make can be made for the user by Console. That makes sense for our own web application. If a client trusts our API, they may as well trust Console too.
An app sits inside the AppNexus Console and makes calls to the API just like Console does. But should apps — which can be made by random third parties — be allowed to make any call to any service for the user like the AppNexus Console can? Each app goes in a specific place (or a few specific places) in Console, usually to change the way a user does a particular task. That should only require a handful of different API services, so it seems unnecessary and potentially harmful to let the app make calls to any and all of the services our API provides. We want to restrict the privileges of the apps (or any system component, for that matter) to those it needs to perform its duties. This idea, known as the “principle of least privilege,” is one of the most fundamental principles of security. I know, this isn’t exactly ground breaking stuff. In fact, many of you may be rolling your eyes, yawning, or muttering “Duh,” under your breath. But I bring it up because it is so fundamental; it’s so well known that I shouldn’t have to write about it, but it’s so important that I will anyway.
So what did we do? We decided to give apps their own set of permissions — each app has a list of what services and service methods it can access, and the users can see which ones they are when they install the app. Then instead of having apps pass along a user’s token, we force the app to authenticate itself. They pass us an app ID, a user ID, and proof that the call is coming from the app whose ID is passed. Once we verify that the call really is coming from the app and that the given user has that app installed, we give the app its own token. When we get a call using that token, we can then check the permissions not only of the user, but of the app as well when deciding whether or not to allow the call.
The result is a system where each app can get its work done, but can’t muck around with anything else. An app that changes the way a user sets up targeting on an advertising campaign can’t also steal the full list of the user’s advertisers. A dashboard app that shows users their data in a unique way can’t accidentally overwrite that data. This gives the platform the best combination of safety and usefulness, which in turn gives our clients the best combination of peace of mind and efficiency.