简体   繁体   中英

Secure multi-tenancy in MySQL application

I have a JSP/MySQL web service where users interact with "processes" -- they can upload data, configure, view reports, etc for a given process. They can also create new processes or run reports that compare several processes.

Currently, the process id is specified in the URL (a GET parameter) so any user can interact with any process. I have been asked to add security and multi-tenancy to this service. For simplicity, let's say each tenant has full access to a set of processes, but processes may be accessible by multiple tenants.

My preferred approach:

  • Add a user table (PK_User_Id, password_hash, name, etc)
  • Add an access table (FK_User_Id, FK_Process_Id)
  • An SSL login page that stores the Tenant_Id in the Session
  • A process-select page that lets you choose a Process_Id that you have access to, and stores that in the Session
  • Almost every page will create its SQL queries based on the Session's Process_Id
  • "Cross-process" pages like Create, Select, and Compare will work off of the Session's User_Id instead

My boss thinks that this is not secure "enough" to satisfy an external code audit. He fears that a wayward developer could still write a query that exposes one customer's data to another, or something.

He wants me to also use ANSI SQL's built in ROLES (the app must stay DB agnostic) to create a db role for each user. The role will detail which tables the role has access to, which rows in shared tables, etc. This way, upon login, the Connection will be "safe" and no developer mistake can possibly cause issues.

  • Is this possible?
  • Are there such a thing as DB-agnostic "Roles" that work with MySQL?
  • Can the roles specify that you are allowed to add rows to a table iff the primary key is 'foo'?
  • Is my system "secure enough" by industry standards?

Here is what I do for MySQL multi-tenant with a single database to ensure data is private:

  1. Create a mysql user for each tenant
  2. Add a tenant_id column to each table
  3. Use a trigger to automatically put the current mysql user into the tenant_id column on INSERT
  4. Create a view for each table that only shows rows where tenant_id = mysql_user (do not include the tenant_id column in the view)
  5. Restrict the tenant mysql user to only have access to these views

Since the application is using the tenant's mysql user there is no chance that they can accidentally get another tenant's data.

I was able to convert a large single-tenant mysql application to multi-tenant in a weekend with minimal changes. I documented the design here: https://opensource.io/it/mysql-multi-tenant/

We had a similar discussion on multitenancy security and handling requests on so question . But in short I think storing tenantID in session is a huge security risk. User can go from one tenant to other and tenantID will remain the same, also tenantID should not be send through url.

  1. use PostgreSQL instead, as it supports real schemas, unlike MySQL

  2. if you have to use MySQL, do the following:

    • make one mysql user per tenant
    • add an indexed column to each table, tenant VARCHAR(16) NOT NULL
    • add a trigger to each table that sets tenant to the mysql connection username ON BEFORE INSERT
    • create a view for each table that sets WHERE tenant = mysql connection username. DO NOT include the tenant column in the select list
    • grant permission to the tenant user for views, but not for tables

And now the user can only see their own tenant information.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM