Way to limit amount of rows returned by broad queries through RLS #28858
gc-ft
started this conversation in
Show and tell
Replies: 1 comment 1 reply
-
Writing this post I decided to work a bit more on the function to make it more configurable and remove the limitation of multiple tables being involved... here is the new version, it takes two variables: a Hope this will be interesting for some, but of course if someone sees a problem with this, do please let me know!
|
Beta Was this translation helpful? Give feedback.
1 reply
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
NOTE: After I wrote this post I adjusted the function and wrote a reply, so read below please for the new version of the function!
Now and then I read here in the discussions or over on reddit or the like that people are wondering if there is some way to make sure with RLS that a where clause on a certain column needs to be used, so that people can not simply dump all rows they have access to from a table through the API. This is usually looked for in cases where for example there are public profiles in a system and it is completely fine if people read a specific public profile but it is quite un-wanted that someone can just scrape all profiles with easy queries.
One way to limit this is of course lowering the amount of max rows that Supabase allows in query results (which defaults to 1000), however it is not REALLY a fix since people can just hammer the API with range requests (limit / offset queries) and still dump all public records.
So therefore people have asked often if there is some way to build a RLS policy which in essence forces a where clause on a certain column in order to return any useful data. I have come up with a somewhat hack to do just that while PostgREST has not implemented anything natively (and I believe it is not very likely this will happen soon since discussions around limiting the API have been around for a few years on the PostgREST GitHub boards and such).
The hack uses the fact that we can set arbitrary headers due to PostgREST for the API reply and can also check them whenever we want. So, first step is a simple Postgres function which checks and sets a specific header
x-limited-response
.see function in second post
This results in the function returning
true
first time this function being run during a postgREST session andfalse
every other time after that.If you then use this policy:
This effectively forces all queries on
some_table
to only return the FIRST result, regardless of any limit/offset added! Why? Because even for limit/offset queries RLS needs to be checked from the first row on, running the query with offset 1 would result in always an empty response, because the first row that should be "skipped" still has RLS run on it.Note that this is the first version of this little hack, there are for sure some things that it does not cover and also running many queries or having multiple tables in a query that have this security will mess up the results in the current setup, because the first row of a second query run in the same session would be blocked already since the function would return FALSE.
Thoughts on this idea would be appreciated!
Fabian
Beta Was this translation helpful? Give feedback.
All reactions