Hi,
We are a SaaS company. So far we've been using Retool as an internal tool within the company, but we are exploring the possibility of using retool to build a prototype for our customers. In order to assess the security of this, I'd like to better understand the security/threat model of a retool application, especially in the context of the embedded use.
If you think about a "normal" webapp, the security model is that the frontend has no integrity (meaning, an attacker can tamper and modify the frontend code that runs in their browser), but we can assume integrity in the backend. This is why nobody designs a frontend that constructs an SQL statement and the backend that executes it.
With retool, it's not clear how we should think about this. Which part of the system can we assume integrity? Or put differently, which part of Retool reside on the server side vs the client side? I think this is a crucial information every embedded app developer should want to know.
Just in case this is a little too abstract, what I think we need is a tamper proof path for our backend to pass some values to the retool app, and for the retool app to use those in the query.
Think the tenant ID in a multi-tenant SaaS. Our backend authenticates the user, ascertains the tenant ID of this user. I need to be able to pass this to retool, so that the query like "SELECT * FROM data WHERE tenant={{tenantId}}" will always use the tenant ID our backend has passed and nothing else.
I don't think the data property and the "parent window" query would meet this bar. The 'metadata' in embed URL might be it, but I cannot tell from the documentation. That section refers to query variable spoofing prevention, but that description is actually worrisome than reassuring.
It cites current_user.groups.map(group => group.name)
as an example that CAN be spoofed, and the only way in which this can be spoofed is that this JavaScript is evaluated in browsers, not on the server side, which suggests the security model is pretty much "any prepared statements used in the app can be invoked any time with any values, except when those arguments are defined trivially coming from current_user
object. IOW, it's much much closer to the "frontend constructs an SQL statement and backend executes it" model that nobody does for good reasons.
Your help is greatly appreciated. To reiterate, I cannot assess this from my side, and if I build something based on the wrong assumption, I could end up exposing every customer's data to an attacker, which is a fireable negligence.
Thank you!