What we have currently implemented works well but I'm just concerned that there maybe a better way or we are doing it completely wrong.
Once logged into our website, on each and every request it will make a request to the API to get the users details.
E.g. Username, ImageUrl, Roles / Permissions, Email Address etc
It then stores this data in the BaseController for the viewpage or anyone else to see during that request.
Upside:
to doing it this way is that you know each request that the users permissions/roles and their details are all up to date!
Downside:
Your most likely to get exactly the same data every request, until that one day they change their details. Thus your possibly making unnecessary calls??
However the first way we tried all this was when the user logged in all their data gets stored in the cookie, the problem with this is that our users hardly ever logout so all the data that is stored in the cookie gets stale often. -> Stale Roles/Permissions is an annoying issue!!!
How does everyone get around the stale data from login.
I would go back to your initial approach of storing the claims inside the cookie.
If you do indeed have very long log in times then I would guard against stagnant claims by periodically refreshing the cookie.
If you are using forms authentication then you could intercept the FormsAuthentication_OnAuthenticate event in Global.asax, decrypt and manage the cookie (here), validate the user and cookie first then run a quick conditional check against a custom field in the userdata property, called refreshedDate.
If the last refresh date or creation date is greater than some configurable window then call to the database and refresh the claim data from the database. Finally update the refreshDate and claim data and update the cookie.
Update
Following on from your comment...
Just to say that it is not uncommon to hit the database for each request, that is to say I have known it happen in a number of production systems. Many people are probably using ASP.NET session state using MS-SQL database's. Typically I have seen it when there is a real security need to invalidate someone's session, deny access and log them out immediately.
If your database is on the network locally to your web servers and/or latency is acceptably low then it can be a perfectly workable solution. Just make sure your database queries are minimal and performance tuned to perfection, consider side steeping any ORM (if applicable) and use raw SQL connections to make things as fast a possible.
If database latency is high, the other middle ground solution is caching, using Redis or Memcached to house the results of your queries and invalidating the cache when permissions are altered etc... but obviously adding the required infrastructure and operational support for caching solutions is a serious consideration.
You can apply an expiration to the cookie; that way it dies and requires them to login. Or, keep their user ID in the cookie, but store their profile info in session. When session dies, the next time the profile is checked if it is null, make a query to the API again. This way, it's getting updated more frequently.
In addition to other suggestions, another option may be to use a notification mechanism from the underlying role/permission store whenever a user's data changes. This notification could then be used to invalidate the cached data on the web server. This would ensure that the cached data is returned in the majority cases but the store would then be hit only when the data had changed.
If the underlying datastore is SQL Serevr then consider something like SqlDependency.
This is obviously a more complex architecture but it would meet your requirement and only you could say whether it's worth the effort / complexity / tradeoff!
Related
i've read all the tutorials and questions asked about the subject but they contradict one another
claims(userclaims and roleclaims) are serialised into a cookie (along with custom identity user properties you specify by overriding the principle factory) but they don't get queried, they're stored in a cookie, which mean that the more claims a user have, the more data will have to round trip between the server and browser
a custom identity user property by default don't get serialised but get queried from the database, so every time you need that data it query it from the database which is more work to do on the database on each request if you frequently query for it
so which is more efficient and which is safer
for instance
IsAdmin should be a role/claim? but then if someone stole the cookie, nah nah, the cookie already contains userid/username/securitystamp, so even if it's a property, the userid on the stolen cookie would query on the custom identity user property, or is there something that will prevent this cookie from working when stolen ?
another instance
if i've 20 property for the user (first name, last name, address 1, address 2, postal code, whatever the case may be), should i simply have the user wait a bit for a bigger slower cookie to be send back and forth or should i do all the work from the db using custom identity user
but then, if i remove or add a claim to the user, would it be updated on the next request if it doesn't get queried or is the security stamp validate that this cookie is still valid ?
cause at the Task AddClaimsAsync of the userstore of efcore it only add the claim to the dbset
i apologize i know this is many questions to ask but the resources on the matter are not that good and one can easily get lost reading the identity source
Rule of thumb - put frequently added items as a claim, everything else can live in DB and be queried on demand. I.e. address 1, address 2 can't be required on every request, so keep them in the DB.
On the other hand IsAdmin (should be a role anyway) I can imagine will be checked on every request, so it should be in the cookie without having to query the db.
If you afraid of your cookies getting stolen, don't show them to anyone! set up SecurityStampValidator to do frequent checks - like every 5 minutes. This basically updates the cookie with the fresh information from your database and changes the cookie. So even if the cookie is stolen, it will only work for 5 minutes.
I don't think the two statements contradict, it depends on your configuration. The second statement mentions "by default".
You do not need to store all information in claims nor do you need all the information all the time. If you want profile information, call the server once and store the information on the client, or get it when needed only.
The same counts for authorization, in case you want to show / hide elements based on permissions. This may include a tag called "IsAdmin". Authorization should be kept close to the resource.
If your client wants to refresh the information, just call the server. Claims are not updated during each request. In general, the user has to log out and log in again. So Claims are not flexible and therefor not really suitable for properties that can change (frequently).
As for safety, it doesn't really matter that the client can alter the information, it is for display only. It doesn't change the permission in the backend.
You can consider to add something like a display name to the properties, if you are showing that in every page. You can also consider to implement caching to limit database calls. In the end it really depends on your requirements.
As for stolen cookie, you'll need to implement additional security to your server to detect suspicious behaviour. You may want to include the ip address as claim. As for the admin, add security, e.g. filter by ip address and / or use an additional code which was send by email.
This question applies to both ASP.NET webforms and MVC apps. I have a checkout process where there are two forms Form A (address page) and Form B (shopping cart page). The normal happy path works where the customer completes the Form A and then click submit button which takes him to the Form B.
The customer can accidently visit the Form B without ever visiting the Form A or completing the information. How can I find out whether the customer has completed the Form A if he access the Form B directly? If he has not completed the Form A, I want to redirect him to Form A. Is there a ASP.NET framework object that I can use for this purpose?
The only foolproof way is to save something to a database that indicates that the particular user has completed Form A. This could be actually storing some entity that is created by Form A or just some sort of log. The key is that you'll need to associate with the user, which means the "user" must actually have an account and be logged in. If it's anonymous, there won't be any real way to track them.
With this set up, then, you'd simply check in your database that the user has a record indicating they've completed Form A in the controller action for Form B. If nothing exists, you redirect the user to Form A. Otherwise, you allow them to view Form B.
And alternate approach is to use Session or set a cookie to indicate that Form A has been completed. There's pros and cons to both of these, and neither is foolproof. With both Session and a cookie you can track anonymous users, so you don't have to force a login. However, Session is not a permanent data store. By default, it will expire after 20 minutes of no activity, and even if you bump that timeout up significantly, it's always going to be finite.
Additionally, depending on the session store you use, it can also be very volatile. In Proc is the default, as it requires no configuration. Everything is stored in memory, but if the server restarts, App Pool recycles, etc. then all the session data is lost. It is possible to configure it to use something like SQL Server, though, and that would be very stable. Either way, you'd still have the timeout issue to deal with.
With cookies, you can set a far-future expires cookie that would effectively be permanent. However, cookies are stored client-side and can be removed by the user. They can also be manipulated (either created manually or modified). This means if a malicious user figured out how you were tracking whether Form A had been completed, they could basically fake that, and make your site think they had completed Form A, when they had actually not. Now, whether any one would care enough to do that is an entirely different matter. Still, it's something to consider.
Finally, both Session and cookies can effectively be disabled by the user. Session actually uses a cookie to store the session id, so if the user disables cookies in their browser, neither approach will then work.
Your best bet is still forcing a login and storing something in a database to indicate that Form A has been completed by that authenticated user. However, if you can deal with or mitigate the downsides of using Session or cookies, then those might be viable options.
we have a asp.net application which use session (in-proc) for single user across pages, now they want to keep the data (eg. a shopping cart) more persistent, even they leave the web app, means close the browser, next time they login use same id, they want the data back, any solution in ASP.NET?
If we save session in sql-server which I think is an option by microsoft, but I am not sure if it works even after user leave the app, or close the browser
Session data is meant to only persist for the lifetime of that browser session.
The answer is to not save the data in session, save it in the database in ShoppingCart and ShoppingCartItem tables instead. These will persist as long as you want them to.
The ShoppingCart table would have a UserID column that is FK to your User table.
You'll need to construct a relational database and store the entries in there.
Granted, the Application scope is higher than Session, but it will only exist for the life of the application pool. It sounds like you're looking for permanent storage.
I've seen shopping cart system using cookies instead and some using both cookies and database.
Cookie only: The "official" size of a cookie is 4K
Cookie + database: Store a GUID in the cookie and use it as a reference in the database
But... I think that storing shopping cart in a cookie or a cookie/database is not very user friendly. I do prefer that the website forget my shopping cart if I leave. I'm annoyed when website store such information with my approval.
You will need to use a database to mirror the data contained in the session, that way the data will persist long after the user logs off, if the application is restarted, or if the server is restarted. You could save the session object into sql-server as a binary object and serialize/deserialize when needed, but how do you know when to do the initial serialization? It's hard to tell when a user has logged off if they close the browser window.
Storing the session object as a single column might work in the interim, but in the long run you will probably want to come up with a proper relational design and store data in columns in tables, that way you can run queries and reports against the "work-in-progress" shopping carts (such as: how long do people let a shopping cart sit before finally checking out?).
As others have mentioned, cookies are another option but those exist on the client side, and if they decide to clear cookies (a lot of tech support people seem to give this advice as the first response when users complain about slow browsers), the shopping cart is lost.
I think, in almost all cases user preference data may be stored in a cookie with (almost) equally good results as when the User Profile API is used. Disadvantages of using cookies (for authenticated users) seem to be that a cookie can be deleted or time-out, in which case the user preference data will be lost. For anonymous users, if the preferences data needs to be persisted across sessions then a cookie will have to be used even when User Profiles are used.
So what are some of the biggest advantages/disadvanges of using either User Profiles or cookies for storing user preferences?
One of the benefits of registering on a site is that it remembers my preferences - if you're storing that information in a cookie on my machine instead of on your server then when I log into your site from another computer, I've got to set all my preferences up again - from a usability point of view, this is fairly bad.
For an anonymous user, storing the prefs in a cookie may seem fairly sensible - you don't know who they are, or whether they will comeback, and as you state, you can't work out from one session to the next who they are - however you'd probably be better off storing some sort of token in the cookie and mapping that to a preferences store on the server.
Also, I've noticed different browsers have different implementations for cookies - for example IE can now receive 50 cookies from one domain (up from the original 20), but it is still limited to a total of 4096 bytes for the entire cookie collection (and previous) - other browsers will support 4KB per cookie, rather than per domain.
Another disadvantage to holding all the preference data in cookies is that all of that data will have to be sent in every request from the client and in any response from the server whenever a change to the data is made. Whilst this may seem like a minor point in the age of broadband it is still an additional overhead. Using the Profiles API meands that the data is held at the server and only a session identification cookie needs to be sent by the browser.
Also, as you stated, for anonymous users if cookies are deleted then the user preferences held in the Profiles DB will no longer be accessible. However this will not be the case with registered users of your website. If they remove their cookies the server will still be able to retrieve their user preferences the next time they log in.
Cookies are limited in maximum length and they are using an implementation beyond of your control (after all, they are a feature of your visitors browser). Personally, I dislike relying on unknown third-party implementations I don't have any control over and if I have to, I'm trying to use it in the simplest way possible.
So from where I'm coming from, I would always store the user data on the server and just pass around a cookie pointing to that information.
Aside of not trusting the browser with a potentially big chunk of data (which may be lost, incorrectly stored or not stored at all depending on not only the browser but also, say, some antivirus application or whatever), this has various other advantages:
You are hiding your implementation from the user: If you store the data in the cookie, it's visible for anybody and can be analyzed or modified at will. This can even lead to users changing cookies to there liking and thus force you into keeping stuff around you probably want to get rid of just because some users are depending on your particular implementation at any time.
As cookies are stored in plain text, on shared machines, everybody can no longer easily see all the settings the previous user made, nor change them at will.
But the most important point remains the disconnect from not-quite-working browser implementations (just storing small tokens is the common, tested use-case)
Don't forget that one of the biggest disadvantages of using cookies is that they can be copied, so its dangerous to store authentication info on them.
I'm not familiar with User Profile API but I'm guessing it stores the information on the server(?). If thats the case then you could have a problem if you have to many users.
Overall maybe the best solution is to use User Profile if it guarantees the persistence of the information.
Keep in mind that its possible to write a ProfileProvider that persists user data in a cookie, so you can have the best of both worlds if you determine the state you want to persist is appropriate for cookies (size, security, etc).
Actually, you do not need to persist preference data in cookies for anonymous users when using the ASP.NET Profile Provider. Simply store the current UserID (which is some horrible looking session-related string) in a cookie. This becomes the previous UserID on subsequent visits, and then you can just grab the old Profile information and migrate it to the current Profile, or even authenticate them as that old anonymous Profile.
I've got an existing site I'm taking over, and right now it stores, in a session variable, the id of the currently logged in user (if logged in at all -- otherwise I'm sure it is empty string or null or something).
The client now wants, after someone is logged in, to "keep" them logged in on that computer for an indefinite amount of time.
ASP.net Sessions have a maximum idle time of 1 day, I believe. The website isn't written all that well in the Flash portion (whole front end is flash) and the flash will process a login, then, as long as the flash isn't reloaded, assume that the user is still "logged in".
I think my solution is to ALSO store a client side cookie with some GUID value and hold in the database the associated user id...sort of like a session that never expires. So, when the page is loaded, I can check my cookie, use that to select the userid out of the database, and if we find one, then set the session value that says user 23 is logged in.
Does anyone see any issues with this perspective? Would you recommend something different? I really don't want to refactor a bunch of the existing code, but just slip this in on top...
PS -- security is not really a concern. The only reason they have people log in is so we can track orders by a person, but no money changes hands through this website. There is also no personal information that a user can view or edit, either.
This is how I do it. I actually have a cookie that holds their login and password, this way I can automatically log them in should they not be logged in. I expire the cookie after a couple of days of inactivity. The downside is that everyone forgets their password because the only time they really have to enter their password is when they come back from extended time-off.
This is for an internal application, with the same customer demands that you have and this works ... and makes the customer happy.
One thing we may end up doing is just using Windows authenication, might actually work better in this circumstance.
That's the way I do it, but the problem with it (at least I think its a problem) is that when you store the username and password in a cookie there is not any encrypting when you add the cookie. If you look at the cookies in your browser the username and password are displayed there plain as day. Is it possible to get some kind of encrypting on the cookies you store? Or how would you handle this?
Check this blog posting out http://timmaxey.net/archive/2009/03/06/asp.net-cookie-auto-log-in.aspx basically you needs to save the cookie with a guid a series, and a token, the token, in my case, changes all the time, the series is something that is generated based on something, like the guid and id combo or whatever, then the guid is always stored with the user. There is a cookie table to stored this info etc... pretty secure, not 100%, but pretty good... Tim Maxey
I recommend using the Enterprise Library Crypto App Block to store an encrypted cookie which is nothing more than a GUID. Get the GUID, and use a session table in the database to track user info.
At the session start event, get the user info and cache it.
Using the session object is not recommend for user info because it won't work on a web farm, unless you use a database for session state.
You're basically rolling your own session state at that point, and I'm fine with that. However, I would not go the route of storing the username/password in a cookie (even if encrypted). There's no way to expire that from the server-side. You can always remove your row in the table to force a user to log in again, but if they hold the username/password they hold the keys to the kingdom.