<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Warrant</title>
    <description>The latest articles on Forem by Warrant (@warrant).</description>
    <link>https://forem.com/warrant</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F4414%2Fc56eaf98-b7a2-447b-afc6-7420febdbd27.png</url>
      <title>Forem: Warrant</title>
      <link>https://forem.com/warrant</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/warrant"/>
    <language>en</language>
    <item>
      <title>Why Google Zanzibar Shines at Building Authorization</title>
      <dc:creator>Karan Kajla</dc:creator>
      <pubDate>Wed, 28 Jun 2023 22:45:00 +0000</pubDate>
      <link>https://forem.com/warrant/why-google-zanzibar-shines-at-building-authorization-47do</link>
      <guid>https://forem.com/warrant/why-google-zanzibar-shines-at-building-authorization-47do</guid>
      <description>&lt;p&gt;Over the last couple years, authorization (AKA “authz”) has become a hot topic of debate. Proponents of various authz frameworks, libraries, and philosophies have voiced their opinions on how it should be implemented, jockeying for position to become &lt;strong&gt;the&lt;/strong&gt; de facto way to implement authz. Among the contestants in this debate, &lt;a href="https://storage.googleapis.com/pub-tools-public-publication-data/pdf/10683a8987dbf0c6d4edcafb9b4f05cc9de5974a.pdf"&gt;Google’s Zanzibar&lt;/a&gt; has recently emerged as a popular way of not only modeling and enforcing authorization for modern, fine grained use cases, but also of scaling to meet the requirements of today’s large-scale, cloud-native applications.&lt;/p&gt;

&lt;p&gt;When we started Warrant in 2021, we set out to build developer-friendly authorization infrastructure that all engineering teams could use. We knew that Warrant would be a core piece of infrastructure for our customers, so our authz service had to be (1) &lt;strong&gt;generic&lt;/strong&gt; enough to model all of their use-cases and (2) &lt;strong&gt;scalable&lt;/strong&gt; enough to support access checks across their authz models globally and with low latency. After reading the seminal &lt;a href="https://storage.googleapis.com/pub-tools-public-publication-data/pdf/10683a8987dbf0c6d4edcafb9b4f05cc9de5974a.pdf"&gt;Zanzibar paper&lt;/a&gt;, we decided to build Warrant’s core authorization engine based on many of the concepts described in the paper (e.g. tuples, namespaces, zookies, etc. – more on these concepts later). We believed that Zanzibar had zeroed in on a set of fundamental concepts and patterns that would help us build a generic solution to the authorization challenges of any application.&lt;/p&gt;

&lt;p&gt;We launched Warrant &lt;a href="https://news.ycombinator.com/item?id=32251305"&gt;to much discussion and debate&lt;/a&gt; and have tackled a wide variety of authorization challenges since then, helping many companies build production-ready authz. In this post, I’ll talk about why we believe Zanzibar is a great foundation for implementing authorization, discuss some areas where it falls short, and share how we’ve addressed those shortcomings with enhancements of our own.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Flexible, Uniform Data Model for Authorization
&lt;/h2&gt;

&lt;p&gt;Zanzibar provides an intuitive and (more importantly) uniform data model for representing authorization. Its authorization paradigm, known as relationship based access control (ReBAC), is based on the principle that all resources in an application are related to each other via directed relationships (e.g. &lt;code&gt;[user:123] is [owner] of [report:abc]&lt;/code&gt;), and the application’s authz rules (i.e. the abilities granted to users of the application) flow from these relationships either explicitly or implicitly. Representing authorization in this way feels intuitive because it’s similar to how most of us already design data models (e.g. relational database schemas) for our own applications, making it easy to understand and reason about authz models in Zanzibar. ReBAC is also extremely flexible, capable of representing any authz model you can throw at it, including other authz paradigms like role based access control (RBAC) and attribute based access control (ABAC).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Zanzibar provides a uniform data model and configuration language for expressing a wide range of access control policies from hundreds of client services at Google[...]”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;–from &lt;strong&gt;Zanzibar: Google’s Consistent, Global Authorization System&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In practice, each relationship between two resources is represented as a “tuple” composed of three parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The &lt;strong&gt;object&lt;/strong&gt; (resource) on which the relationship is being specified.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;relationship&lt;/strong&gt; being specified.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;subject&lt;/strong&gt; (a resource or group of resources) that will possess the specified relationship on the object.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Z5rs34qY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/http://blog.warrant.dev/img/zanzibar-graph.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Z5rs34qY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/http://blog.warrant.dev/img/zanzibar-graph.png" alt="Zanzibar Graph" width="800" height="312"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Together, the set of all tuples makes up a big graph of relationships in which the objects and subjects are the nodes, and the relationships between them are the edges. This graph is powerful because it can be traversed in various ways to determine the capabilities of users in an application. For example, a path between a user and a resource might mean that the user has write privileges on the resource. In another scenario, it might mean that the user is not allowed to perform writes on a different resource. To dictate how the graph can be traversed and to assign semantic meaning (for authz) to the relationships it represents, Zanzibar provides us with &lt;em&gt;namespaces&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Authorization Logic Decoupled from Application Logic
&lt;/h2&gt;

&lt;p&gt;Namespaces allow us to assign meaning to the relationships represented by our graph for the purpose of authorization. Each namespace defines the available relationships (e.g. admin, writer, reader) on a type of resource (e.g. report), and optionally, a set of logical rules that specify how each relationship can be inferred from others (e.g. &lt;code&gt;an [editor] of a [report] is also a [viewer] of that report&lt;/code&gt;). They are similar to database schemas in that they allow us to define the structure of an authorization model, but unlike database schemas, namespaces also allow us to express logic on top of that structure. For example, the namespace for a report object type might define three relationships: &lt;code&gt;admin&lt;/code&gt;, &lt;code&gt;editor&lt;/code&gt;, and &lt;code&gt;viewer&lt;/code&gt;. In addition to defining these relationships, the namespace can also specify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A subject can only have the admin relationship on a report explicitly.&lt;/li&gt;
&lt;li&gt;A subject can have the editor relationship on a report explicitly OR implicitly if it has the admin relationship on that report.&lt;/li&gt;
&lt;li&gt;A subject can have the viewer relationship on a report explicitly OR implicitly if it has the editor relationship on that report.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The ability for namespaces to specify logical rules (or policies) like these between relationships makes it possible to separate authorization logic from application logic. This makes application code much simpler. The application only needs to confirm that a user has a particular capability (e.g. editor) before executing a section of code (e.g. persisting a proposed edit on a document).&lt;/p&gt;

&lt;h2&gt;
  
  
  Stateful, Centralized, Query-able Permissions
&lt;/h2&gt;

&lt;p&gt;While modern, policy-driven authz solutions like Open Policy Agent (OPA) offer some of the features and benefits described so far, one thing remains unique to Zanzibar. It’s a &lt;em&gt;stateful&lt;/em&gt;, &lt;em&gt;centralized&lt;/em&gt; service, meaning that all tuples (the relationship graph) and namespaces are pieces of data that are stored and updated centrally. A major benefit of this design is the ability to query the data, not only to check if a particular subject has access to a specific resource, but also to get the list of resources a particular subject has access to. This is extremely useful in practice, for example, to audit a user’s privileges for regulatory compliance or to understand the impact of a change to the authorization model before applying it. In our opinion, having the ability to query permissions like this should be a requirement in any authorizaton system and can only be done in a stateful system with a global view of all authz data. However, as with any system design decision, this approach comes with its trade-offs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Global Scale, Low Latency
&lt;/h2&gt;

&lt;p&gt;Since Zanzibar stores all authorization data centrally, client applications must make requests to it to check permissions, making it a potential performance bottleneck for those applications. To minimize the end-to-end response times of authz queries, Zanzibar is distributed globally (as close to client applications as possible) and utilizes aggressive caching, responding to queries from cache (in single milliseconds) whenever possible. Because access patterns and freshness requirements for authorization data vary from application to application, Zanzibar has the concept of a “zookie” – a global, incrementing version number for each change made to the authorization data. Zookies make caching feasible while still allowing client applications to dictate when they favor correctness over speed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Our Take on Zanzibar
&lt;/h2&gt;

&lt;p&gt;While the concepts and features of Zanzibar are great, Google never built a publicly available implementation because they built Zanzibar to solve their own authorization needs for services like Drive, Docs, YouTube, and more. Fortunately, Warrant implements all of the concepts we’ve discussed so far, many of them with slight variations intended to either improve developer experience or add functionality that we feel Zanzibar lacks.&lt;/p&gt;

&lt;p&gt;In Warrant, &lt;em&gt;tuples&lt;/em&gt; are known as &lt;em&gt;warrants&lt;/em&gt;. A warrant includes the same three major components (object, relationship, and subject) as a tuple but can also include an optional component that we call a &lt;em&gt;policy&lt;/em&gt;. The policy component is a user-defined boolean expression that is evaluated at query-time to determine whether the warrant is available to the query or not. If a warrant matches a query &lt;em&gt;and&lt;/em&gt; its policy evaluates to &lt;code&gt;true&lt;/code&gt;, that warrant is considered during the query. Otherwise, the warrant is ignored.&lt;/p&gt;

&lt;p&gt;Policies can reference dynamic contextual data that is passed in by the query (e.g. &lt;code&gt;[user:123] is an [approver] of [transaction:abc] [if transaction.amount &amp;lt;= 100]&lt;/code&gt;). Having the ability to do this makes Warrant capable of modeling attribute based access control (ABAC) scenarios in which external data (e.g. the transaction amount) is required to make an authorization decision, something Zanzibar’s purely ReBAC approach struggles with. You can learn more about warrants in our &lt;a href="https://docs.warrant.dev/concepts/warrants/"&gt;documentation&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;namespaces : tuples :: object types : warrants
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Namespaces&lt;/em&gt;, as described in Zanzibar, are known as &lt;em&gt;object types&lt;/em&gt; in Warrant. Object types are represented as JSON and conform to a JSON schema specification. Unlike Zanzibar’s namespaces, object types support the ability to restrict the types of objects that can possess each relationship, making it easier for developers to reason about the scope of each object type’s relationships. Warrant also provides various pre-built object types to standardize and simplify the implementation of common authorization use cases like RBAC, feature entitlements, and multi-tenancy within Zanzibar’s ReBAC paradigm. You can learn more about object types and the various built-in models Warrant offers in our &lt;a href="https://docs.warrant.dev/concepts/object-types/"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Looking Forward &amp;amp; Open Source
&lt;/h2&gt;

&lt;p&gt;More than two years after choosing to build Warrant atop Zanzibar’s core principles, we’re extremely happy with our decision. Doing so gave us a solid technical foundation on which to tackle the various complex authorization challenges companies face today. As we continue to encounter new scenarios and use cases, we’ll keep iterating on Warrant to ensure it’s the most capable authorization service. To share what we learn and what we build with the developer community, we recently open-sourced the core &lt;a href="https://github.com/warrant-dev/warrant"&gt;authorization engine&lt;/a&gt; that powers our fully managed authorization platform, &lt;a href="https://warrant.dev/"&gt;Warrant Cloud&lt;/a&gt;. If you’re interested in authorization (or Zanzibar), check it out and give it a star!&lt;/p&gt;

</description>
      <category>authorization</category>
      <category>opensource</category>
      <category>architecture</category>
      <category>cybersecurity</category>
    </item>
    <item>
      <title>Storing Access Policies in Policy Files vs. in a Database</title>
      <dc:creator>Karan Kajla</dc:creator>
      <pubDate>Tue, 19 Apr 2022 15:35:19 +0000</pubDate>
      <link>https://forem.com/warrant/storing-access-policies-in-policy-files-vs-in-a-database-1goh</link>
      <guid>https://forem.com/warrant/storing-access-policies-in-policy-files-vs-in-a-database-1goh</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;When tasked with adding authorization &amp;amp; access control to an application, one of the first decisions many developers make is whether to store their application's access control policies in policy files or in a database. This decision is dictated by the business &amp;amp; operational needs of the application and is often made indirectly when choosing to use a library or implement a custom access control system from scratch. In this post, we'll cover the pros and cons of both approaches and discuss ideal use-cases for each.&lt;/p&gt;

&lt;h2&gt;
  
  
  Storing Access Policies in Policy Files
&lt;/h2&gt;

&lt;p&gt;In the policy file approach, sometimes referred to as &lt;em&gt;policy-as-code&lt;/em&gt;, an application's access policies are represented in a standardized notation and stored in a structured file format (yaml, json, a custom format). The application can then read files of this format and make authorization decisions at runtime based on the defined policies. More modern implementations of this approach (like &lt;a href="https://casbin.org/en/"&gt;Casbin&lt;/a&gt; or &lt;a href="https://www.openpolicyagent.org/"&gt;OPA&lt;/a&gt;) have implemented a custom file format which supports lightweight code blocks that can be executed at runtime to make &lt;em&gt;attribute-based&lt;/em&gt; authorization decisions (ex: user has access until 9PM, user with IP address X.X.X.X has access, etc).&lt;/p&gt;

&lt;h3&gt;
  
  
  Pros
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Simple &amp;amp; Lightweight
&lt;/h4&gt;

&lt;p&gt;The policy file approach is simple &amp;amp; lightweight from the developer's perspective. Many authorization libraries take this approach so they're easy to drop into any application. The developer simply needs to define their application's authorization policies in a file and add the appropriate authorization checks to their code. Then they're off to the races.&lt;/p&gt;

&lt;h4&gt;
  
  
  Fast
&lt;/h4&gt;

&lt;p&gt;Policy files are lightweight, so an application can read these files into memory and make authorization decisions quickly at runtime. No database or network calls are required to perform an authorization check.&lt;/p&gt;

&lt;h4&gt;
  
  
  Easily Version Controlled
&lt;/h4&gt;

&lt;p&gt;Since access policies are stored as files, like the application's source code, they can be checked into a version control system (like Git), making it easy to version updates to access policies as they change over time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cons
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Rigid
&lt;/h4&gt;

&lt;p&gt;One-off cases for certain customers/users are a fact of life when operating a live system. While it's possible to define one-off rules in policy files, this can very quickly grow out of control, making policy files harder to manage. Policy files are better suited for applications whose access model can be defined by a finite set of generalized access policies without many one-off cases.&lt;/p&gt;

&lt;h4&gt;
  
  
  Difficult to Support User-Defined Policies
&lt;/h4&gt;

&lt;p&gt;Many modern applications (Google Docs, Dropbox, Asana, GitHub, etc.) allow users to self-manage access policies on resources they create (ex: &lt;em&gt;&lt;a href="mailto:john.doe@gmail.com"&gt;john.doe@gmail.com&lt;/a&gt; can make edits to my document&lt;/em&gt;). By nature, these types of access policies are dynamic at runtime and difficult to support when storing access policies in files.&lt;/p&gt;

&lt;h4&gt;
  
  
  Policy Updates Require a Developer
&lt;/h4&gt;

&lt;p&gt;With the policy file approach, a developer typically needs to be involved when an application's access policies need to be updated. This is because the policy files are usually maintained using the same process as the application's source code (for simplicity). Additionally, the format &amp;amp; structure of the policy files isn't as accessible to non-technical team members. This can quickly become a drag on engineering teams that don't want to deal with the day-to-day management of an application's access policies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Storing Access Policies in a Database
&lt;/h2&gt;

&lt;p&gt;In the database approach, sometimes referred to as &lt;em&gt;policy-as-data&lt;/em&gt;, the application's access policies for each user, resource, etc. are represented in a standardized format and stored in a database. The application can then query the database at runtime to perform authorization checks or fetch the access policies for a particular user or resource.&lt;/p&gt;

&lt;p&gt;The structure of both the access policies and the underlying database tables storing those access policies is dependent on the type of access model required by the application (RBAC, ABAC, etc). For example, in a previous post we detailed how to structure your database for &lt;a href="https://dev.to/implementing-role-based-access-control"&gt;implementing Role Based Access Control&lt;/a&gt;. More modern approaches, such as &lt;a href="https://research.google/pubs/pub48190/"&gt;Google Zanzibar&lt;/a&gt;, define a way to structure database tables to allow specifying arbitrary rules to enforce fine-grained access control on any resource in an application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pros
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Flexible
&lt;/h4&gt;

&lt;p&gt;Since individual access policies for each user and resource in the application are stored in the database, handling one-off cases is as simple as adding a new row to the policy database.&lt;/p&gt;

&lt;h4&gt;
  
  
  Support for User-Defined Policies
&lt;/h4&gt;

&lt;p&gt;Storing access policies in a database is a natural fit for building applications that allow users to self-manage access policies on resources they created. Granting another user access to a resource is simply a new row in the policy database, and each new policy is immediately enforceable in the application.&lt;/p&gt;

&lt;h4&gt;
  
  
  Accessible to Non-Technical Roles
&lt;/h4&gt;

&lt;p&gt;One of the biggest advantages of storing access policies in a database is that it's easy to build a user interface on top of the data. This allows even non-technical users to easily manage an application's access policies in real time, removing their dependence on engineering teams. This is especially valuable for product managers, customer support, and other non-technical roles that support software products with complex access control models.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cons
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Complicated to Implement &amp;amp; Manage
&lt;/h4&gt;

&lt;p&gt;Effectively storing access policies in a database at scale requires the design, management, and hosting of the underlying policy database. As a result, implementing an access control system that stores access policies in a database is more complicated than storing access policies in files and requires greater effort to maintain over time.&lt;/p&gt;

&lt;h4&gt;
  
  
  Not Performant by Default
&lt;/h4&gt;

&lt;p&gt;Because access policies are stored in a database, performing authorization checks isn't a fast operation by default. Querying the policy database to check if an access policy exists can take orders of magnitude longer than it takes to check against a policy file loaded into memory. This operation can be made fast by pre-fetching access policies or employing a good caching strategy, neither of which is trivial to implement.&lt;/p&gt;

&lt;h4&gt;
  
  
  Not Version Controlled by Default
&lt;/h4&gt;

&lt;p&gt;Access policies stored in a database are not easily version controlled like policies stored in a policy file are, so more work is required to ensure policy updates are rolled out carefully. Version control can be added on top of the policy database, but this isn't trivial to implement either.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Because both approaches to access policy management offer a different set of trade-offs, they both tend to be more useful in some use-cases than in others. For example, the policy file approach is often used for managing access to cloud infrastructure (a heavy focus of frameworks like OPA) because the access model in such use-cases tends to be fairly static, well-defined, and uniform, without many one-off cases. On the other hand, the policy database approach is often used for application access control, particularly in Enterprise/B2B SaaS applications because these applications tend to have complex, dynamic access control models with many one-off cases and customizations requested by each customer. Deciding which approach to take for your use-case involves weighing the trade-offs of both approaches and choosing the approach that offers the greatest benefit to your application and team.&lt;/p&gt;

&lt;h2&gt;
  
  
  Authorization as a Service
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://warrant.dev"&gt;Warrant&lt;/a&gt; is a fully managed authorization service that helps you add access control to your application and manage its access policies over time. Built from the ground up to solve the challenges of building and maintaining authorization in consumer &amp;amp; enterprise SaaS products, Warrant makes it dead simple to implement role based access control, fine grained access control, and other authorization schemes. Add enterprise grade access control to your application in minutes — &lt;a href="https://app.warrant.dev/signup"&gt;try Warrant for free&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>webdev</category>
      <category>security</category>
    </item>
    <item>
      <title>Insecure Direct Object Reference &amp; How to Protect Against it</title>
      <dc:creator>Karan Kajla</dc:creator>
      <pubDate>Thu, 18 Nov 2021 17:57:20 +0000</pubDate>
      <link>https://forem.com/warrant/insecure-direct-object-reference-how-to-protect-against-it-7li</link>
      <guid>https://forem.com/warrant/insecure-direct-object-reference-how-to-protect-against-it-7li</guid>
      <description>&lt;p&gt;Insecure Direct Object Reference (IDOR) is one of the most common forms of &lt;em&gt;broken access control&lt;/em&gt; which OWASP recently listed as the &lt;a href="https://owasp.org/Top10/"&gt;number one application security issue in 2021&lt;/a&gt;. A quick search for "IDOR" on &lt;a href="https://hackerone.com/hacktivity?querystring=IDOR&amp;amp;filter=type:public&amp;amp;order_direction=DESC&amp;amp;order_field=popular&amp;amp;followed_only=false&amp;amp;collaboration_only=false"&gt;Hacker One's Hacktivity feed&lt;/a&gt; shows that many top tech companies (and even the U.S. Department of Defense) have fallen victim to IDOR, in some cases paying out well over $10,000 per bug bounty. In this post, I'll explain what IDOR is, what causes it, and ways to protect your application against it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Insecure Direct Object Reference?
&lt;/h2&gt;

&lt;p&gt;IDOR is an access control vulnerability that occurs when an application uses an identifier for direct access to an object in a database but doesn't perform proper access control or authorization checks before querying or modifying the database. This often results in vulnerabilities that allow malicious users to access or modify other objects in the application, including those belonging to other users.&lt;/p&gt;

&lt;p&gt;To better understand what IDOR is, let's walk through an example. A common case of IDOR occurs when developers implement the ability to update objects in their application. Typically, an update operation exposes the internal identifier of the object to the user (in the URL or API endpoint, for example), and that identifier is used by the system to update the appropriate object.&lt;/p&gt;

&lt;p&gt;Consider an API for managing &lt;em&gt;objects&lt;/em&gt; in a SQL database with the following table structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="o"&gt;#&lt;/span&gt; &lt;span class="n"&gt;NOTE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;each&lt;/span&gt; &lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="n"&gt;belongs&lt;/span&gt; &lt;span class="k"&gt;to&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;single&lt;/span&gt; &lt;span class="k"&gt;user&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="n"&gt;AUTO_INCREMENT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;userId&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have a &lt;code&gt;GET /objects/:objectId&lt;/code&gt; endpoint for retrieving individual objects:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;GET https://api.my-app.com/v1/objects/2408
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which returns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2408&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"My Object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"userId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"This is my object."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also have a &lt;code&gt;PUT /objects/:objectId&lt;/code&gt; endpoint for updating individual objects:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;PUT https://api.my-app.com/v1/objects/2408
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which takes a request body:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2408&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"My Object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"My object's updated description."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In our API, the code for our PUT endpoint simply parses the request body and uses it to generate and execute a SQL &lt;code&gt;UPDATE&lt;/code&gt; query for the object specified in the request body:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;objects&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;"My Object"&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;"My object's updated description."&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2408&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key thing to note is our code doesn't explicitly check that the object being updated belongs to the user making the request. The query above also doesn't have a condition checking for ownership (i.e. &lt;code&gt;WHERE userId = &amp;lt;logged_in_user_id&amp;gt;&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;As a result, a malicious user (userId &lt;code&gt;81&lt;/code&gt; for example) could make a request to our PUT endpoint and update any user's objects (provided they specify a valid id).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;PUT https://api.my-app.com/v1/objects/2408
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2408&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"User 81's Object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"This object has been modified by user 81."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This issue seems fairly benign when dealing with example objects, but can become a major concern when malicious users can modify someone else's banking details or fetch another user's billing information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mitigation Techniques
&lt;/h2&gt;

&lt;p&gt;Preventing IDOR in an application requires consistent attention to detail, and there isn't really one silver bullet solution to fix it once-and-for-all (especially in a growing application). However, there are many ways to mitigate it, and I'll cover a few of them below. The best way to keep an application free from vulnerabilities related to IDOR is to employ a combination of the methods described, especially the last one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use Non-Contiguous Identifiers
&lt;/h3&gt;

&lt;p&gt;Even in a system with IDOR issues, a malicious user still needs to be able to enumerate or guess valid identifiers for other objects in order to access or modify them. In the example IDOR scenario from above, if the malicious user &lt;code&gt;81&lt;/code&gt; didn't know the id of user &lt;code&gt;2&lt;/code&gt;'s object (&lt;code&gt;2408&lt;/code&gt;), they wouldn't be able to modify it. However, since we use a standard SQL integer identifier that increments by 1 each time a new record is created, it's pretty easy to guess valid identifiers. One way to prevent this is to use non-contiguous identifiers for database objects (like a UUID). However, this strategy does come with its downsides (UUIDs take more space to store, database index performance can suffer due to non-contiguous identifiers, etc.) and isn't guaranteed to prevent exploits as a result of IDOR.&lt;/p&gt;

&lt;h3&gt;
  
  
  Require Ownership Conditions in Database Queries
&lt;/h3&gt;

&lt;p&gt;There are multiple layers in an application at which ownership or access control checks can be added to prevent IDOR. At the very least, requiring these checks at the database layer (the lowest layer in most web apps/services) can significantly reduce IDOR issues. Whether you're using an ORM or writing your own queries, a good way to enforce that all database queries include ownership checks is to abstract out all database interactions into separate "Service" and "Repository" classes (learn more about this pattern &lt;a href="https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html"&gt;here&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The repository class is responsible for taking inputs and executing database queries (always written with an ownership check) based on those inputs, while the service class acts as a higher level interface to the repository you can use throughout your code. Following this pattern, all database queries for a particular database table are isolated to a single class/file which makes it easier to monitor and enforce ownership checks in queries. More importantly, any code using the service class to interact with the data is required to provide an owner id. Here's a basic example in JavaScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;ObjectRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;objectId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="cm"&gt;/*
         * Execute the following SQL statement via ORM, etc.
         *
         * SELECT *
         * FROM objects
         * WHERE
         *     userId = &amp;lt;userId&amp;gt; AND
         *     id = &amp;lt;objectId&amp;gt;;
         */&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="cm"&gt;/*
         * Execute the following SQL statement via ORM, etc.
         *
         * UPDATE objects
         * SET
         *     name = &amp;lt;object.name&amp;gt;
         *     description = &amp;lt;object.description&amp;gt;
         * WHERE
         *     userId = &amp;lt;userId&amp;gt; AND
         *     id = &amp;lt;object.id&amp;gt;;
         */&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;ObjectService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Missing required parameter: userId&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;repository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ObjectRepository&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;getById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;objectId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;objectId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Not Found&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updatedObject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Not Found&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;updatedObject&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;//&lt;/span&gt;
&lt;span class="c1"&gt;// Example Usage of ObjectService&lt;/span&gt;
&lt;span class="c1"&gt;//&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;objectService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ObjectService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;UserSession&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getUserId&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updatedObject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;objectService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;updateObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedObject&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sendStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using patterns like the one above to enforce that database queries include ownership conditions will go a long way in preventing major IDOR vulnerabilities. However, not all ownership schemes map directly to a simple query condition like in our example. Take a collaborative text editing application like Google Docs, a file sharing service like Dropbox, or even an enterprise software service where users can grant other users the ability to view and edit documents on a per object basis. Applications like these typically maintain a set of ownership rules to help determine who has access to objects and require much more in order to prevent IDOR.&lt;/p&gt;

&lt;h3&gt;
  
  
  Implement Proper Authorization &amp;amp; Access Control
&lt;/h3&gt;

&lt;p&gt;The most effective way to prevent IDOR in applications is to implement a proper authorization &amp;amp; access control system. One that can be queried anywhere in an application to determine if a user has the appropriate access to an object or resource before allowing them access to it. You can then add access control checks to your application wherever privileged data is accessed or modified, much like we did in our example above. To learn how to implement a basic Role Based Access Control system, check out our previous write-up on &lt;a href="https://dev.to/implementing-role-based-access-control"&gt;Implementing Role Based Access Control in a Web Application&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A good access control system should be able to model your application's database schema &amp;amp; how all your data is related, allow you to implement common access control schemes (like Role Based Access Control, Fine Grained Access Control, etc.), and provide an easy way to check against dynamic access control rules in your code to prevent vulnerabilities like IDOR. It should also be flexible, allowing you to implement whatever access control model your application requires, from basic RBAC to more complex models used for services like Google Docs or Dropbox. Finally, in a good access control system, the ability to modify your access model without having to push code changes should be a requirement.&lt;/p&gt;

&lt;p&gt;Building secure, flexible, and consistent access control for an application is difficult and often not the focus of most developers building software. Warrant is an API-first access control service that makes it easy for any developer to drop a few lines of code into their application and instantly have secure access control. We have a generous free tier so you can test it out in your next application. &lt;a href="https://warrant.dev/"&gt;Get started&lt;/a&gt; today!&lt;/p&gt;

&lt;p&gt;Join the discussion on &lt;a href="https://discord.gg/QNCMKWzqET"&gt;Discord&lt;/a&gt;, &lt;a href="https://twitter.com/warrant_dev"&gt;Twitter&lt;/a&gt;, and &lt;a href="https://www.reddit.com/r/warrantdev/"&gt;Reddit&lt;/a&gt; to hear more about IDOR, access control, and everything security related.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>security</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Authorization in 2021</title>
      <dc:creator>Aditya Kajla</dc:creator>
      <pubDate>Fri, 05 Nov 2021 19:27:03 +0000</pubDate>
      <link>https://forem.com/warrant/authorization-in-2021-4899</link>
      <guid>https://forem.com/warrant/authorization-in-2021-4899</guid>
      <description>&lt;p&gt;The topic of authorization has seen a recent resurgence in interest from developers and security folks alike. The OWASP Foundation, a trusted voice on web application security, just updated its &lt;a href="https://owasp.org/Top10/"&gt;Top 10 Web Application Security Risks&lt;/a&gt; and for the first time rated 'Broken Access Control' as the top vulnerability facing developers. Also this year, Airbnb, Carta, and Intuit each separately published deep-dives detailing their newly built internal authorization services.&lt;/p&gt;

&lt;p&gt;Authorization is by no means a new security concept. So why this renewed attention to it? In this post, we’ll look at authorization as it stands today, what's changed in the landscape, and go over some best practices developers should follow.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Authorization Spectrum
&lt;/h2&gt;

&lt;p&gt;As previously mentioned, authorization is not a new concept. &lt;a href="https://csrc.nist.gov/glossary/term/authorization"&gt;NIST&lt;/a&gt; defines it as “the process of verifying that a requested action or service is approved for a specific entity.” One addition we'd make to this definition is that good authorization also ensures proper gating and access controls on data.&lt;/p&gt;

&lt;p&gt;Still, this is a very broad definition of authorization. There are no standards defining exactly how access checks should be implemented or what should be used to check permissions. But if you've read up on authorization, you've probably come across a couple of specific ‘types’ of authorization: ‘coarse-grained’ and ‘fine-grained’ authorization. Again, there isn’t an official definition or standards governing these two types but it’s generally accepted that coarse-grained authorization is more straightforward and simplistic (ex. Any user can access any report if they are an ‘admin’) while fine-grained authorization takes in many more inputs to determine access (ex. User [A] can edit report [X] if they have the [edit report X] permission).&lt;/p&gt;

&lt;p&gt;Even though both are often described as two exclusive types, in practice it's more helpful to think of authorization as a spectrum with coarse-grained and fine-grained authorization serving as the two ends. Depending on the product and use-case, a system can be closer to coarse-grained, closer to fine-grained or even somewhere in between. It's also likely for systems to shift along this spectrum over time as usage and functionality change.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Changed?
&lt;/h2&gt;

&lt;p&gt;Going back to our original question, if authorization is nothing new, why is there a renewed interest in it as a security concern? For one, the market for B2B software (particularly SaaS) has exploded over the past decade. Enterprises large and small are more comfortable than ever before in adopting new software products for their internal and customer-facing needs. It used to be that implementing proper authorization, especially fine-grained authorization, was a topic of concern for internal software development teams at Fortune 500s or enterprise software companies selling multi-million dollar contracts to large companies. These days, even smaller startups are competing for large enterprise deals where fine-grained authorization is considered table stakes. I'd argue that this market shift is being driven by a few key product themes. In no particular order, here are a few that stick out to me the most in B2B software.&lt;/p&gt;

&lt;h3&gt;
  
  
  Data, Data Everywhere
&lt;/h3&gt;

&lt;p&gt;Modern B2B and enterprise software applications are collecting and processing more data than ever before. Whether it’s user-generated (documents, notes, messages, comments) or machine-generated (ML training data, logs, analytics data), modern apps are data-hungry. And the more data applications collect, the better the authorization schemes need to be in order to safeguard against costly data leaks and exploits.&lt;/p&gt;

&lt;h3&gt;
  
  
  Built for Collaboration
&lt;/h3&gt;

&lt;p&gt;After working for years with tools like Google Docs and Dropbox, enterprise users expect to be able to share and collaborate on their content in whatever application they’re using. This expectation has pushed B2B apps to offer collaboration out of the box as a first-class feature. Implementing collaboration functionality is non-trivial and requires fine-grained authorization to ensure users can share and restrict access to specific content in real time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Integrations
&lt;/h3&gt;

&lt;p&gt;The rise of API-driven platforms and more recently ‘no/low-code’ tools has led to a plethora of integration opportunities between applications. But again, exposing programmatic data exports and uploads requires robust authorization in order to safeguard against unintended data leakage or access.&lt;/p&gt;

&lt;h2&gt;
  
  
  Best Practices
&lt;/h2&gt;

&lt;p&gt;Whether you're a solo developer building an indie SaaS product or a developer at a big software company, hopefully this overview shows you the importance of implementing proper authorization in your system. While we won't get into specifics, there are some best practices (some borrowed from OWASP) you should consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;As fine-grained as possible.&lt;/strong&gt; Going back to the authorization spectrum, you want your authorization checks to be as specific as possible. Ideally, this means your system has the ability to check access based on specific records and resources (ex. User [A] can edit report [B]) instead of generic behaviors (ex. Any admin user can edit any report).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deny by default.&lt;/strong&gt; Application behavior and data should not be accessible by default. This makes it easier to enforce that only the right users have access to the right data and actions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implement once and reuse.&lt;/strong&gt; Authz logic will get more complex the longer your application exists. Don’t spread out multiple implementations across the codebase because it will lead to missed cases and potential holes in your system.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maintain an audit log.&lt;/strong&gt; Keep an authorization log in your system (all allow/deny responses) so you can track access checks and conduct audits where necessary.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are just some high-level starting points but should at least help you think of and protect against common authorization and access control related exploits.&lt;/p&gt;

&lt;p&gt;If you’d like to chat more about authorization and access control, join us on &lt;a href="https://discord.gg/QNCMKWzqET"&gt;Discord&lt;/a&gt; or on &lt;a href="https://twitter.com/warrant_dev"&gt;Twitter&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Implementing Role Based Access Control in a Web Application</title>
      <dc:creator>Karan Kajla</dc:creator>
      <pubDate>Sat, 25 Sep 2021 00:00:53 +0000</pubDate>
      <link>https://forem.com/warrant/implementing-role-based-access-control-in-a-web-application-ko3</link>
      <guid>https://forem.com/warrant/implementing-role-based-access-control-in-a-web-application-ko3</guid>
      <description>&lt;p&gt;Access Control is the process of allowing (or disallowing) user access to specific resources or actions in a software system. For example, only allowing certain users access to internal admin pages on a website or only allowing paying users access to a premium feature. There are many approaches to implementing Access Control, but Role Based Access Control (RBAC) is one of the most popular and widely used. In this guide, we'll cover a standard way to implement RBAC and discuss some best practices for implementing Access Control in APIs and web applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;RBAC is an Access Control model in which the ability to access a resource or action in a system is tied to a permission (or policy), and each of those permissions is associated with one or more roles. Every user in the system has one or more roles and thus has all the permissions associated with those roles. This hierarchical structure is fairly intuitive and works really well for managing user access in a wide range of applications such as SaaS &amp;amp; enterprise software, e-commerce websites, company internal apps, and more.&lt;/p&gt;

&lt;p&gt;Since Access Control (especially RBAC) is fundamentally a relational problem, it makes sense to use a relational database like PostgreSQL or MySQL to implement it. We'll break down the data model in this guide using SQL.&lt;/p&gt;

&lt;h2&gt;
  
  
  Users
&lt;/h2&gt;

&lt;p&gt;Before doing anything else, we need to keep track of users in our application. For the purpose of this guide, we just need a unique &lt;code&gt;id&lt;/code&gt; for each user in our system. This id will be used later to associate users with roles. Most applications will also store extra user information like an email, a password, and first &amp;amp; last name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="n"&gt;AUTO_INCREMENT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Permissions
&lt;/h2&gt;

&lt;p&gt;Once we have users, the first step in implementing RBAC is to define a set of permissions (or policies) and associate each permission with a privileged action in your application. For example, you might define a &lt;code&gt;user:create&lt;/code&gt; permission associated with the ability to &lt;strong&gt;create a new user&lt;/strong&gt; in your application. Only users that have the &lt;code&gt;user:create&lt;/code&gt; permission will be able create a new user.&lt;/p&gt;

&lt;p&gt;To manage permissions, we really only need each permission to have a unique &lt;code&gt;id&lt;/code&gt; like users have. This is enough to associate permissions to roles. To make working with permissions more human-friendly, we'll make this &lt;code&gt;id&lt;/code&gt; a unique string identifier (i.e. something like &lt;code&gt;user:create&lt;/code&gt;) instead of an integer. This will make it easy to understand what each permission represents just by looking at its &lt;code&gt;id&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;permissions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Roles
&lt;/h2&gt;

&lt;p&gt;Once we have our permissions defined, it's time to group them together in the form of roles. Roles are like personas for the different types of users that access our application. These personas will dictate which permissions should be grouped together for each role. For example, if your application has a free tier with basic features that are available to all users and a premium tier with more powerful features available only to paying users, you might define two different roles: One role called &lt;code&gt;free_tier_user&lt;/code&gt; that grants access to all of the basic features and another role called &lt;code&gt;premium_user&lt;/code&gt; that grants access to both the basic and premium features.&lt;/p&gt;

&lt;p&gt;The data model for roles will look exactly like the model for permissions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;roles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Role Permissions
&lt;/h2&gt;

&lt;p&gt;Since every role will have permissions, we need a way to associate permissions to roles. We'll call this relationship a &lt;em&gt;role permission&lt;/em&gt;. To represent a role permission, we need to track the &lt;code&gt;id&lt;/code&gt; of the role and the &lt;code&gt;id&lt;/code&gt; of the permission we're associating together. Note that permissions can belong to multiple roles.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;role_permissions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;role_id&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;permission_id&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;role_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;permission_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  User Roles
&lt;/h2&gt;

&lt;p&gt;Since users will have roles, we also need a way to associate users to roles. We'll call this relationship a &lt;em&gt;user role&lt;/em&gt;. To represent a user role, we need to track the &lt;code&gt;id&lt;/code&gt; of the role and the &lt;code&gt;id&lt;/code&gt; of the user we're associating together. Note that users can have multiple roles.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;user_roles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;role_id&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;role_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Authorization
&lt;/h2&gt;

&lt;p&gt;Now that we have a data model to store and associate users, roles, and permissions, we can use permissions to protect access to resources and actions in our system. We need (1) a way to check the data model to figure out if a user has a permission and (2) an easy way to perform these checks anywhere in our application code. This process of validating user access is known as &lt;strong&gt;authorization&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Querying Permissions
&lt;/h3&gt;

&lt;p&gt;We can figure out if a user has a particular permission by querying our data for a relation between the user attempting to gain access and the permission required to gain access.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="o"&gt;#&lt;/span&gt; &lt;span class="n"&gt;Given&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="k"&gt;user&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt; &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;permission&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;create&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;#&lt;/span&gt; &lt;span class="n"&gt;we&lt;/span&gt; &lt;span class="n"&gt;can&lt;/span&gt; &lt;span class="n"&gt;determine&lt;/span&gt; &lt;span class="n"&gt;if&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="k"&gt;user&lt;/span&gt; &lt;span class="n"&gt;has&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;required&lt;/span&gt; &lt;span class="n"&gt;permission&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="o"&gt;#&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Getting&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="k"&gt;user&lt;/span&gt;&lt;span class="s1"&gt;'s role(s)
# (2) Checking if any of the user'&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="n"&gt;roles&lt;/span&gt; &lt;span class="k"&gt;grant&lt;/span&gt; &lt;span class="n"&gt;them&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;required&lt;/span&gt; &lt;span class="n"&gt;permission&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;permissions&lt;/span&gt;
&lt;span class="k"&gt;INNER&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;role_permissions&lt;/span&gt;
    &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;permissions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;role_permissions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;permission_id&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt;
    &lt;span class="n"&gt;permissions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;"users:create"&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt;
    &lt;span class="n"&gt;role_permissions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;role_id&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;role_id&lt;/span&gt;
        &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;roles&lt;/span&gt;
        &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The query above will only return a result if the user with id &lt;code&gt;15&lt;/code&gt; has the &lt;code&gt;users:create&lt;/code&gt; permission through one of their roles. If not, it will return an empty result, meaning the user does not have the required permission through any of their roles.&lt;/p&gt;

&lt;h3&gt;
  
  
  Access Checks in Code
&lt;/h3&gt;

&lt;p&gt;To make it easy to check for a permission anywhere in your application, you might abstract the query above into a helper class or method that can be called anywhere in your code. In JavaScript, this might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Authorization&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Returns true if the user has the&lt;/span&gt;
    &lt;span class="c1"&gt;// permission with the given permissionId&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;hasPermission&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;permissionId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// NOTE: Assume getPermissionsForUser runs the SQL query from above&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;permissions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getPermissionsForUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;permissions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can then call this helper method to protect actions in your application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;createUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newUser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;currentUserId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;UserSession&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getCurrentUserId&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hasPermission&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentUserId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;users:create&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Unauthorized attempt to create a new user!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;//&lt;/span&gt;
    &lt;span class="c1"&gt;// logic to create a new user&lt;/span&gt;
    &lt;span class="c1"&gt;//&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Best Practices
&lt;/h2&gt;

&lt;p&gt;Well-implemented Access Control is one of the most effective ways to provide data privacy for users and prevent potential data loss or theft. When implementing an Access Control model like RBAC, it's important to keep a few things in mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Define permissions based on resources and actions (i.e. &lt;code&gt;users:create&lt;/code&gt;)&lt;/strong&gt;. This leads to well-defined permissions that never need to change even if your roles and application logic do.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Do not perform access checks based on role.&lt;/strong&gt; This can be a very rigid approach that makes it hard to change your access model without updating code. Instead, it's better to check for access to permissions since these map directly to the resources and actions in your application.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Have a centralized access control service.&lt;/strong&gt; Since access control is independent of your application's business logic, it's a good idea to separate authorization logic into it's own service. We did this with the &lt;code&gt;Authorization&lt;/code&gt; class we implemented in JavaScript above.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Access Control isn't a core focus for most applications, but it's critical to get right. The margin for error is very low, and even a minor issue in authorization logic could expose privileged data and actions to users who shouldn't have access to them. If you don't want to worry about authorization best practices and implementing secure access control, use &lt;a href="https://warrant.dev/"&gt;Warrant&lt;/a&gt; to add access control to your application using RBAC or other access models in under 20 lines of code.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
