danami Posted October 13, 2008 Share Posted October 13, 2008 (edited) This contribution will allow you to add an ajax password strength meter to WHMCS that uses the cracklib library on the server to check password strength. This is the same library that your server and various control panels use for checking passwords. Note: You need to have cracklib, cracklib-dicts, and the PECL PHP cracklib extension installed for this to work! Make sure that phpinfo() reports crack supported enabled. Make sure that openbasedir restrictions aren't blocking access to the cracklib dictionary files. 1. Save this code to checkpassword.php and place it in your WHMCS directory <?php /** * Password check with ajax and cracklib * * 1. Make sure that cracklib is installed on your server. * # rpm -qa | grep cracklib * # cracklib-2.8.9-3.3 * # cracklib-dicts-2.8.9-3.3 * * 2. Make sure that the PHP cracklib extension is installed. Install pecl to install cracklib. * # yum install php-pear * # pecl install crack * * There is a tiny bug in the compilation procedure, to avoid it do: * # cd /var/cache/php-pear/crack-0.4 * # ./configure; make; make install * * 3. Configure php5 to work with crack, edit /etc/php.ini or create a new crack.ini file in /etc/php.d/ and enter: * [Crack] * ; Modify the setting below to match the directory location of the cracklib * ; dictionary files. Include the base filename, but not the file extension. * extension=crack.so * crack.default_dictionary = "/usr/share/cracklib/pw_dict" * * 4. Make sure to restart apache. phpinfo(); should report crack support enabled * * 5. crack.default_dictionary files must be accessable to any openbase dir restrictions. * Give openbasedir access to the files or copy the dictionary files to a path that PHP has access to. */ /* Our cracklib dictionary file (no file extension) */ define('CRACKLIB_DICTIONARY_FILE','/usr/share/cracklib/pw_dict'); /** * Check password using PHP's cracklib functions * * @param string $password Our password we are checking * @return string */ function checkCracklib($password) { // Check if cracklib is installed if (!function_exists('crack_opendict')) { $message = 'Cracklib is not installed'; return $message; } // Open crackLib dictionary $dictionary = crack_opendict(CRACKLIB_DICTIONARY_FILE); if (!$dictionary) { $message = 'Unable to open cracklib dictionary'; return $message; } // Perform cracklib password check $check = crack_check($dictionary, $password); // Retrieve messages $message = crack_getlastmessage(); // Close cracklib dictionary crack_closedict($dictionary); return $message; } /** * Generates our xml ajax response * * @param string $message Our cracklib message * @return string */ function xmlResponse($message) { $output = '<?xml version="1.0" encoding="UTF-8"?>'; $output .= '<result><![CDATA['; if ($message == 'strong password') { $output .= '<div style="width:100%;background:green" id="password_bar">Strong Password</div>'; } else { $output .= '<div style="width:100%;background:red;" id="password_bar">'.ucfirst($message).'</div>'; } $output .=']]></result>'; return $output; } $password_test = checkCracklib(substr($_GET['pass'],0,128)); $output = xmlResponse($password_test); header('Content-Type: text/xml'); header('Pragma: no-cache'); echo $output; ?> 2. On your password page include javascript and css in your smarty template (for example add to orderforms\default\default\viewcart.tpl) {literal} <script type="text/javascript"> function check_password(passid) { if (window.XMLHttpRequest) { http = new XMLHttpRequest(); } else if (window.ActiveXObject) { http = new ActiveXObject("Microsoft.XMLHTTP"); } handle = document.getElementById(passid); var url = 'checkpassword.php?'; if(handle.value.length > 0) { var fullurl = url + 'pass=' + encodeURIComponent(handle.value); http.open("GET", fullurl, true); http.send(null); http.onreadystatechange = statechange_password; }else{ document.getElementById('password_strength').innerHTML = ''; } } function statechange_password() { if (http.readyState == 4) { var xmlObj = http.responseXML; var html = xmlObj.getElementsByTagName('result').item(0).firstChild.data; document.getElementById('password_strength').innerHTML = html; } } </script> <style type="text/css"> #password_strength { width: 90%; background: #cccccc; } #password_bar { font-size: 9px; background: #7FFF00; border: 1px solid #cccccc; padding: 2px; } </style> {/literal} 3. Add the password meter html code (for example add to orderforms\default\default\viewcart.tpl) Change <tr><td class="fieldarea">{$LANG.clientareapassword}</td><td><input type="password" name="password" size="20" /></td></tr> <tr><td class="fieldarea">{$LANG.clientareaconfirmpassword}</td><td><input type="password" name="password2" size="20" /></td></tr> To <tr><td class="fieldarea">{$LANG.clientareapassword}</td><td><input type="password" name="password" size="20" id="password" onchange="check_password('password')" /></td></tr> <tr><td class="fieldarea">{$LANG.clientareaconfirmpassword}</td><td><input type="password" name="password2" size="20" /></td></tr> <tr><td class="fieldarea">Password Strength</td><td><div id="password_strength"></div></td></tr> Now WHMCS will check password strength just like your server does! Have fun! Edited October 13, 2008 by danami 0 Quote Link to comment Share on other sites More sharing options...
danami Posted October 13, 2008 Author Share Posted October 13, 2008 (edited) I've updated checkpassword.php to use simple PHP checks first. If you have cracklib enabled then it can use them also. You can enable or disable: Length check Lowercase check Uppercase check Numbers check Special Characters check Cracklib check New checkpassword.php <?php /** * Password check with ajax and cracklib * * 1. Make sure that cracklib is installed on your server. * # rpm -qa | grep cracklib * # cracklib-2.8.9-3.3 * # cracklib-dicts-2.8.9-3.3 * * 2. Make sure that the PHP cracklib extension is installed. Install pecl to install cracklib. * # yum install php-pear * # pecl install crack * * There is a tiny bug in the compilation procedure, to avoid it do: * # cd /var/cache/php-pear/crack-0.4 * # ./configure; make; make install * * 3. Configure php5 to work with crack, edit /etc/php.ini or create a new crack.ini file in /etc/php.d/ and enter: * [Crack] * ; Modify the setting below to match the directory location of the cracklib * ; dictionary files. Include the base filename, but not the file extension. * extension=crack.so * crack.default_dictionary = "/usr/share/cracklib/pw_dict" * * 4. Make sure to restart apache. phpinfo(); should report crack support enabled * * 5. crack.default_dictionary files must be accessable to any openbase dir restrictions. * Give openbasedir access to the files or copy the dictionary files to a path that PHP has access to. */ /* Normal password checks */ define('PASSWORD_LENGTH_MINIMUM',6); //Set to 0 to disable define('PASSWORD_LOWERCASE',true); define('PASSWORD_UPPERCASE',true); define('PASSWORD_NUMBERS',true); define('PASSWORD_SPECIAL_CHARS',true); /* Enable our cracklib dictionary check and define path to dictionary file (no file extension) */ define('CRACKLIB_ENABLED',false); define('CRACKLIB_DICTIONARY_FILE','/usr/share/cracklib/pw_dict'); /** * Check password using PHP's cracklib functions * * @param string $password Our password we are checking * @return string */ function checkCracklib($password) { // Check if cracklib is installed if (!function_exists('crack_opendict')) { return 'Cracklib is not installed'; } // Open crackLib dictionary $dictionary = crack_opendict(CRACKLIB_DICTIONARY_FILE); if (!$dictionary) { return 'Unable to open cracklib dictionary'; } // Perform cracklib password check $check = crack_check($dictionary, $password); // Retrieve messages $message = crack_getlastmessage(); // Close cracklib dictionary crack_closedict($dictionary); return $message; } /** * Check password using simple tests * @param string $password Our password we are checking * @return string */ function checkPassword($password) { // Password Length if(PASSWORD_LENGTH_MINIMUM !=0 && (strlen($password) < PASSWORD_LENGTH_MINIMUM)) { return 'It must be at least '.PASSWORD_LENGTH_MINIMUM.' characters in length'; } // Letters - lowercase if(PASSWORD_LOWERCASE && !preg_match("/([a-z]+)/", $password)) { return 'It must contain lowercase letters'; } // Letters - uppercase if(PASSWORD_UPPERCASE && !preg_match("/([A-Z]+)/", $password)) { return 'It must contain uppercase letters'; } // Numbers if(PASSWORD_NUMBERS && !preg_match("/([0-9]+)/", $password)) { return 'It must contain numbers'; } // Special Characters if(PASSWORD_SPECIAL_CHARS && !preg_match("/[\W_]/" , $password)) { return 'It must contain special characters'; } return 'strong password'; } /** * Generates our xml ajax response * * @param string $message Our cracklib message * @return string */ function xmlResponse($message) { $output = '<?xml version="1.0" encoding="UTF-8"?>'; $output .= '<result><![CDATA['; if ($message == 'strong password') { $output .= '<div style="width:100%;background:green" id="password_bar">Strong Password</div>'; } else { $output .= '<div style="width:100%;background:red;" id="password_bar">'.ucfirst($message).'</div>'; } $output .=']]></result>'; return $output; } //Check password $password = substr($_GET['pass'],0,128); $password_test = checkPassword($password); //If password passes normal test check using cracklib dictionary if ($password_test == 'strong password' && CRACKLIB_ENABLED) { $password_test = checkCracklib($password); } $output = xmlResponse($password_test); header('Content-Type: text/xml'); header('Pragma: no-cache'); echo $output; ?> Edited October 13, 2008 by danami 0 Quote Link to comment Share on other sites More sharing options...
danami Posted October 13, 2008 Author Share Posted October 13, 2008 (edited) Also if you want it more responsive (real-time feedback) you can change the way you call it on your input: onchange="check_password('password')" To onkeyup="check_password('password')" Edited October 13, 2008 by danami 0 Quote Link to comment Share on other sites More sharing options...
LemonBarley Posted October 14, 2008 Share Posted October 14, 2008 yum install php-pear did not work 0 Quote Link to comment Share on other sites More sharing options...
LemonBarley Posted October 14, 2008 Share Posted October 14, 2008 * extension=crack.so * crack.default_dictionary = "/usr/share/cracklib/pw_dict" phpinfo did nto show cracklib support. searched for "crack" in the phpinfo page, but its not found. 0 Quote Link to comment Share on other sites More sharing options...
danami Posted October 14, 2008 Author Share Posted October 14, 2008 (edited) yum install php-pear did not work Those instructions are for rpm based distros (Redhat/Centos) . If you are using debian or another OS then you'll need to try and install it yourself. If you can't get cracklib installed .. then just use the basic checks included in the second checkpassword.php file ... Edited October 14, 2008 by danami 0 Quote Link to comment Share on other sites More sharing options...
danami Posted October 14, 2008 Author Share Posted October 14, 2008 * extension=crack.so* crack.default_dictionary = "/usr/share/cracklib/pw_dict" phpinfo did nto show cracklib support. searched for "crack" in the phpinfo page, but its not found. Did you do all the steps outlined in the file to get crack installed (These instructions are for rpm based distros only)? 1. Make sure that cracklib is installed on your server. rpm -qa | grep cracklib cracklib-2.8.9-3.3 cracklib-dicts-2.8.9-3.3 2. Make sure that the PHP cracklib extension is installed. Install pecl to install cracklib. yum install php-pear pecl install crack There is a tiny bug in the compilation procedure, to avoid it do: cd /var/cache/php-pear/crack-0.4 ./configure; make; make install 3. Configure php5 to work with crack, edit /etc/php.ini or create a new crack.ini file in /etc/php.d/ and enter: [Crack] ; Modify the setting below to match the directory location of the cracklib ; dictionary files. Include the base filename, but not the file extension. extension=crack.so crack.default_dictionary = "/usr/share/cracklib/pw_dict" 0 Quote Link to comment Share on other sites More sharing options...
danami Posted October 15, 2008 Author Share Posted October 15, 2008 If you want to require strong passwords you can add this javascript function to the ajax javascript clear any weak passwords that are submitted (add this to the original ajax javascript functions). function empty_weak_password(passid, passid2) { var html = document.getElementById('password_strength').innerHTML; var pos = html.indexOf("Strong Password"); if (pos < 0) { document.getElementById(passid).value = ''; document.getElementById(passid2).value = ''; } } then change the form onsubmit to this (for example add to orderforms\default\default\viewcart.tpl): <form method="post" action="{$smarty.server.PHP_SELF}?a=checkout" {if !$loggedin} onsubmit="empty_weak_password('password','password2')" {/if}> Then just change the "Password required" lang in your language file to "A strong password is required" 0 Quote Link to comment Share on other sites More sharing options...
Zorro67 Posted October 16, 2008 Share Posted October 16, 2008 Thanks Danami, nice hack! 0 Quote Link to comment Share on other sites More sharing options...
LemonBarley Posted October 20, 2008 Share Posted October 20, 2008 i wonder if someone can help me to install this addon. i cant make it work 0 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.