Ok, I'm new to web development, so I might be getting some of these terms wrong. I apologize in advance.
I am having trouble understanding the different elements of authentication. Every method seems to be advised against by someone, though not always with clear reasons. I am building a web app for a company that will have access to a database, so I would like to make sure it is secure.
So the there are three places I have seen commonly used to store information.
FormsAuthentication.SetAuthCookie(). This stores a session cookie that will exprire with the browser, and nothing sensitive is on the client. However, it can only store one value. This stackoverflow answer shows a method of storing multiple values here, but the guy who gives it says not to use it, though not why.
FormsAuthenticationTicket. I don't know where this information is stored, but it allows for a simple method of storing multiple values. Securing it, according to the documentation requires calling Encrpty() to store, and decrypt() to retrieve. This seems wasteful, but what do I know.
Session["SomeRef"] = new CustomObject(). The second answer in this question explains how to do this, but a comment to it calls it dangerous because it can be stolen. This looks like the best method to me, because the information is still stored on the server, and can store multiple values.
I cannot find any comparisons for these methods, or good explanations on the "best practice" way of storing multiple pieces of information after authenticating a user. The information is just the User's name and their userId.
Here is some further clarification to help you decide.
SetAuthCookie can be implemented in a way to store multiple values. In practice, however, you usually can't store enough to avoid a database lookup. It's best to store the user name (unique identifier) and load more information during the request. As your question suggests, you shouldn't store sensitive information on it. You should assume that all information sent in a cookie can be decrypted and read and you should take precautions that that information can't be used maliciously. All session cookies can be stolen and I'll explain why in a moment.
FormsAuthenticationTicket is the same API as SetAuthCookie but at a lower level in the Framework. With SetAuthCookie, Encrypt() and Decrypt() should be happening anyway (it's the default configuration.) It's not wasteful but use method 1 instead because it's easier.
Session has some limitations. Notably, by default it's process-dependent. That means that when the server restarts or more than one web server is involved, your session is lost and you have to authenticate again. It is the easiest to use and fastest when using the default memory session storage (InProc). You can use sql storage or a dedicated session server to overcome the process-dependency.
All three methods are considered dangerous for the same reason all cookie-based authentication systems are dangerous: because the cookie's value can be sniffed over wireless and reused to take over a session. This is known as sidejacking and it also applies to scenarios 1 and 2. The way to prevent this is to implement HTTPS. Then, the cookie transimission (and everything else) is encrypted at the network level and can't be stolen.
TLDR; Use SetAuthCookie and HTTPS
NOTE this answer has been edited several times for clarity.
Related
I manage a couple of older webapps that at some point have been converted to Laravel. They both allow login via email/password combinations or FaceBook logins, using Socialite for the latter.
FaceBook has advised me I need to confirm I meet the requirements for:
[A] Enforce encryption at rest for all Platform Data storage (e.g., all database files, backups, object storage buckets)
More clarification has not been forthcoming, and FB docs for developers tend to be self-referencing without really being clear. The inference here seems to be that any data provided by FaceBook via their API must be encrypted in the DB.
This can partly be achieved through casting certain User attributes to "encrypted" and applying this to the DB fields retrospectively for existing FB and non-FB users. However I don't see any obvious way of encrypting email address and still being able to use Laravel authentication in any fairly standard way. I can see how it could be made to work, though solutions seems to be onerous and rather awkward
As I find Laravel tends to offer straightforward ways of achieving routine functionality, and I don't think providing email/password logins is especially unusual, I'm surprised to find no information at all about how to work around this.
Am I mis-understanding the requirements here? Are others in a similar position not coming across these Data Protection Assessment requirements, or are they just telling FB "sure, everything's as it should be" and applying their own standard of security to user data?
I don't think this is off-topic or too vague, but appreciate it might be. If the question stays up, any advice is welcome.
Thanks
Edit:
Moved to github Laravel discussions
https://github.com/laravel/framework/discussions/42397
If you examine firebase cms, you will understand better what you mean.
must be talking about encryption of repositories like automatic backup.
I am a relatively inexperienced programmer.
I have managed to build a web api which uses basic authentication as per the following:
https://weblog.west-wind.com/posts/2013/Apr/18/A-WebAPI-Basic-Authentication-Authorization-Filter which is working very nicely (forced over ssl obviously). Inside the OnAuthorizeUser i check the un/pw against an mssql database, via a call to an internal class called "DB" where all my database interaction occurs.
So all Controller methods are filtered by the Basic Authentication ("decorated" at the Controller level) however, access to certain Controller Methods also needs to be limited depending on the user - so there is a need to understand the user permissions. Based on my limited former ASP.NET experience I think I would have stored the relevant user details in a Session (or possibly cache) however I have so far steered clear of this based on wanting to stick to the concept of having a RESTful application etc
Rightly or wrongly, in playing around I realised I could use a private static (instance?) of my User class inside my internal DB class and populate it at the time of initial authorisation. I also added a public method (public User getThisUser()) to return the private User. From within my Controller methods I create an instance of DB and am able to check the values etc.
I was very worried that I would have issues with the "scope" of this "static" User, so to test, I created a Controller method to simply return the User information from DB.getThisUser(). In doing so I have found that I can log in as multiple different users (using different browsers concurrently for example) and each one consistently returns the correct user information (as logged in).
I'm still not entirely convinced this is "safe" however reading through the details of implementing something like ASP.NET Identity as a possible alternative makes my head spin and really seems like massive overkill in this case - I'm not using Entity Framework and after much searching I could not find a single example of NOT using an ORM (I need a solution to work with an existing DB).
Is this destined to fail? Do I go back to considering session or cache? Something else? I would really appreciate any feedback / advice on this from all of you who are more experienced than me. Thanks in advance for any help.
i think you're getting a bit confused.
an API is supposed to be stateless, meaning no session. Yes, you have a controller which translates into an endpoint.
You can hit an endpoint with all the information required to satisfy the request and this is it. Don't think of an API as an actual application where all requests are linked somehow. Instead, think of it at an application where each request is separate and can come from anywhere and any user.
How does the application know which user sent a request? Well, it doesn't unless you pass that information in.
You don't fire a request saying GetMeUserDetails. The api has no idea what you want. Instead you would say GetMeUserDetails for userId 12345. Now, since your request contains all the information required to satisfy the request, the API can now give you what you expect.
If some calls require authentication, you might use some sort of tokens to identify the user, but again, the information is passed in via the token.
You probably realize what static means and how it works. you are not going to see problems until you try to send two or more requests at the same time and then you'll realize that the first call now contains the details of the second request because well, static ...
As part of an application my users can create documents with embedded images/files/text etc. Viewing and editing this content requires the user to log in. At the moment the images and files though are delivered as permanent links so if those links are shared any non-authenticated user can access them forever.
I would like to make these files secure. My initial thought was to use the login token and user's id to check if they have access and only deliver the files if they do. But then I started working on it and it seems the most practical solution would involve generating a link that will expire at some point in the future. This doesn't remove the exposure to unauthenticated access but maybe reduces it enough.
The questions that come to mind are:
Is there a common approach or a few options on how this should be implemented?
I've seen returning urls with expiration periods used
Google docs seems to do something more sophisticated for it's embedded images but I can't tell what
Others?
Basic design points?
Pros/Cons of each?
Yes, it reduces the authenticated access to a fixed time but theoretically it provides un-authenticated access. So a security professional will claim it has no authentication. This kind of timed expiry link is usually used to safeguard against one time un-authenticated access like password reset(along with an expiring token independent from the time).
What is your goal? From whom are you trying to protect the data? Is the users who already have access to files and you want to limit providing an expiry time? From the question, you need to secure the access to the files/documents which has text and embedded images in it from everyone. You are right about the timed expiry design. It will not guarantee you authentication and integrity of the document and if it is over non-secure HTTP it will not even provide you integrity of the document from a potential adversary.
you can use cookies(secure cookie) over HTTPS. As long as the user has the non-expired cookie, allow access to the files/documents. The cookie approach needs distributed cookie management if you to host the solution in multiple boxes with a reverse proxy in-front. Though cross-site scripting is a threat but still most of major web application providers are using cookie based solutions. Please note, cookie breaks the REST nature of the web-application.
Another approach (similar to cookie) is to generate authenticated tokens tied to user/documents which has access for N number of attempts for a time period set while generating the token. This method has to be used over HTTPS to avoid un-wanted listeners.
An always changing link is very costly to manage and not scalable over time because it is too much state to manage and application crash makes it even more costly. Re-directing to authentication is a safe bet for you provided you have already cookie management in place or you have one application instance to take care of.
Or you can you HTTP digest authentication provided that your framework supports it so that you do not have to worry about the cookie-hell. Please note that you may need to write up some client-side java script based on your use case.
I haven't had to tackle a login process before so this is new territory for me and all I seem to be finding on Google are conflicting methods of handling this process, so I was hoping someone could help clarify.
So far I have a salted SHA1 hash made from mixing username, password and my salt variable.
When the user logs in their credentials get hashed, then this hash gets sent to sql and if found comes back with a UserID (or something). So I know they are authenticated.
With that I can handle their session with session variables.
Is that right so-far?
Anyway, I wanted to have the option of "remember me" and was looking at storing something in a cookie but am not sure what to put in there as, as-far-as I am aware storing the hash would be pretty much the same as putting their username & password in plain text.
I'm confused, can anyone shed some light?
Thanks in advance
You are usually better off using the authentication methods provided by your platform than creating one yourself. There are a lot of non-obvious problems that you can easily leave yourself open to. Which platform are you using? Are you using a web framework?
General purpose hashes like SHA1 are inappropriate for password hashing as they are optimised to be very quick, when you want something that is very slow. For discussion of this, see How To Safely Store A Password.
Anyway, I wanted to have the option of "remember me" and was looking at storing something in a cookie but am not sure what to put in there as, as-far-as I am aware storing the hash would be pretty much the same as putting their username & password in plain text.
Hashes are designed to be one-way functions, so no, it isn't the same as putting their username and password in plain text. However if you do it that way, you'll have to create a way of letting somebody authenticate with the hash instead of their username and password, and that is the same as storing their username and password on the client (as far as you are concerned, anyway).
I like the fact that you have used salt for your hashing but I don't think it's necessary to use the username for hashing only password+salt should be enough. Specially it will inflict an overhead of rehashing if you want the option of changeable usernames for your system.
For remember me option, I don't think you should store any credentials at client side cookies. Only the session ID should be enough. If you want to make it really secure you should use client-side certificates that are issued by the server.
http://it.toolbox.com/blogs/securitymonkey/howto-securing-a-website-with-client-ssl-certificates-11500
Your first login process is correct and up to todays security standards with the only exception that you may want to choose another hashing function over sha1.
Sha1 is very quick and therefore brute force attacks to crack a hash are faster. So if your hashes (database) and token (source code) get leaked, the passwords can be cracked.
One countermesure is to use a slower hashing function (see Jims answer for an article about that)
But the best of course would be not to leak your hashes in the first time.
A possibility for the remember me function is to let the user keep the session cookie for longer. For example Magento and Zend Auth does this.
This is however very ugly because you are likely to get hundrets of thousands of sessions stored on your servers, even for users that never return.
The far more elegant way is to store this information client side.
Sidenote: Of course you shouldnt put too many cookies on the client because they get transmitted with every page request. But a login cookie is a very valid case to do so. A good practice is to store the login cookie at the client side and populate the server session with data saved in a database at login which is marked in a session. This way you eliminiate continous database requests and have a good user data registry. Of course write has to be done to the database and session directly or better to the database and then somehow flushed to the application (full or incrementally).
Putting the hash in a client cookie isnt like "plaintext". However its ugly and awful and insecure on many levels.
There are some different approaches but they mostly involve some hashing again.
The most common and easy one is something like to put a cookie with user_id=john and user_token=HASH($userid.$appsecret) on the client. Or to store them as one in one cookie.
This is kinda secure but I prefer the following method:
Generate a string that holds:
userid ; user agent ; first two ip segments ; current timestamp ; your application secret token
Run it through a good hashing function and store a cookie at the users client that looks like
auth=userid;timestamp;hash-of-the-above
When the client logs in via cookie you re construct taht string from above but take the timestamp and user id from the cookie. Generate the hash and see if it matches. Then you have validated that it is the cookie you generated for that ip adress segment and this user agent at the specified time
Sidenote: first two ip segments rarely changes with dynamic isps. you can leave them away too, its for extra security.
What is the main advantage of thsi method?
The client or you can invalidate all login cookies by setting a timestamp. Only cookise that have been generated afterwards are accepted. You can also implement a timeout.
This is good if you want to "remote logout" form a public computer where you forgot to log out or something.
I think functionality is very important and with this method you dont have to keep track of single login cookies (like google does).
Hope this helps you.
You can scale this method to any level of security you like and adjust it to your needs.
your authentication is just fine. If you want to make it even more secure you could transmit the login information with a SSL encrypted connection so nobody can read what's going across the network.
The remember token is quite simple let's say you want a remember me function that is valid for 14 Days.
A stranger with no authenticated session comes to your site:
Check if there is a remember me token in a cookie
If yes, check if you can find this remember me token in your database and check if the "valid until" column is still valid (date comparison)
If you find a valid token you can set the user id and authenticate his session
If you don't find a valid token redirect the user to the login page if necessary
When the user fills out the login form and authenticates him sucessfully:
Generate a token using an appropriate hashing function. The token you hash could look like "[Timestamp]---[userpwd]" so it's (almost) definitely unique! Save the token and the date until the token is valid (+14 Days from now as example) to your database connected with the user's id. If there's an expired token, replace it because you don't need to store expired tokens.
If the user logs out by clicking the logout button or similar just delete the token record in your database and the user's cookie.
That's it!
If your platform (web server etc) supports HTTP digest authentication, i would strongly advise you to use it. It was designed by people who know more about security than either of us ever will. It doesn't send passwords over the network. It is supported by all modern web browsers, including mobile devices. If the browser has the password stored, it happens transparently during connection, giving you the 'remember me' functionality without needing to go anywhere near a cookie.
The only thing it doesn't do is let you use a nice form - the use will get a dialog box from their browser to log in.
I can't imagine that there doesn't exist an efficient, lightweight, secure authentication and authorization library for ASP.NET applications that is easy to use in e.g. your controllers and views. I read tons of articles and I performed a zillion searches, but did not find one yet. Does anyone know of such a library? Or did anyone create one himself and is willing to share?
The ASP.NET authentication system is mainly based on the Username rather than on UserId. I really don't understand that. Imagine you want to create a blog with comments. A user can register and post a comment. Two well-known MVC examples (Nerddinner and MVC Music Store) use the default asp.net authentication system (membershipprovider / identy / principal etc.) and use the Username to store the user that belongs to some object, e.g. "HostedBy"-field.
To me, this seems not a very good practice:
It's not possible to change username without having to change all the related records.
Why not us an int as Id? You need just 8 bytes to store 16 million users. Unless you limit the username to 8 byte-characters, it is less efficient in terms of storage space.
A string-based relationship seems not very efficient, as string based lookups are slower than integer based lookups.
Oke, I can imagine why you want to use a Guid and not an int, because that is virtually impossible to guess and to remember and that could increase security in some way; if that's the reason, that's fine to me.
But, then remains the question why the IIdentity interface makes just the Username available and NOT the UserId. If you use the UserId as foreign key, it's hard to e.g. fetch a list of all the posts of the current logged in user: you always need a database lookup to fetch the UserId that belongs to the username.
Another thing I wonder about is that the authentication system seems rather bloated. My best guess is that at at most 90% of the users will use an authentication system for just one application. So, why create default functionality to make it capable of serving multiple applications? (the application column in aspnet_Users).
If you don't care about these things, it's might be allright, but, I want to prepare for 16+ million users, don't you? Or, I want to server my pages under 50ms... So.. why the heck did Microsoft build the default authentication system this way? It seems pretty bloated and crappy to me.
A related question (which doesn't give answer to mine):
How can I access UserId in ASP.NET Membership without using Membership.GetUser()?
OK, you dislike the ASP.NET Membership Provider. If you're an NHibernate shop, then you could take a look at Rhino Security by Ayende Rahien.