I'm trying to think out my user authentication system for a site in development and have read many of the posts on stack overflow and elsewhere to get my head around this. I found a couple of options I was wondering if this one looks like a decent starting point:
http://php.about.com/od/finishedphp1/ss/php_login_code_6.htm
It appears to encrypt the passwords and avoid some of the obvious pitfalls.
Also, perhaps a silly question, but I want to use the authentication for 2 reasons:
1. To provide the user with some extra functionality on an otherwise public page. (Think "Hello [username]" at the top of the page).
2. Provide user access to private pages also.
These 2 types of applications (login = added stuff on public page versus login=access to private page) are reliant on the same authentication, right?
In other words, whether I wanted to do one or the other or both shouldnt' impact how I think about authentication, correct?
Please let me know if I'm asking for trouble by using an about.com tutorial for this....
Thanks in advance.
FOLLOW UP EDIT:
Ok, so the about.com tutorial has some holes. I found a more complete system below that appears to use SHA1 encryption instead. This also has an email verification for new users and some other nice functionality. At first glance, does this seem like a solid route to take?
http://www.unlimitedtree.com/topic/1503-tutadvanced-login-member-system-php-tutorial/
Yes, you are asking for trouble. There are several reasons why I would avoid the about.com approach:
User name and password are stored on the client side. You'll never want to do that. First: if a malicious attacker gets access to the cookie, he can use the id and password hash to take over the account. Second: there are huge data sets out in the wild called rainbow tables which allow malicious attackers to find out which string (= password) results in the given hash. This means that if you don't have a long/complicated password, someone may use the rainbow tables to get you clear text password and try it on this and other websites you are registered to.
The variable $username is used unchecked and unfiltered. Hello SQL Injection.
The password is encrypted using a simple md5() function. MD5 puts you at the risk of hash collisions. Nowadays you should use better hash functions like SHA-1 and use salt.
Security is a complex topic. I recommend you to use well tested authentication and authorization solutions as provided by established frameworks. Also think about OpenID.
A few PHP frameworks and their auth components:
Apache Zeta Components (former eZ Components): Authentication
CakePHP: Authentication and Authorization
FLOW3: Security (Authentication and Authorization)
Symfony: Security (Authentication and Authorization)
Zend Framework: Zend_Auth and Zend_Acl
Concerning your question:
In other words, whether I wanted to do one or the other or both shouldnt' impact how I think about authentication, correct?
Yes. You have to differentiate between Authentication and Authorization. The former helps you to identify who the user is and the latter helps you to find out what the user is allowed to do. Read this short introduction to learn about the topic.
Related
I was thinking of writing my own authentication script but I don't know much about security.
From the articles I've reading, it looks like it usually involves hashing the password with a salt and storing it in the database. Then when user requests to log in, password is hashed and compared with the database. If it matches, then the user's data is stored in $_SESSION.
However, I don't know if this is secure or not. I read something about storing session keys in the database but I'm not sure about how that works, or how to implement that.
Can someone explain how to implement secure authentication?
Also, are there any suggestions for PHP authentication libraries I can incorporate that are easy to learn instead of writing my own?
Check this answer here.
Although the answer is 3 years old, the suggested phpass library is up to date.
Also, +1 to Aron Cederholm. Password security is an extensive subject and you should look first at the related questions already discussed here on StackOverflow so you will be more familiar with the subject and best practices in security.
Although I like frameworks (Symfony, Zend, etc) as they generally implement these good practices, just using them don't make you a good programmer. You have to learn its inner workings. I always salute a programmer dwelving into coding his own secure authentication mechanism (as long as they don't implement it in a live site that really needs strong security), because that's the best way to learn and understand the inners of the subject. Always start from an existing implementation, and THEN use that as an example for creating your own codebase.
Things to keep in mind:
Authentication; verifying the user is who they say they are.
Authorization; ensuring the user is allowed to do what they are trying to.
Accounting; recording and auditing what they do.
For authentication, you'll need to track "users" connected to and (often) authenticated with the system. This requires knowing an identifier (a username, email, or some other unique token) and a pass-phrase. Store the username and pass-phrase somewhere, but never store the pass-phrase without securing it first: don't use a message digest algorithm (like MD5 or SHA1) with a salt. Use bcrypt instead. Although it's not a bad idea to use a framework here, do not always rely on a framework to do the right thing.
For authorization, you'll need to track what actions the user is taking and perform permission checks to see if they are allowed to do the action they are attempting. This can be accomplished in a number of different ways and all of them are domain specific -- you won't often find a cut-n-dried example of it, though you can find lots of frameworks to help you.
For accounting, you need to record what actions the user does. This is the most often neglected part of any application, but when bad things happen, it's utterly crucial knowledge to have and reconstructing it from web server access logs is a nightmare. Again, this is domain specific but a good framework should ease the implementation of it.
Lastly, tying all three of these together is your user's session. When you call 'session_start()' in PHP, it sends a session identifier as a cookie to the client and stores a file to the server's hard drive containing the contents of $_SESSION for that user. You can also configure PHP to override the default functionality and save session data using session_set_save_handler. You can then store that information to the database.
TL;DR: Use a framework like CodeIgniter, Drupal, Yii or some other actively developed solution. The vast majority of frameworks out there will do just about anything you need them to, and if they don't, they can be modified very easily. Don't create your own framework for this; use one that is already available.
I use tank_auth (a Codeigniter plugin) which is pretty good. The source code is a good reference for how to implement secure login.
I'm currently consider to implement a login system by using php+mysql, it haven't got any major problem.
However, I've notice that, more and more site currently not only use their own login system (actually, some of them are remove their own login system), but use different social networks login system (twitter, facebook, google...just like stackoverflow).
Can someone explain what is the pros and cons of these? And if using other login, are they grab the data from the facebook (for example with facebook login) or just use it as login, to prove someone who are a real human...?
(It is great if someone can provide some php example :) )
OpenID
stackoverflow.com uses OpenID. Jeff Atwood(Author stackoverflow) even has an article explaining why stackoverflow.com uses OpenID. But to me(also Jeff Atwood) the most important properties of these (social) logins are:
I don't have to store(probably insecure) the passwords anymore and that the user will have less identities(passwords) to remember.
Even if the password get's exposed it only has to change the password in one/that spot instead of hundred spot or it has to be smart enough to not use the same password for every site, but then it will be insane difficult to remember the passwords.
Example
For an example i would advise you to read this answer from me about OpenID.
This is a complex question. It's cumbersome to create yet another account for your visitors, for them using Janrain Engage (that's the best IMO) is way easier. But then you are looking at trust issues, using a rather complex protocol etc. On the other hand, it's becoming really cumbersome to create yet another account so please don't unless you have a checkout process where you can more easily ask for a password -- under no circumstances ask for a username though unless you really, really must, the email address should always suffice.
A new project requires a simple panel (page) for admin and staff members that:
Preferably will not use SSL or any digital ceritification stuff, a simple login from via http will just be fine.
has basic authentication which allows only admin to login as admin, and any staff member as of the group "staff". Ideally, the "credentials(username-hashedpassword pair)" will be stored in MySQL.
is simple to configure if there is a package, or the strategy is simple to code.
somewhere (PHP session?) somehow (include a script at the beginning of each page to check user group before doing anything?), it will detect any invalid user attempt to access protected page and redirect him/her to the login form.
while still keeps high quality in security, something I worry about the most.
Frankly I have little knowledge about Internet security, and how modern CMS such as WordPress/Joomla handle this.
I only have one thing in my mind: that I need to use a salt to hash the password (SHA1?) to make sure any hacker who gets the username and password pair across the net cannot use that to log into the system. And that is what the client wants to make sure.
But I am really not sure where to start, any ideas?
The use of HTTPS is an absolute requirement, and must be used for the entire life of the session. Keep in mind that session id's are used to authenticate browsers and if an attacker can obtain one (sniffing or xss), then he doesn't need a username/password. This is laid out by The OWASP Top 10 2010 A3 Broken Authentication and Session Management. If you want to implement secure session you must read that link.
md4,md5 sh0 and sha1 are all a broken message digest functions and can never be used for passwords. Any member of the sha-2 family is a good choice, sha256 is very large and is a great choice for passwords.
You should absolutely never transfer a password hash across the network or spill it to a user/attacker. If you are sending a hash to the server to authenticate then you have introduced a very serious vulnerability into your system. Using sql injection the password hash can be obtained from the database, then this hash can be simply replayed to authenticate, bypassing the need to crack the password hash. This is as if you are storing passwords in clear text.
Use the $_SESSION superglobal and session_start() to maintain your session state, never re-invent the wheal. The default PHP session handler is secure and will do what you need.
session_start();
if(!$_SESSION['logged_in']){
die("Authentication required!");
}
Also make sure to implement CSRF protection into your system. Using CSRF an attacker can access the administrative panel by forcing your browser to send requests. Make sure to test your application for XSS this is a good free xss scanner, again xss can be used to hijack an authenticated session by using XHR or by obtaining the value of document.cookie. It is also a good idea to test for SQL Injection and other vulnerabilities, wapiti will do the trick.
Not using SSL would leave a pretty substantial hole in the whole system as it is pretty easy to sniff network traffic
This has been much discussed on SO already, here are some of the useful links:
Developing a secure PHP login and authentication strategy
Login without HTTPS, how to secure?
Secure Login in PHP
How do I write/put together a secure login in PHP? The website developer guide said I shouldn't roll my own, so referring to samples available via Google is useless.
How do you pros do it? Lets say you're building a world-class app in rails, would the same libraries / techniques be usable here?
Thanks
In Rails, one would generally use a pre-existing library. Authentication is easy to do wrong, and the problem's been solved so many times that it's rarely worth the effort to solve it again. If you are interested in writing your own implementation, then I'll describe how modern authentication works.
The naive method of authenticating a user is to store their password in a database and compare it to the password the user submits. This is simple but unbelievably insecure. Anyone who can read your database can view anyone's password. Even if you put in database access controls, you (and your users) are vulnerable to anyone who hacks around them.
Proper form is to use a cryptographic hash function to process the password when it is chosen and then every time it is submitted. A good hash function is practically irreversible -- you can't take a hash and turn it back into a password. So when the user logs in, you take the submitted password, hash it, and compare it to the hash in the database. This way, you never store the password itself. On the downside, if the user forgets their password, you have to reset it rather than send it to them.
Even this, however, is vulnerable to certain attacks. If an attacker gets hold of your password hashes, and knows how you hash your passwords, then he can make a dictionary attack: he simply takes every word in the dictionary and hashes that word, keeping it with the original. This data structure is called a rainbow table. Then, if any of the dictionary word hashes match a password hash, the attacker can conclude that the password is the dictionary word that hashes to that password. In short, an attacker who can read your database can still log in to accounts with weak passwords.
The solution is that before a password is hashed, it is combined (usually concatenated or xor'd) with a value called the salt which is unique to each user. It may be randomly generated, or it may be an account creation timestamp or some such. Then, an attacker cannot use a rainbow table because every password is essentially hashed slightly differently; he would have to create a separate rainbow table for every single distinct salt (practically for each account), which would be prohibitively computationally expensive.
I will echo the advice of the other answerers: this is not simple stuff, and you don't need to do it because it's been done before, and if you do it yourself you stand a very good chance of making a mistake and inadvertently compromising your system's security. But if, for whatever reason, you really, really want to write one yourself, I hope that I have provided an (incomplete!) outline of how it's done.
The Zend Framework has an 'Auth' module which would be a good place to start. Or, if your site will be hosting an install of WordPress or PHPBB, there are ways of leveraging those technologies' authentication modules to sign in to other pages of a site.
One thing to look at when you are trying to authenticate is what is your real goal.
For example, on SO I use my google login, and that works, as they just need to know who I am, and they can trust that Google has an idea. So, if that model will work for you, then look at using OpenID, as there are various tools for that.
If you must do your own, then there will be various tests to ensure that it is secure, again, depending on how paranoid you want to be.
Never trust anything from the user, unless you have used some strict verification.
Use https to help protect the password of the user, you owe them that much.
I will end my response here as Thom did a fantastic response.
by Soulmerge:
I think the accepted answer in your other question states it pretty well. Hash the passwords with a salt. Other than that, there are some security ideas on the transport layer:
Use https when sending passwords. This makes sure nobody can catch them on the wire (man-in-the-middle attack or the client uses an evil proxy)
An alternative is to hash the password using javascript when the login form is submitted. This makes sure that the password is never transported in plaintext. You should hash the hashed value again with a salt on the server. (md5($_POST['postedPwHash'] . $salt))
a good method to somewhat secure the client-server transaction (if no ssl is available) is to use a one-time random key to create a unique hash from the credentials, then only send that unique hash to the server. the server then compares this hash to its own generated hash instead of comparing it to the real credentials. this would provide a good defense against the man-in-the-middle attack. the downside is that to do this the user must have JS enabled (at least i dont know of a good method to encrypt client-side data without it). this means that you will need a sufficient fallback when it isn't on. you can even create the form in JS to make sure its enabled.
this library is a simple library i wrote once that does the procedure i described, though it probably needs some improvements.
note that this is in addition to using "salting" methods and other server-side security measures. it is also quite vulnerable to dictionary attacks as the entire hashing process is by definition procedural, predictable and visible to the user (as JS always is).
My answer is "Don't do it"
This is a very complex area, full of potential security gotcha's. If you are not an expert in this field, then you are really just asking for trouble and problems down the road.
I would recommend looking at getting an existing solution to do. Sadly I don't know any that I would be happy to recommend, other than openid. I'm sure you will get some good suggestions here though...
I'm looking to implement user login onto my site for the first time. I'm happy to either build my own solution, or implement something open source, however no package has been an obvious choice in my search so far. Equally, I'm fully aware that as an intermediate php programmer at best, I am highly likely to miss something obvious if I roll my own solution, and leave the doors well and truly open.
Any suggestions? We're not talking super sensitive or payment data here, but equally, I'm keen not to have people mess up my site!
requirements are
- php based
- simple as possible, not need for fancy bells and whistles
- not Zend framework, since i've now rolled my own very basic frameworkthanks to this post
Thanks for your input.
A few good security gotcha's are
never store the an un-encrypted users password in the database
never store the users password or even a hash of the password in session or cookie data.
If you need to have ensure that the login is secure you have to use https.
I found these article very helpful in building login systems with cookies:
blog post on the fishbowl.
Improved Persistent Login Cookie Best Practice
"You'll put your eye out kid."
Security is hard. I hate to say this, but the odds of you making a simple authorization scheme that is secure are quite slim. There is no easy mode here. So you might want to start by reading through a bunch of authentication code in the various frameworks/cmses, and other places where you can see how others have done it, and begin researching.
Here are some links:
http://www.topmost.se/personal/articles/casual-cryptography-for-web-developers.htm
http://pear.php.net/packages.php?catpid=1
I find that for some uses, building my own using http authentication is sufficient. I'd recommend this as a starting point.
Since you have your own basic framework, it should not be too difficult to include the authentication code in some place that is common.
Some advantages are
Not a lot of code.
Does not require
cookies or URL rewriting.
Disadvantages
Doesn't scale well to more granular
access control.
No easy way to "log
out".
--
bmb
This is not that hard, and fun to code, as a beginner.
You need a place to store your data (let's say a mysql database).
You should at least have a login field, and a password field. (the password should be stored crypter using sha1() for instance).
Now, you have to display a login form. I assume this is ok for you.
What is to be done, whenever we get the login and the password?
Query the database to see wether there is a match with login_base == login_form and password_base == sha1(password_form).
If yes, you set something, like a session for instance.
So on a page where one should be logged, you only have to check if there is a session set.
This is for the basis; then you can add some levels and so on.