none
MultiTenant Application Prevent Tenant Access Data from Other Tenant in Shared Database RRS feed

  • Question

  • I’m working on a tenant application and i was wondering how i can block tenant access other tenant data.

    First, let me expose some facts:

    1. The app is not free, 100% for sure the malicious user is a client.
    2. All the primary keys/identity are integers (Guid solve this problem but we can't change right now).
    3. The app use shared database and shared schema.
    4. All the tenants are business group wich own several shops.
    5. I'm use Forgery...

    I have some remote data chosen by dropdown and its easy change the id's and acess data from other tenants, if you have a little knowledge you can f*ck other tenants data.

    The first thing i think was check every remote field but this is kind annoying...

    So i build a solution compatible with Code First Migrations using Model Convention andComposite Keys, few tested, working as expected.

    Here's the solution:

    Convention Class

    public class TenantSharedDatabaseSharedSchemaConvention<T> : Convention where T : class
    {
        public Expression<Func<T, object>> PrimaryKey { get; private set; }
    
        public Expression<Func<T, object>> TenantKey { get; private set; }
    
        public TenantSharedDatabaseSharedSchemaConvention(Expression<Func<T, object>> primaryKey, Expression<Func<T, object>> tenantKey)
        {
            this.PrimaryKey = primaryKey;
            this.TenantKey = tenantKey;
    
            base.Types<T>().Configure(m =>
            {
                var indexName = string.Format("IX_{0}_{1}", "Id", "CompanyId");
    
                m.Property(this.PrimaryKey).IsKey().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity).HasColumnOrder(0).HasColumnAnnotation("Index", new IndexAnnotation(new[] {
                    new IndexAttribute(indexName, 0) { IsUnique = true }
                }));
    
                m.Property(this.TenantKey).IsKey().HasDatabaseGeneratedOption(DatabaseGeneratedOption.None).HasColumnOrder(1).HasColumnAnnotation("Index", new IndexAnnotation(new[] {
                    new IndexAttribute(indexName, 1) { IsUnique = true }
                }));
            });
        }
    }

    Convetion Registration:

    ** On convention register i pass two properties, first the primary key and second is the tenant id.

    modelBuilder.Conventions.Add(new TenantSharedDatabaseSharedSchemaConvention<BaseEntity>(m => m.Id, m => m.CompanyId));

    Base Entity Model

    public class BaseEntity
    {
        public int Id { get; set; }
    
        public int CompanyId { get; set; }
    
        public Company Company { get; set; }
    }

    Order Entity (Example)

    ** Here i reference the currency and client with company and all work as expected...

    public class Order : BaseEntity
    {
        [Required]
        public int CurrencyId { get; set; }
    
        [ForeignKey("CompanyId, CurrencyId")]
        public virtual Currency Currency { get; set; }
    
        [Required]
        public int ClientId { get; set; }
    
        [ForeignKey("CompanyId, ClientId")]
        public virtual Client Client { get; set; }
    
        public string Description { get; set; }
    }
    1. Is there any impact on performance?
    2. Is there any disadvantage compared to check every remote field?
    3. Someone have the same idea and/or problem and came with another solution?

    Wednesday, June 10, 2015 12:37 PM

Answers

  • I'm use asp.net mvc

    Well, you drank that MS MVC/Controllers using EF directly Kool-Aid too hard. And it's got you in trouble and serious trouble.

    You should put EF behind a DAL,  and the EF Entity/object should never come past the DAL

    http://en.wikipedia.org/wiki/Separation_of_concerns

    https://msdn.microsoft.com/en-us/library/ee658120.aspx?f=255&MSPPError=-2147217396

    <copied>

    Security Patterns

    Security patterns represent proven design solutions to common security problems. The impersonation/delegation approach is a good solution when you must flow the context of the original caller to downstream layers or components in your application. The trusted subsystem approach is a good solution when you want to handle authentication and authorization in upstream components and access a downstream resource with a single trusted identity.

    <end>

    DTO(s) should be going through the tier boundaries and not EF being used directly up at the controllers that;s if you want to implement some kind of security by using n-tierusing  

    http://en.wikipedia.org/wiki/Data_transfer_object

    Thursday, June 11, 2015 3:01 AM

All replies

  • The app use shared database and shared schema.

    Well that's your problem right there. Each client should have there own database. The database server can host seperate databases and their schemas in isolation from each other.

    The client-side application should be running in isolation from each other like using  WPF and MVVM or Windows forms based solution using MVPVM, a desktop solution,  where user security can be implemted at the method level

    You need a backend application server using WEBAPI or WCF that implements granular user based security at rhe method level with each client backend applilication in isolation from each other.

    The application starts sharing resouces with multiple different user-clients, and you are asking for the trouble  you are getting, which is easily hackable particularly so if the client is using a Web based UI

    Wednesday, June 10, 2015 1:15 PM
  • The app use shared database and shared schema.

    Well that's your problem right there. Each client should have there own database. The database server can host seperate databases and their schemas in isolation from each other.

    The client-side application should be running in isolation from each other like using  WPF and MVVM or Windows forms based solution using MVPVM, a desktop solution,  where user security can be implemted at the method level

    You need a backend application server using WEBAPI or WCF that implements granular user based security at rhe method level with each client backend applilication in isolation from each other.

    The application starts sharing resouces with multiple different user-clients, and you are asking for the trouble  you are getting, which is easily hackable particularly so if the client is using a Web based UI

    I'm use asp.net mvc :\

    Wednesday, June 10, 2015 8:25 PM
  • I'm use asp.net mvc

    Well, you drank that MS MVC/Controllers using EF directly Kool-Aid too hard. And it's got you in trouble and serious trouble.

    You should put EF behind a DAL,  and the EF Entity/object should never come past the DAL

    http://en.wikipedia.org/wiki/Separation_of_concerns

    https://msdn.microsoft.com/en-us/library/ee658120.aspx?f=255&MSPPError=-2147217396

    <copied>

    Security Patterns

    Security patterns represent proven design solutions to common security problems. The impersonation/delegation approach is a good solution when you must flow the context of the original caller to downstream layers or components in your application. The trusted subsystem approach is a good solution when you want to handle authentication and authorization in upstream components and access a downstream resource with a single trusted identity.

    <end>

    DTO(s) should be going through the tier boundaries and not EF being used directly up at the controllers that;s if you want to implement some kind of security by using n-tierusing  

    http://en.wikipedia.org/wiki/Data_transfer_object

    Thursday, June 11, 2015 3:01 AM