# Dev Training ### Access Control ## What is it? ### Access Control (Authorization) * Authorization ≠ Authentication * Authentication (Authn) * Prove that the user is who they say they are * Authorization (Authz) * Determine whether a user is allowed to perform a specific action or access specific data Notes: Let's start by examining some often-confused terms here. Authorization is not authentication! Authentication is when you make a user prove their identity in some way. Authorization is when you determine whether a user identity is allowed to access data or perform actions. ### Confusion ```csharp [Authorize] public class HomeController { public ActionResult UserDetails(int id) { ... } } ``` Notes: It is easy to understand this confusion when you see examples like this. Here, the 'Authorize' attribute on the Home controller means that any authenticated user can access it. While this is technically a form of authorization, it is not what the term usually refers to. ### Common scenario
Authentication is enforced but not authorization
Notes: As a result of this, many applications fail to properly restrict access for authenticated users, and rely on their user interface or data/implementation obscurity to protect sensitive data and functions. ## IDOR ### What is IDOR? * Insecure Direct Object Reference * Direct reference to a resource with limited/no access control checks * One of the most common AC vulnerabilities Notes: Insecure Direct Object Reference (or IDOR) is an extremely common type of vulnerability. I mean we find them almost everywhere we look. In short, it involves direct access to a resource via some identifier with limited or no access control checks. ### With running IDs * Resources are identified with running (database) ID * Most common AC issue * Easy to find other valid IDs and extract data ```shell https://api.example.com/userdetails/1337 ``` Notes: A basic example would be something like this. Users are assigned some incremental integer identification number. The upshot of this is that I can easily guess more valid user IDs. However, this is only IDOR if I can access sensitive information about other users this way. ### With complex IDs * Sometimes ad hoc AC is enforced by using *complex* IDs ```shell api.example.com/userdetails/2eb96434-6c94-11eb-9439-0242ac ``` * Later that week ```shell api.example.com/posts/ ``` ```json { ... "author": "2eb96434-6c94-11eb-9439-0242ac", ... } ``` Notes: But what if we use something unpredictable like UUID? Well, sure, that does seem to do the trick, until you realize that entity identifiers are generally not considered sensitive information and tend to leak. The most important thing is to enforce proper authorization. ## Mass assignment ### What is it? * Aka Autobinding, Object injection * HTTP request parameters bound to native objects * Binding can be abused to set value of fields that should not be editable Notes: Mass assignment goes by many names, often depending on the specific framework. It has to do with the way frameworks tend to map objects passed via requests to data entities by default. If not used carefully, this can allow attackers to modify unexpected fields with various consequences. ## Example ### Model ```csharp public class UserModel { public string Email { get; set; } public string Name { get; set; } public bool IsAdmin { get; set; } } ``` Notes: Let's say we have a very simple .NET user model entity thing with a very interesting field called isAdmin. ### Endpoint ```csharp [HttpPut] public IActionResult Update(UserModel model) { // Maps UserModel to a database model and saves it UpdateUser(model); return Ok(); } ``` Notes: Now let's say we have this perfectly reasonable-looking controller function for updating a user entity. ### Expected request ```http PUT /Users/Update HTTP/1.1 Content-Type: application/json Content-Length: 31 {"name": "Innocent Non-hacker"} ``` Notes: And here we have a perfectly reasonable-looking request to the application's web server. This is all perfectly reasonable and nothing can go wrong, right? Right?? ### Abusing binding ```http PUT /Users/Update HTTP/1.1 Content-Type: application/json Content-Length: 38 {"name": "New Owner", "isadmin": true} ``` Notes: But what happens when I do this? I am now become admin. ### Mitigation * Depends on language and framework * In general * Mark fields as read-only and validate * Use a stripped model for binding * Manually bind fields to db object Notes: How best to mitigate this issue depends heavily on your tech stack. Consult the documentation of your data modeling framework for the recommended strategy. Generally, you can mark such sensitive fields as 'read-only' when applicable. You can use a stripped version of your actual model entity for this type of action, containing only the fields you want the user to be able to change. You can also manually set relevant fields from the submitted object, rather than passing the entire object, to avoid this issue. ## Impact ### Only read * Sensitive data exposure Notes: Unauthorized read access is just a fancy way of saying data leak. Data leaks can be extremely serious. They can incur hefty fines and irreparable damage to a company's reputation, especially in the case of sensitive personally identifiable information (or PII). Not to mention the damage to the actual people who's personal information it is. ### Read/write * Loss of data integrity * Account takeovers * System takeover Notes: With write access, things become even more serious. That can lead to anything from loss of data integrity at best to full system takeover at worst. ## General access control strategies ### Solved problem * The idea is not complicated * But the execution can be (and usually is) * Doesn't scale well * Strategies exist to help with scaling Notes: Great news! This problem is basically solved. The idea is not complicated at all. Basically every piece of data and every action requires some permission which can be granted on a user-by-user basis. Implementing this idea securely tends to be a nightmare and it scales awfully with the application. Thankfully, abstraction strategies exist to help with this. ### Role-based Access Control * Very common, built into many frameworks * Users are assigned roles that determine access * Does not cover all use cases * User A can see details for self but not user B Notes: Role-based access control (or RBAC if you're really into Microsoft) is a very common approach, where you assign roles - basically pre-grouped permissions - to users based on their intended scopes of operation within a system. This is a great way to standardize access control for different groups of users based on their actual roles in the system. However, that is not enough by itself, as it does not cover user-specific cases. I.e. User A cannot view details of User B. ### Attribute-based Access Control * More general rules * Can, e.g., handle the case with users A and B * Greater overhead * Relatively scalable Notes: Attribute-based access control (or ABAC) is another common approach that complements RBAC well. It allows developers to write and assign access control logic to data and actions. For example, a 'view user details' action might have the logic 'if requested user id matches requester id or requester is admin, allow access'. This requires somewhat more overhead, but is extremely flexible and relatively scalable. ### In conclusion * Many other strategies exist that are suitable for different use cases * Important to have good documentation * Simple and clear guidelines Notes: The right choice for you is probably some combination of strategies. Make sure to follow recommended guidelines for your tech stack, follow the documentation well, and document your own access control system to ensure consistency in development and proper customer configuration. ### Frameworks * [Casbin](https://casbin.org), a popular authorization framework that supports multiple strategies * [Open Policy Agent](https://www.openpolicyagent.org/), a scalable general purpose authorization framework Notes: In case you are not using a framework that comes with rich authorization features, there are many different authorization frameworks which you can use to manage your authorization strategy. Here are just two examples. ## Rules of thumb ### Make access control a part of the design process Notes: Again, bring security to the table from day 1. It may be a difficult and expensive problem to address, but it will only be more difficult and expensive tomorrow. ### Don't rely on obscurity * Never assume API endpoints are secret * Never assume IDs are secret * Never assume implementation details are secret Notes: 'Security by obscurity is not security' is a very important phrase to remember. API endpoints, IDs, implementation details (e.g. source code), can all become comromised in a variety of ways and you should assume that they are already compromised. If the security of your system relies on any of those remaining secret, it does not have good security. ### Simple layered design * Web layer * Accepts HTTP requests * Only interacts with service layer * Service layer * Access control enforced * Interacts with service and DB layer * Database layer * Unrestricted access to data Notes: Layers are good. They are a way of separating concerns in complex applications, which helps to avoid many design pitfalls. This is a common example of layered software design which promotes both good access control and ease of development. ## Epilogue ### Further reading * [OWASP Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Access_Control_Cheat_Sheet.html) * [OWASP Mass Assignment Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Mass_Assignment_Cheat_Sheet.html) * [Practical Attacks and Defences for GraphQL APIs](https://medium.com/csg-govtech/closing-the-loop-practical-attacks-and-defences-for-graphql-apis-138cb667aaff) ### Hall of fame * [Childrens' Smartwatch Data Leak](https://www.youtube.com/watch?v=QZ6j9DHw5p4)