35 Responses to Build a secure login with Zend Framework

Avatar

Zend Framework in Action » Secure login with Zend Framework

July 4th, 2009 at 8:23 am

[...] Zimuel has posted an article on how to build a secure login with Zend Framework: After a long pause i’m come back on my blog with a post about the development of a secure web [...]

Avatar

Joe Devon

July 11th, 2009 at 9:54 am

Thanks for sharing your interesting approach and glad to have you back writing.

I wanted to add a couple points. The MD5 password field length is fixed, so char is probably more appropriate than varchar.

Re: strength of MD5:
http://it.slashdot.org/article.pl?sid=07/11/20/1914209

If you salt the MD5, then you’ve got a more secure setup. Add a column for each user and a random unique salt for each and it’s even better.

Avatar

Enrico Zimuel

July 11th, 2009 at 6:02 pm

Thank you Joe, i just updated the post with your suggestions. You are absolutely right, a random salt definitely improves the security of the MD5.

Avatar

Michael Krapf

July 15th, 2009 at 7:38 pm

Your tutorial is top notch and I appreciate the effort.

Please bear with me as I am a php novice in training.

Is it necessary to install the entire Zend backage in the library folder?

How do I add new users? I am familiar with phpMyAdmin, but if the passwords are protected from the admin, shouldn’t the user have the ability to submit their own credentials?

Any additional information for a newbie would be very helpful and appreciated.

Avatar

Enrico Zimuel

July 16th, 2009 at 10:30 am

If you want to use only some classes of the Zend Framework (ZF), without the MVC feature, you can install only these classes into the /library directory of the ZF.
Anyway my suggestion is to install all the files of the /library folder of the ZF. In this way you can use the same ZF installation for all the php applications of your server.
Related to the question on how add new users into the MySQL table ‘users’, you can use this simple query:

SET @salt=SUBSTRING(MD5(RAND()),-20);
INSERT INTO users (username,password,salt,email) VALUES (’user’,MD5(CONCAT(@salt,’password’)), @salt, ‘email’);

where ‘user’ is the username, ‘password’ is the password in plain and ‘email’ is the email address of the user.
As you can imagine there are a lot of others way to create a random salt, this one is very easy and it uses directly the MySQL engine to generate the salt.
You can create a simple php page to add a user account directly from the user subscription page (better if with SSL protection). In this way the admin of the web pages doesn’t know the password of the users.

Avatar

Stephen Karl Lang

July 16th, 2009 at 7:45 pm

Great post, Enrico. I especially appreciate how these methods can also be applied to other frameworks and/or technologies. You have a new subscriber :)

Avatar

Kalpesh

July 20th, 2009 at 10:28 am

Hi,
I like your tutorial.
I use this in my project.
I am using Model_Db_Table to access database.
To insert user name and password there is a function DbTable
called $this->insert($data);

How can i create password with md5 salt.

If you help me with this then i will be much thankful to you.

Again thanks for this tutorial.

Avatar

Enrico Zimuel

July 20th, 2009 at 11:08 am

For instance you can use this code:

Zend_Loader::loadClass(’Users’);
$user= new Users();
$salt=substr(md5(mt_rand()),0,20);
$md5Password=md5($salt.$password);
$data= array (
‘username’ => $username,
’salt’ => $salt,
‘password’ => $md5Password,
‘email’ => $email
);
if (!$user->insert($data)) {
// @todo error
}

Avatar

Kalpesh

July 27th, 2009 at 1:48 pm

Hi, thanks for your reply,
IT works
But how can i store user name in session.
I try to use Zend_Session_Namespace in submit Action before it redirects to home page

$sess = new Zend_Session_Namespace(’MyNamespace’);
$sess->username =’Kalpesh’ ;

but when i go home page i try to print session value called username.
It doesn’t print it.

Is there anothe way to store username in session.

And again thanks for reply

Avatar

Hari K T

July 27th, 2009 at 7:48 pm

Good one . Really a nice effort to help the newbie like me .
Wish u good luck .
Bye till we see for nxt post . :)

Avatar

Joe Devon

July 28th, 2009 at 5:47 pm

Something else to consider….a pagewide or sitewide salt as well (depending on the situation). The reason being, if someone breaks into your database and has the random salts that were generated and stored in the dB, he can brute force the entire database at his leisure and pull out passwords…whereas adding a pagewide-salt into the code, he’d have to break into both the database and the source code. Just an extra layer of protection.

P.S. I use Zend_Config_Ini to pull in the full form into Zend_Form, including the csrf, in a class I wrote to automate it….. Something like so:
$config = new Zend_Config_Ini(APPLICATION_PATH
. ‘/configs/’. $form . ‘.ini’
,APPLICATION_ENV);
$formConfig[$form] = new Zend_Form($config->$form);

Obviously I can’t use a function to set a random salt in the config. Is there any way of doing this as well as the ttl in the config without invoking any methods on the token as in your code above?

Also, you’re time to live is set to 60. Is that minutes?! The ttl in my forms seem pretty short. Maybe I should increase it too. I wonder what the default is.

Avatar

David

August 3rd, 2009 at 8:39 am

Excellent tutorial, especially for a ZF noob like me. Very helpful, thanks.

Avatar

Justin Hendrickson

August 26th, 2009 at 2:59 pm

One quick pet peeve correction:
uniqid() creates a unique identifier. Hashing that value with md5() makes it “less unique”. http://us.php.net/manual/en/function.uniqid.php#91126

Avatar

Enrico Zimuel

August 26th, 2009 at 6:48 pm

Thanks for your suggestion. I read only the first part of the php manual where is written that md5(uniqid(mt_rand(), true)); is better because difficult to guess. Using the md5 function there is a probability (very low) to generate the same output from different inputs.

Avatar

Anurag Jain

August 28th, 2009 at 11:36 am

Hello ,
Let me go straight.

Will this work on 1.9, if no then what are the possible changes?

Anurag

Avatar

Enrico Zimuel

August 31st, 2009 at 5:29 pm

I just tried with the last version 1.9.2 of the Zend Framework and it works fine.

Avatar

Fozzy

September 29th, 2009 at 3:34 pm

Hey,

I just stumbled up on your tutorial. Thanks for taking the time to write it.

One quick question, is it safe to separate the salt from the password? Most security stuff I have seen mentions prepend/append the salt to the password or some cleaver similar thing.

However, I don’t see how one could make an easy SQL statement that would work in this fashion, so I would guess a custom auth_adaptor would be needed.

Curious as to there being any real reason do combine the salt with the password? Of if it’s doesn’t really provide any more security as someone who could hack your DB prob. hacked your source code and could figure out the salt, either way?

Avatar

Chris UK

September 30th, 2009 at 11:02 am

Finally a Auth example app that works for Zend Framework 1.9!! Thank you so much.

Avatar

01kuzma

September 30th, 2009 at 12:51 pm

Hi!
It’s great tutorial and thank you for it!
I’m novice in ZF so maybe it will sound a bit stupid :)
The checkSession() function checks if the user is authorized to see the secured content. So this function must be called each time from each controller?
Or it should be called only from Auth controller in index action like this:
public function indexAction()
{
$this-> checkSession();
$this->view->auth=Globals::getConfig()->authentication->active;

}
Than you!

Avatar

Enrico Zimuel

October 3rd, 2009 at 8:41 am

You don’t have to call the checkSession() in every controller. This function is called into the Plug-in Controller Initializer for every http request.
In this way if someone is able to see a controller that means that he is authorized.

Avatar

Enrico Zimuel

October 3rd, 2009 at 8:50 am

In my example i use a salt random value to increase the entropy of the password. This method is used to prevent dictionary attacks of the hashed passwords. If you see in the code i prepended the salt with the password and after i generate the MD5. This is built with the MySQL query: MD5(CONCAT(salt,’password’)) where ‘password’ is the password string value.
If you want to improve more the security of the login system you can store the salt values in a different way and not in the same table.

Avatar

Refactoring the ZF Secure Login example with Zend_Application - Zimuel’s blog

October 22nd, 2009 at 6:26 am

[...] this post i’m going to refactoring the ZF Secure Login application, that i provided in my previous post, using the new Zend_Application class, out from the version 1.8 of Zend [...]

Avatar

Ankit

November 5th, 2009 at 6:22 pm

I think there is a problem with your statement:

$this->_response->setRedirect(’/index/login’)->sendResponse();

in checkSession() function. Above method does redirect the user, but it also performs and underlying request. I believe you need to also have exit; afterwards.

Avatar

Heshan Peiris

November 6th, 2009 at 7:10 am

I’m new to zend framework and this article is really worth for me to get familiar with framework. Thank you for the article.

Avatar

Enrico Zimuel

November 6th, 2009 at 2:20 pm

Hi Ankit,
generally speaking your comment is right, but in this case there are not other instructions after the sendResponse() so it works fine without the exit statement.

Avatar

Ankit

November 6th, 2009 at 7:24 pm

Hi Enrico,

Thanks for your reply. Are you saying that Zend will not go ahead with processing the request after preDispatch() function returns?

I am asking because I have seen that if I do not have “exit;” ZF actually processes the request and then forwards the user to the redirect location.

This is a problem because, an authorized user can actually perform an action without actually logging in.

I don’t know if this is due to not having exit; or having one of my settings set incorrectly.

Avatar

Enrico Zimuel

November 9th, 2009 at 1:59 pm

Hi Ankit,
if you use the sendResponse() you force the flow of the dispatcher sending the output to the browser.
In this way an unauthorized user cannot execute actions without login.
For more info: http://framework.zend.com/manual/en/zend.controller.response.html

Avatar

Ankit

November 10th, 2009 at 11:54 pm

Hi Enrico,

It is correct that the user will be eventually forwarded to the login page. However, I believe that ZF still processes the underlying request. Suppose instead of going to index, an unknown user (not logged in) was going to let’s say…

/customer/deleteCustomer/?customer_id=12.

Here, unless we exit(), ZF would execute the deletion and then forward the user to the login page.

Avatar

Enrico Zimuel

November 11th, 2009 at 9:47 am

Hi Ankit,

you are absolutely right! Without the exit() an authorized user can execute actions.
When i built it I was focused only on the view side, that is not rendered without authorization.
It was my fault, sorry.
I modified the source code of the example.
Thank you very much Ankit for your suggestion.

Avatar

Rodrigo Ferrari

November 11th, 2009 at 2:28 pm

Hello,

Thanks for this greate share, but I´m not able to make it run. Just Copied all the files and add ZF 1.8 and tryed to run, the response is that 404 no found the page http://localhost/index/login And the response is The requested URL /index/login was not found on this server.

How can I fix it?! I´m new to ZF.

Thanks.

Avatar

Snowcore

November 11th, 2009 at 5:01 pm

Thanks for the great tutorial!

Avatar

Enrico Zimuel

November 11th, 2009 at 5:11 pm

Hi Rodrigo,
I think you have a problem of configuration of your apache.
Check these points:
- the .htaccess file in the public folder
- the configuration of apache about the mod_rewrite
For more info: http://framework.zend.com/wiki/display/ZFDEV/Configuring+Your+URL+Rewriter

Avatar

sasikumar

November 17th, 2009 at 4:11 pm

when run your secure login script the I got the follwing error

Not Found

The requested URL /index/login was not found on this server.

the htacces file available in public folder

here this our htacces

RewriteEngine on
RewriteRule !\.(js|ico|gif|jpg|png|css)$ index.php

please tell me what is the solutions

Avatar

Enrico Zimuel

November 18th, 2009 at 8:49 am

You have to check the configuration of your web server.
If you use Apache you have to switch on the mod_rewrite and check the directive AllowOverride.
Moreover if you use a virtual host you have to insert the directive AccessFileName .htaccess.
For more info visit this link: http://framework.zend.com/wiki/display/ZFDEV/Configuring+Your+URL+Rewriter

Avatar

Charles

January 21st, 2010 at 3:39 pm

A really well written and useful tutorial which has helped me loads.

Comment Form

About this blog

This is my personal blog about computer programming in PHP for business and for passion. I'm Enrico Zimuel a Software Engineer since 1996. I work as Senior Consultant at Zend Technologies. For more info about me you can visit my web site.

PHP 5 Zend Certified Engineer Zend Framework Certified Enginner
follow me on twitter