I have somewhat of a thought problem, where I'm not sure if what I already built can be done a lot more efficiently, so that's why I'll share my 'problem' here. (to be clear, everything I have built works, I'm just looking to make it more efficient).
I have a webapp made with MVC & SQL which has a log-in system etc for users.
A user has a status, which is an enum, and can be active, blocked etc and is stored in the database (along with other user-data).
Within my webapp I have made a custom AuthorizeAttr. for authorizing users on every call made (applied as a global filter).
However, the 'normal' authentication is based on the cookie, which does not change when I would change the user-status in the database. For instance, users can de-activate another user in the same group (when being Admin). These database changes are not taking immediate effect since by default the authorization only verifies the cookie, and the cookie is based on the status when logging in.
To fix this issue, I added some additional logic to my authorizationAttr, which on every request calls the database for the current user status (the enum), and then simply does some checks whether the user is allowed to continue, or a redirect is required.
Calling the database on every request seems (even just for 1 enum) seems to be a bit taxing on the server/db especially when the webapp would grow in popularity (= lots of users).
One idea I thought of was to cache the enum in session cache but for short periods of time (like 60 seconds), this would save some database calls, but obviously the user can still use the webapp for max 60seconds after being de-activated.
I could be wrong in thinking that these database calls are actually that taxing of course.
Any ideas for improvement?
how do you know that checking status per request is too expensive? did you measure performance cost of checking user status in the database? have you created your custom cache without actually measuring the cost of simple solution? do you use ORM like hibernate? they have 2nd level cache built in so often there will be no roundtrip to the database.
i think it's way better to stick to the KISS principle rather than creating custom solution for a difficult problem. even if your database will be the bottleneck then usually buying additional hardware once is cheaper than maintaining overcomplicated solution for years
if your application grow, first thing you throw away is relation database
Have you considered using ADO.NET DataSets for your requirement? If you don't have multiple front-ends you could possibly read the login statuses initially into the dataset. All read/write operations could be made to this and you could later save your changes to the actual database. In case you have multiple front-ends, would it be possible for you to restrict all read/write/modify operations of one group to a single front-end instance? Because I guess you could use the dataset approach in that case as well.
Related
My Problem:
My app has number of pages/resources that should be accessible by guest users but only after providing correct pair [Resource Code - Unique Token] (each page has one Page Code and multiple unique "Tokens" issued for each user). Tokens are generated beforehand and stored in DB. After accessing the page, user will be able to interact with multiple other resources belonging to particular page.
How I organized this so far:
Page asks user to provide token and checks it with records in DB. If this is a correct token for resource requested, it writes cookie and then, every time user interacts with the resource or its content, controller will every time read cookie and check [PageCode-Token] pair with database before continuing the action.
Question:
Is there any other, more elegant and efficient approach? Should I use Session instead? I feel a bit bad about querying DB every time.
This depends on how many users access your service, if the volume is too large it would be recommended to create a cache where all tokens are stored, thus avoiding a database overload. However if the service is not widely used this is not necessary as a database can handle a lot of requests.
You could create a cache in two ways, using ready-made software or create a small cache within the project itself.
If you choose to use software, I would recommend Redis, it is a cache database that stores values with or without a timeout, ie after a while the tokens are deleted.
Keep in mind that this does not prevent you from making requests to the database, but you will always make requests to the cache first (Redis) and if the value does not exist, it is necessary to search within the database.
But if you choose to create your own, you will need to do most things manually and always knowing how much resources can be allocated. It may be more advantageous to use software than reinvent the stone.
I'm currently writing a web app which would largely be used by developers, and I figured (from personal experience) that there would be times where it would be handy to run custom searches in an unrestricted way. I would like to let my users run arbitrary multi-statement SQL searches on their personal data (for an extra fee), so they can retrieve the data that's relevant to their question at the time.
Obviously, this is something that needs to be done with extreme caution, so I would like to make sure I'm going to tackle this the right way.
As I see it, the main points of concern are:
A malicious user could run a DOS (can track this via logging and remove their permissions)
Someone could run a function in a malicious way
Someone could access/modify data that doesn't belong to them (including database schema)
Someone could delete or modify data in a query (I would prefer they do that in a controlled manner)
What would be the safest way to go about providing this kind of ability to users safely?
This is dangerous territory (and I strongly recommend you weigh up this requirement carefully due to the obvious dangers you will be exposing yourself to), however I will try to give you the safest way to proceed if you must.
The only assumption I am making here is that you are running a current version of PostgreSQL and that you require users to remotely connect to the server (using their own tools) to execute their custom queries. Even if they will be entering them into a webpage, most of the same techniques will still apply as long as they each have a separate user log in for the database server.
First, (as NoBugs pointed out) to prevent users executing obvious malicious statements (like UPDATES, DELETES, DROPS, etc) you need to ensure that the user account connecting to the server has only SELECT permissions on the db(s) and table(s) they should be able to read from. Have a look in manual to see how to define roles for users, and grant specific permissions to those roles.
http://www.postgresql.org/docs/9.0/static/user-manag.html
http://www.postgresql.org/docs/9.0/static/database-roles.html
Note that you can only limit a user down to a particular table. If
users each need to be given access to different parts of a table, then
PostgreSQL (and nearly all DBMS's) will not support this out of the
box. Your only option would be to try and create some kind of SQL/TCP
proxy that intercepts requests, and modifies them somehow to limit
query results, before passing on to the database server. This would be
extremely difficult even for a very experienced developer!
To prevent (or at least detect) DOS attacks, you will need an external script or process to keep an eye on the resource usage of the database (and/or the entire server) every few seconds, and possibly build in a mechanism to restart the PostgreSQL service if it is maxed-out.
You will need to experiment with how long before you should intervene
carefully, as it is quite possible for a legitimate query to max
things for a few seconds.
As you mentioned, you would need to keep a careful log of who was trying to execute what, & when so, if necessary you can work backwards from a failure, to find out the culprit. You can really only rely on the system logs for this, which can be configured to write out to files, CSV, or Syslog.
I would suggest you pre-create some tools to help you quickly search
these logs to find what you need before you need to try and find it
(pun intended).
Finally you should also try to follow the other standard best practices for administration and security (all of which can be found in the manuals) including:
Only allow access for your users from specific ip's/hosts (dont give the general public any chance at connecting to your server. Your customers will need static IP's to access the system, but this is certainly worth considering to mitigate risks.
Keep a close eye on all of your standard administrative tasks for the server (especially backups, disk space, log file maintenance, index usage, etc.)
Make sure the user the sql is running as has permissions only to the tables/files the user should be able to modify.
There are also some other considerations - only allow trusted input (maybe use https in your api calls?) and know Mysql could access files and stuff you wouldn't want to let it access.
See also: http://www.greensql.com/article/protect-yourself-sqli-attacks-create-backdoor-web-server-using-mysql
C# - ASP MVC - .NET 4.5 - Bootstrap - Razor
I have a form wizard (http://vadimg.com/twitter-bootstrap-wizard-example/examples/basic.html) that is used to setup a complex object (obj1). A property of obj1 is a List<obj2>. On one step of the wizard I want to add multiple obj2's to the list. Since obj2 is slightly complex as well, I thought I would use another wizard to help build it. Except I need to persist this List<obj2> on wizard 1, while I'm off in wizard 2 building another obj2.
My first thought was to use a session to hold the List<obj2>, I was just wondering if that's a good option, or if there would be a better one? The user may leave from Wizard1 to go to Wizard2 and come back multiple times.
There's no perfect answer here; each approach has trade-offs. But here are some options that I can think of (and these are independent of ASP.NET/C#)
Session (as you suggest)
This will store data in web server memory (by default). If you have a lot of users, this could be a problem.
You risk the information being lost when the user gets a new cookie/the session times out.
Potentially better performance that a db, depending again on the number of users
Database (as you mentioned)
Could cause more database traffic.
Can save information for user even if they close a browser, switch computer, the power goes out, etc.
Maybe a separate NoSQL database just for transient wizard data would be worth trying.
Cookie (store data on the user's computer)
Users can potentially tamper with/view the data
There is a limit on cookie size (4 KB each?)
Local storage (HTML5)
Similar to cookies
But not such a small limit
Not every browser supports it (may need polyfill)
Form/Post/Hidden/ViewState
You could just post the data and drag the information from response to response
But this gets really annoying with back buttons & timeouts
Lots of work, and again, the user can tamper with the information
I have a small web application that has multi-language support (en, de, it, fr, nl, sl, hr). This application is accessed constantly from a lot of users that use it for a short time (the time to fill their data to get an internet access code).
I have a problem with setting the culture similar to this thread:
InitializeCulture change language of domain
I know how to do it, it's just that I'm not sure which state-management to use. I wanted to ask for suggestions which method to use. Those are my thoughts:
Session - the easiest way and the more elegant, but it's server side and I have a lot of requests so I fear that the server can get too overloaded
Cookie - easy to implement and it's client side, but some users have cookies disabled in their browser
QueryString - not so easy to implement in this phase, but it's client side and can be easily tested because the application has only 3 forms (3 URLs to add query string parameters)
I'd like to hear your ideas and suggestions.
Thank you in advance!
Actual persistence store would actually depend upon the scope/life-time of culture selection. For example, if it's user specific selection that has to be persisted over sessions then you can use database or persistent cookie where cookie will remember for a machine and database will remember across machines. The retrieval (from database) will happen when it's needed - and the value can be cached into ASP.NET cache (will need different key per user) or session or view-state (if its single page application) etc.
You shouldn't worry too much about putting that into session if you are already using session state for something else. In such case, it doesn't really consume any significant memory. If you have log out function then you can explicitly clear the session state and release that little bit of memory. If you don't have log out functionality then you can use small value for session timeout.
I have a need to bring some role based content (several pieces resulting into one object) from the database to a service layer. Access to each content piece will depend on the role that the user has. If the user role has no access to a piece, that one will be empty. This is not a huge application, just a web service method exposing some content based on roles.
I could do this in three ways.
1) Based on the user role, make database calls for each piece of content.
Pros - The roles are managed in the code thus helping business logic (?) stay in the code. Only brings back data that is needed.
Cons - Multiple db calls. Code needs to be modified when a new role is added. (unless some really complicated business logic is used.)
2) Make a single db call and bring back all the content pieces as separate results sets. Loop through the sets and obtain pieces based on the user role.
Pros - Single db call. Roles are managed within the code.
Cons - Code needs to be modified for new roles. Extra data is brought back though it may not be needed. Those unneeded queries can add a couple of seconds.
3) Send the roles to the db and get each piece based on the role access.
Pros - single db call. Only brings back what is needed. No need to change code for new roles as only stored procedure needs to change.
Cons - Business logic in the database?
It looks to me that #3 > #2 > #1. (overriden > to mean better than)
Does anyone have any insights into which approach may be better?
Update -based on some comments, some more details are below.
User role is obtained from another system. #3 would ideally pass it to the db, and in crude terms for the db, return data as- if user_role ="admin", get all pieces, for "editor" get content pieces 1,3 and 55. Again, this is not a big application where the role management is done in the db. Its a web service method to expose some data for several companies.
We obviously cannot use this model for managing the roles across an application. But for a method level access control as in this scenario, I believe #3 is the best way. Since the roles come from another system than where the content resides, the logic to control access to different content pieces has to reside somewhere. The database looks like the right place to have a maintainable,scalable, less hassle solution in this particular scenario. Perhaps, even create a look up table in the content db to hold roles and content piece access to give a sense of "data" and "logic" separation, rather than having a udf to perform the logic.
If no one can think of a valid case against #3, I think I'll go ahead with it.
I would always pick option 3 and enforce it in the database itself.
Security is best handled at the closest point to the actual data itself for a lot of reasons. Look at it this way: It is more common for an additional application to be added in a different language than it is to toss a database model. When this happens all of your role handling code would have to be duplicated.
Or let's say the application is completely bypassed during a hack. The database should still enforce it's security.
Finally, although people like separating "business logic" from their data, the reality is that most data has no meaning without said logic. Further "security logic" isn't the same thing as regular "business logic" anyway. It is there to protect you and your clients. But that's my $0.02.
Looking at your other options:
2) You are sending too much data back to the client. This is both a security and performance no no. What if your app isn't the one making the data request? What if you have a slight bug in your app that shows too much to the user?
1 and 2) Both require redeploy for even slight logic changes (such as fixing the mythical bug above). This might not be desired. Personally, I prefer making minor adjustments to stored procedures over redeploying code. On a sizeable enough project it might be difficult to know exactly what all is being deployed and just generally has a higher potential of problems.
UPDATE
Based on your additional info, I still suggest sticking with #3.
It depends on how your database is structured.
If you can manage access rights in the database, you might have a table design along the lines of
Content Table
ContentId Content
Role Table
RoleID RoleName
ContentAccess Table
ContentID RoleID
Then passing in the role as a query parameter is absolutely not "business logic in the database". You would obviously write a query to join the "content" and "contentaccess" tables to retrieve those rows in the content table where there's a matching record in ContentAccess for the current user's role.
If your application uses code to determine if a user is allowed to see a specific piece of content, that doesn't work. The crudest example of this would be "if user_role = "admin" then get all content, if user_role = "editor" get items 1, 3 and 55". I'd argue that this is not really a maintainable design - but you say the application is not really that big to begin with, so it might not be a huge deal.
Ideally, I'd want to refactor the application to "manage access rights as data, not code", because you do mention maintainability as a requirement.
If you don't want to do that, option 1 is the way to go; you could perhaps refine it to an "in" query, rather than multiple different queries. So, you run whatever logic determines whether a user role can see the content, and then execute a query along the lines of "select * from content where content_id in (1, 3, 55)".
Different people have different feelings about stored procedures; my view is to avoid using stored procedures unless you have a proven, measurable performance requirement that can only be met by using stored procedures. They are hard to test, hard to debug, it's relatively rare to find developers who are great at both Transact SQL and C# (or whatever), and version control etc. is usually a pain.
How many new roles per year do you anticipate? If few roles, then stick everything in code if it makes the code simpler. If a lot, use option #3.
If you really dislike multiple calls, you can always do a SELECT ... UNION or defer the retrieval to a simple stored procedure.
Alternatively, consider just getting one of myriad RBAC frameworks and let it take care of the problem.