Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Building Production-Grade Web Applications with Supabase

You're reading from   Building Production-Grade Web Applications with Supabase A comprehensive guide to database design, security, real-time data, storage, multi-tenancy, and more

Arrow left icon
Product type Paperback
Published in Aug 2024
Publisher Packt
ISBN-13 9781837630684
Length 534 pages
Edition 1st Edition
Languages
Tools
Arrow right icon
Author (1):
Arrow left icon
David Lorenz David Lorenz
Author Profile Icon David Lorenz
David Lorenz
Arrow right icon
View More author details
Toc

Table of Contents (20) Chapters Close

Preface 1. Part 1:Creating the Foundations of the Ticket System App
2. Chapter 1: Unveiling the Inner Workings of Supabase and Introducing the Book’s Project FREE CHAPTER 3. Chapter 2: Setting Up Supabase with Next.js 4. Chapter 3: Creating the Ticket Management Pages, Layout, and Components 5. Part 2: Adding Multi-Tenancy and Learning RLS
6. Chapter 4: Adding Authentication and Application Protection 7. Chapter 5: Crafting Multi-Tenancy through Database and App Design 8. Chapter 6: Enforcing Tenant Permissions with RLS and Handling Tenant Domains 9. Chapter 7: Adding Tenant-Based Signups, including Google Login 10. Part 3: Managing Tickets and Interactions
11. Chapter 8: Implementing Dynamic Ticket Management 12. Chapter 9: Creating a User List with RPCs and Setting Ticket Assignees 13. Chapter 10: Enhancing Interactivity with Realtime Comments 14. Chapter 11: Adding, Securing, and Serving File Uploads with Supabase Storage 15. Part 4: Diving Deeper into Security and Advanced Features
16. Chapter 12: Avoiding Unwanted Data Manipulation and Undisclosed Exposures 17. Chapter 13: Adding Supabase Superpowers and Reviewing Production Hardening Tips 18. Index 19. Other Books You May Enjoy

Understanding PostgREST’s OpenAPI Schema exposure

In this section, I want to talk about schemas, their structures, how PostgREST exposes them, as well as how to avoid exposure.

You must be aware that your complete public schema structure is, in fact, publicly visible to everyone who has the Anonymous Key to your project. But you might wonder, why is that? And shouldn’t we have discussed this in Chapter 11? The short answer is this – PostgREST follows the OpenAPI specs, and even though someone can see the schema, they can’t see your data, so it’s not a security issue per se. Let’s dig into this further.

In Chapter 1, I explained how PostgREST introspects the database and provides an API on top of it. PostgREST hereby follows the OpenAPI specification and allows us to explore the possible API calls (https://postgrest.org/en/v12/references/api/openapi.html) and build upon them. This means that once someone has your API URL and Anonymous Key (which is exposed when you use Supabase with frontend clients), everybody knows what your schema looks like, which relationships between the tables exist, and which RPCs are available to be called.

There is an open-source Supabase Schema Visualizer (created by GitHub user @zernonia and available at https://github.com/zernonia/supabase-schema) that creates a visual representation of your schema. You can find it integrated within your project’s Supabase Studio Dashboard (see Figure 12.1), but it is also independently usable and will create a schema visualization, with a provided API URL and an Anonymous Key.

Figure 12.1: A visualized schema with relations (don't worry about the specifics; this is just an overview of the Supabase Schema Visualizer)

Figure 12.1: A visualized schema with relations (don't worry about the specifics; this is just an overview of the Supabase Schema Visualizer)

This means that a potential hacker could use the existing information as an easy-to-understand visualization of your structure. Also, it means that your maybe-super-precious architecture is partially exposed to the outside world.

PostgREST exposes this information at the base path of the Supabase REST API. You can just make a GET request to YOUR_API_URL/rest/v1/ and add an HTTP header with the Anonymous Key (in curl, this is -H 'Apikey: YOUR_ANON_KEY'). The server will then respond with the full JSON output of the schema (which the visualizer uses to create a diagram):

Figure 12.2: A small extract of the PostgREST OpenAPI introspection

Figure 12.2: A small extract of the PostgREST OpenAPI introspection

Note

On localhost, don’t use ?apikey, as it works without it and throws an error otherwise.

But what about other schemas, like the rls_helpers schema we created? Is that exposed as well? No. The default schemas that are exposed are public, storage, and graphql_public (graphql_public is a schema that reflects data from the public schema for the GraphQL endpoint of Supabase, which you can learn more about here: https://supabase.com/docs/guides/graphql).

Okay, but what if I don’t want my schema structure to be visible/exposed? Let’s discuss that now!

Preventing schema exposure

If you want to avoid people scanning through your schema with the PostgREST APIs (which are available at YOUR _API_URL/rest/v1/), there’s a simple solution and a correct solution.

The simple solution is to completely disable OpenAPI exposure by running this SQL expression:

ALTER ROLE authenticator SET pgrst.openapi_mode TO 'disabled';
NOTIFY pgrst, 'reload config';

By running this, OpenAPI generation will be disabled, but this also means that Supabase’s health check assumes that PostgREST is down, as it doesn’t respond anymore on the base URL. So don’t do this!

If you did, reverse your code to this:

ALTER ROLE authenticator RESET pgrst.openapi_mode;
NOTIFY pgrst, 'reload config';

Instead, let’s look at the correct solution – this involves returning a mocked OpenAPI response with empty API data, as described at https://postgrest.org/en/v12/references/api/openapi.html#overriding-full-openapi-response. To do so, we need to define a mock function in our database that returns the most basic JSON as a valid OpenAPI response:

create or replace function mock_openapi() returns json as $_$
declare
openapi json = $$
  {
    "swagger": "2.0",
    "info":{
      "title":"Overridden",
      "description":"This is a my own API"
    }
  }
$$;
begin
  return openapi;
end
$_$ language plpgsql;

Once executed, we need to tell PostgREST to use this function to generate the schema response:

ALTER ROLE authenticator SET pgrst.db_root_spec
 TO 'public.mock_openapi';
NOTIFY pgrst, 'reload config';

Note

In Supabase Studio, there is an API Docs tab that usually shows you documentation specifically for each of your tables. As it is based on the returned OpenAPI response from PostgREST, which is now empty, this will not show auto-generated docs anymore – however, this should be your least concern, as your documentation is now this book!

Now you know how to hide away your schema while still being able to use PostgREST on the schema. If you want to undo this action, just use RESET:

ALTER ROLE authenticator RESET pgrst.db_root_spec ;
NOTIFY pgrst, 'reload config';

We can also remove schemas for use with PostgREST completely. Let’s see that next.

Removing schemas from usage via API

If you really want to, you can go as far as saying that you don’t want PostgREST to act on a schema at all. This also means disabling the usage with the Service Role Key. The only thing that you can then do to perform a query on the database is to connect directly to it.

With a local instance, you can control the API-exposed schemas in the config.toml file under the [api] section. There, you will find the schemas = ... configuration. On supabase.com, you’ll find this in the API | API settings section, where you can add or remove schemas to be used by the API:

Figure 12.3: Setting the PostgREST-enabled schemas

Figure 12.3: Setting the PostgREST-enabled schemas

That’s all you need to do to disable API access to a schema. But what if you want the opposite – to specifically allow a custom schema to be used with PostgREST? Let’s see that too.

Specifically exposing a schema to the API

Removing a schema to be able to be used by the API was straightforward; however, adding a custom one to be exposed isn’t as intuitive as just creating it. Obviously, after creating a new schema, you must add it to the Exposed schemas section shown in Figure 12.3, but you also need to set a few permissions for the API to be able to read the tables properly. This is done with SQL commands granting the proper permission roles within Postgres.

You can find the set of commands to execute for an API-exposed schema on this page: https://supabase.com/docs/guides/api/using-custom-schemas. I will refrain from copying and pasting them into this book; note that you need to replace myschema with the custom schema you want to expose.

As an additional note, creating a Supabase client with a different schema than public can be done by passing { db: { schema: 'schema-name' }} to the options when creating a client, like so:

createClient(url, key, { db: { schema: 'your-schema' } });

That’s all there is to know about schema exposure. Let’s hit the next topic.

lock icon The rest of the chapter is locked
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime
Banner background image