We have a multi-tenant Asp.Net MVC 4 web application with each tenant having its own repository of files (a folder in the file-system). We took the shared database, shared schema approach and we identify tenants by their subdomain.
What is the best way to ensure that a tenant can only access his repository folder and no other folder in the file-system? we check it in the application business logic, but what if we make a mistake...?
When running the application, all tenants run under the same user (which is defined in IIS application pool).
Do we need to serve each tenant as a separate user - using impersonation? do we need to impersonate each time a request is made to the server - in order to fill it?
I've heard this has performance drawbacks and is not the prefered way, but what is?
We also have a windows service which fills requests in the background (for all tenants), sent to it through MSMQ. Does this service also needs to change its identity every time it gets a request?
Edit:
In addition, we need a type of isolation which if someone uploads a file infected with a virus - it will affect only this tenant's files, and not every tenant on the server. We use ant-virus software, but we need this separation also in case the antivirus software will not identify the virus.
Thank you
all tenants run under the same user
If each tenant has a separate IIS Web App and identity (whether app pool or "normal" user), then you can use NTFS access control.
These does not depend on having all users having a local or domain user accounts on the web servers to allow impersonation (and this NTFS access control).
However it will add memory overhead on the servers of course – each tenant will have their own worker process.
[…]MSMQ. Does this service also needs to change its identity every time it gets a request?
I'm not sure you can do impersonation based on MSMQ messages, I would expect this not to work (MSMQ messages do not carry the necessary identity information).
Anything shared is going to need to be implemented to check all access: depending on the nature of the processing this may be more difficult (eg. if client requests can be something of the order "get information from the file" for an arbitrary file: the service would need to do the access checks1).
1 There are Win32 functions that will do the heavy lifting.
Related
So, I am developing an Web Application in .Net Core 6. I have two API's, one for User authentication (using Identity), and another for executing my app services. For each API i have an separate DB, one for storing the users information, and another for storing my services information. Let's say that one of my services is uploading a file to my server. In that case i need to know witch user has uploaded the file, relating the file with the user. However, since my user is in another DB, i cannot make an relationship between them.
I thought in referencing the user Id with an Integer, getting the information in API requests, but in that case, if i delete the user, it will still reference him. Should I just make my app services tables in the DB that stores the user authentication info ?
For distributed systems like your describing, I recommend using a Guid/Unique Identifiers.
It's also not uncommon to store some user information across distributed systems for that exact purpose of not losing the associated information. That said, you should be careful to always have a source of truth such as the identity server, and possible setup sync jobs that will keep the other services "eventually updated." This is often done using message bus to send updates and have listeners for your services that will pickup changes such as name, contact info, or hierarchy data.
Hope that helps.
I have distributed system, in which I access some internal network resource through Windows Authentication:
User #345 request -> MyWebInterface -> SerializableQueue -> Worker #123
Worker #123 access resource through WinAuth (currently under service account, not from user account).
User #345 response <- MyWebInterface <- SerializableQueue <- Worker #123
The problem is in step 2 - I need to impersonate under User #345 and then access resource. This is security requirement to use this resource.
How one should serialize user credentials and then deserialize them at worker to accomplish WinAuth impersonation?
Impersonation is not a native feature of any queueing system I’m aware of - MSMQ in particular does not offer this functionality.
I’m taking the scenario where you have an asynchronous service that Requires impersonation to a back end service you do not control (e.g. an SMB share or another service which requires windows auth). If you do control the back-end service, consider allowing your service to authenticate as itself then “act as” the real client.
So, under the assumption you need real impersonation, you have a couple options: S4U and C2WTS. Both are essentially ways to use SeTcbPrivilege to issue tokens for users by username (no password required). A good tutorial of both technologies is available on MSDN.
If that doesn’t immediately trigger the warning bells, it should be noted that this would be a very security critical piece of code. SeTcbPrivilege by itself only affects the local machine and is therefore manageable, but if used in combination with delegation it can be used to access remote resources with the same privileges as the caller. You essentially are running your service with “domain admin” rights unless constrained and planned very carefully.
Background
I'm building a single tier application Winforms application using C#. A SQL Server localdb database is attached to the application that runs when the application does. The plan was to use Windows Authentication to verify that the user is part of the MyApplication role/group and can use the application. But, in order to prevent users from accessing the database via other means, I was thinking of using an Application Role so that only the one SQL application user can edit the db tables.
Question
My understanding is that in order to use an Application Role, you need to provide a username and password in the connection string. I can encrypt this information, but obviously it will need decoded before being sent to the database. Is this a concern in a single tier application? What are other alternatives?
To use an application Role, you'll use the sp_setapprole stored procedure where you will provide the name of the application role and the password, rather than sending it in the connection string. When you use application roles, you still connect using an ordinary login, but once you successfully sp_setapprole, your connection loses its user permissions and instead gains the permissions of the application role. Having the decoded password in memory is a concern if you have reason to believe that users may decide to use a debugger to attach to your process to extract the password. Any administrator would also be able to decrypt the encrypted password on disk as well if you choose to use windows machine-level key containers. Using only a single tier for an application that uses a database is a security risk, and you have to decide based on the circumstances surrounding the application whether it is an acceptable risk to gain the reward of skipping a few weeks of design and development.
Source:
https://technet.microsoft.com/en-us/library/ms190998(v=sql.110).aspx
I highly recommend implementing a web api to manage your application's interactions with the database as well as security. This web api could use a windows "service" account to authenticate with the database, and users would authenticate with the api using their individual windows accounts. This has the added benefit of you never having to think about passwords. As far as managing API permissions, that is an issue that is up to you to design and implement as you see fit. The main issue you need to understand and deal with is uniquely identifying AD users. Take a look at this SO post for more info on that: What Active Directory field do I use to uniquely identify a user?
Your service account would have all necessary permissions on the database to do what the application needs to do, but not all api users would necessarily have permission to use all api functions. You would manage a store of uniquely identified AD users that have permission to use the application and what permissions they have. The rest is design and implementation details that are up to you.
Define user with privilege only to execute stored procedures. By this way if someone use SQL Management Studio, s/he cannot browse/edit tables and even cannot see the table names.
I have a scheduled task to create to get data from a site using the webclient
class. How do I execute a database update with the data retrieved under a different windows user? I was told not to use the same account to access the site as performs the update. Should I just create a windows service that runs the web request then call a db component with authentication settings set under IIS to run under a different user? Or is there a tidier way to do this running a single exe as a scheduled task? The Scheduled task runs under a single user. Could I run the task and switch user for the update? We are using Windows authentication at the database level.
Run two Windows Services. One to get the data from the website, running under Account "A" which stores the data locally. The other Windows Service running under Account "B" picks up the locally stored data and executes the database update.
Other designs will require you to store the credentials somewhere in a config or other file - this way the Windows Services are always running under the correct account for the task they are attempting.
You clearly stated that you will have to use a Windows user to get access to the database. However, often this will not be the case when you authenticate against a web site so exactly how you solve your problem will depend on the details of that.
You should probably execute your process as the Windows user that has access to the database. Then you have to solve how to authenticate against the web site. If the site uses forms based authentication it is a bit complicated but there is an answer to the question WebClient accessing page with credentials that might help.
If you need to use the WebClient.Credentials property to authenticate against the web site you might find it easier to execute your process as the user that has access to the web site. You then need to use impersonation to access the database. A simple way to do that is to use the SimpleImpersonation NuGet package.
In most cases you will have to store the password for one of the users so your process can use it to either log in to the web site or impersonate the user. A relatively safe way to store the password is to use the Windows Data Protection API (DPAPI). The class ProtectedData can assist you in storing secrets so only a specific user on the computer can access the secret (e.g. the password).
At first I was passing around a session variable but then someone told me that isn't supported in azure. Does anyone have any other suggestions ? I'm just saving an object of a login user.
Azure does support sessions, just that placing sessions in individual web roles is not going to work well. For example, if you want to scale your app to 2, 4 or 8 servers or maintain high availability you will have a load balancer that will route the requests between the different servers. Therefore, if you have multiple web servers each with their own user sessions behind a load balancer...you will have a problem as you could have a request that goes to a web role (server) without the session state data.
If you want to store a single variable that is available to all web roles...
Distributed Caching (Azure has a couple options for this)
Azure Table Storage (it would be fast for a single variable)
SQL Azure DB (probably overkill for a single variable)
All of these options above would allow shared access (read/write) from multiple Azure web roles. There are ASP.NET session state providers written for Azure Caching and SQL Azure DB that are available too. Conversely, Azure Table Storage is a real good option for very fast retrieval of data based on a unique key.
If your web role is running on single instance then sessions will work fine.
but in case of scalability needs,you will have to go for caching.