PHP integrated dynamic password authentication (recommended)
This article mainly introduces PHP integrated dynamic password authentication in detail. Dynamic passwords use one-time passwords and invalidate used passwords to improve security performance. Interested friends can refer to it
Most systems currently use static passwords for identity authentication login, but because static passwords are easy to be stolen, their security cannot meet security requirements.
Dynamic passwords use a one-time password and invalidate used passwords to prevent security issues caused by password theft.
Dynamic passwords are divided into HOTP (dynamic passwords based on event counting, RFC4226), TOTP (dynamic passwords based on time counting, RFC6238), OCRA (challenge-response dynamic passwords, RFC6287) and other methods.
This article introduces the solution of dynamic password authentication integrating TOTP method. The PHP framework uses Thinkphp3.2.3, and the dynamic password generator uses google authtication.
1. Add oath algorithm class to Thinkphp framework
oath algorithm encapsulation class oath.php code is as follows:
<?PHP /** * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * PHP Google two-factor authentication module. * * See http://www.idontplaydarts.com/2011/07/google-totp-two-factor-authentication-for-php/ * for more details * * @author Phil **/ class Google2FA { const keyRegeneration = 30; // Interval between key regeneration const otpLength = 6; // Length of the Token generated private static $lut = array( // Lookup needed for Base32 encoding "A" => 0, "B" => 1, "C" => 2, "D" => 3, "E" => 4, "F" => 5, "G" => 6, "H" => 7, "I" => 8, "J" => 9, "K" => 10, "L" => 11, "M" => 12, "N" => 13, "O" => 14, "P" => 15, "Q" => 16, "R" => 17, "S" => 18, "T" => 19, "U" => 20, "V" => 21, "W" => 22, "X" => 23, "Y" => 24, "Z" => 25, "2" => 26, "3" => 27, "4" => 28, "5" => 29, "6" => 30, "7" => 31 ); /** * Generates a 16 digit secret key in base32 format * @return string **/ public static function generate_secret_key($length = 16) { $b32 = "234567QWERTYUIOPASDFGHJKLZXCVBNM"; $s = ""; for ($i = 0; $i < $length; $i++) $s .= $b32[rand(0,31)]; return $s; } /** * Returns the current Unix Timestamp devided by the keyRegeneration * period. * @return integer **/ public static function get_timestamp() { return floor(microtime(true)/self::keyRegeneration); } /** * Decodes a base32 string into a binary string. **/ public static function base32_decode($b32) { $b32 = strtoupper($b32); if (!preg_match('/^[ABCDEFGHIJKLMNOPQRSTUVWXYZ234567]+$/', $b32, $match)) throw new Exception('Invalid characters in the base32 string.'); $l = strlen($b32); $n = 0; $j = 0; $binary = ""; for ($i = 0; $i < $l; $i++) { $n = $n << 5; // Move buffer left by 5 to make room $n = $n + self::$lut[$b32[$i]]; // Add value into buffer $j = $j + 5; // Keep track of number of bits in buffer if ($j >= 8) { $j = $j - 8; $binary .= chr(($n & (0xFF << $j)) >> $j); } } return $binary; } /*by tang*/ public static function base32_encode($data, $length){ $basestr = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; $count = 0; if ($length > 0) { $buffer = $data[0]; $next = 1; $bitsLeft = 8; while (($bitsLeft > 0 || $next < $length)) { if ($bitsLeft < 5) { if ($next < $length) { $buffer <<= 8; $buffer |= $data[$next++] & 0xFF; $bitsLeft += 8; } else { $pad = 5 - $bitsLeft; $buffer <<= $pad; $bitsLeft += $pad; } } $index = 0x1F & ($buffer >> ($bitsLeft - 5)); $bitsLeft -= 5; $result .= $basestr[$index]; $count++; } } return $result; } /** * Takes the secret key and the timestamp and returns the one time * password. * * @param binary $key - Secret key in binary form. * @param integer $counter - Timestamp as returned by get_timestamp. * @return string **/ public static function oath_hotp($key, $counter) { if (strlen($key) < 8) throw new Exception('Secret key is too short. Must be at least 16 base 32 characters'); $bin_counter = pack('N*', 0) . pack('N*', $counter); // Counter must be 64-bit int $hash = hash_hmac ('sha1', $bin_counter, $key, true); return str_pad(self::oath_truncate($hash), self::otpLength, '0', STR_PAD_LEFT); } /** * Verifys a user inputted key against the current timestamp. Checks $window * keys either side of the timestamp. * * @param string $b32seed * @param string $key - User specified key * @param integer $window * @param boolean $useTimeStamp * @return boolean **/ public static function verify_key($b32seed, $key, $window = 5, $useTimeStamp = true) { $timeStamp = self::get_timestamp(); if ($useTimeStamp !== true) $timeStamp = (int)$useTimeStamp; $binarySeed = self::base32_decode($b32seed); for ($ts = $timeStamp - $window; $ts <= $timeStamp + $window; $ts++) if (self::oath_hotp($binarySeed, $ts) == $key) return true; return false; } /** * Extracts the OTP from the SHA1 hash. * @param binary $hash * @return integer **/ public static function oath_truncate($hash) { $offset = ord($hash[19]) & 0xf; return ( ((ord($hash[$offset+0]) & 0x7f) << 24 ) | ((ord($hash[$offset+1]) & 0xff) << 16 ) | ((ord($hash[$offset+2]) & 0xff) << 8 ) | (ord($hash[$offset+3]) & 0xff) ) % pow(10, self::otpLength); } } /* $InitalizationKey = "LFLFMU2SGVCUIUCZKBMEKRKLIQ"; // Set the inital key $TimeStamp = Google2FA::get_timestamp(); $secretkey = Google2FA::base32_decode($InitalizationKey); // Decode it into binary $otp = Google2FA::oath_hotp($secretkey, $TimeStamp); // Get current token echo("Init key: $InitalizationKey\n"); echo("Timestamp: $TimeStamp\n"); echo("One time password: $otp\n"); // Use this to verify a key as it allows for some time drift. $result = Google2FA::verify_key($InitalizationKey, "123456"); var_dump($result); */ ?>
Due to Google’s dynamic password algorithm The medium seed key uses base32 encoding, so the base32 algorithm is required. The content of base32.php is as follows:
<?php //namespace Base32; /** * Base32 encoder and decoder * * Last update: 2012-06-20 * * RFC 4648 compliant * @link http://www.ietf.org/rfc/rfc4648.txt * * Some groundwork based on this class * https://github.com/NTICompass/PHP-Base32 * * @author Christian Riesen <chris.riesen@gmail.com> * @link http://christianriesen.com * @license MIT License see LICENSE file */ class Base32 { /** * Alphabet for encoding and decoding base32 * * @var array */ private static $alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567='; /** * Creates an array from a binary string into a given chunk size * * @param string $binaryString String to chunk * @param integer $bits Number of bits per chunk * @return array */ private static function chunk($binaryString, $bits) { $binaryString = chunk_split($binaryString, $bits, ' '); if (substr($binaryString, (strlen($binaryString)) - 1) == ' ') { $binaryString = substr($binaryString, 0, strlen($binaryString)-1); } return explode(' ', $binaryString); } /** * Encodes into base32 * * @param string $string Clear text string * @return string Base32 encoded string */ public static function encode($string) { if (strlen($string) == 0) { // Gives an empty string return ''; } // Convert string to binary $binaryString = ''; foreach (str_split($string) as $s) { // Return each character as an 8-bit binary string $binaryString .= sprintf('%08b', ord($s)); } // Break into 5-bit chunks, then break that into an array $binaryArray = self::chunk($binaryString, 5); // Pad array to be pisible by 8 while (count($binaryArray) % 8 !== 0) { $binaryArray[] = null; } $base32String = ''; // Encode in base32 foreach ($binaryArray as $bin) { $char = 32; if (!is_null($bin)) { // Pad the binary strings $bin = str_pad($bin, 5, 0, STR_PAD_RIGHT); $char = bindec($bin); } // Base32 character $base32String .= self::$alphabet[$char]; } return $base32String; } /** * Decodes base32 * * @param string $base32String Base32 encoded string * @return string Clear text string */ public static function decode($base32String) { // Only work in upper cases $base32String = strtoupper($base32String); // Remove anything that is not base32 alphabet $pattern = '/[^A-Z2-7]/'; $base32String = preg_replace($pattern, '', $base32String); if (strlen($base32String) == 0) { // Gives an empty string return ''; } $base32Array = str_split($base32String); $string = ''; foreach ($base32Array as $str) { $char = strpos(self::$alphabet, $str); // Ignore the padding character if ($char !== 32) { $string .= sprintf('%05b', $char); } } while (strlen($string) %8 !== 0) { $string = substr($string, 0, strlen($string)-1); } $binaryArray = self::chunk($string, 8); $realString = ''; foreach ($binaryArray as $bin) { // Pad each value to 8 bits $bin = str_pad($bin, 8, 0, STR_PAD_RIGHT); // Convert binary strings to ASCII $realString .= chr(bindec($bin)); } return $realString; } } ?>
Put these two files into the ThinkPHP\Library\Vendor\oath directory of the Thinkphp framework. The oath directory is Created by myself.
2. Add database fields
Add the following fields to the user table:
auth_type (0-static password, 1-dynamic password)
seed (seed) Key)
temp_seed (temporary seed key)
last_logintime (last successful login time)
last_otp (last used password)
where auth_type is to indicate which authentication method the user uses, seed is the user's seed key, and temp_seed is a seed key temporarily saved before the user activates it. If the user successfully activates dynamic password authentication, the content of this field will be filled in the seed field. last_logintime and last_otp are the time and dynamic password of the last successful authentication, which are used to prevent users from reusing the same password.
3. Code integration
1), open dynamic password
in the original system Change the password page and add the selection of authentication method, for example:
# If the user selects the dynamic password method, a QR code will be generated and displayed on the page for the user to activate the dynamic password Password. In order to be compatible with Google authentication, its QR code format is the same as Google's. For the method of generating QR codes, see my other article "Thinkphp3.2.3 integrates phpqrcode to generate QR codes with logo".
The code to generate the key QR code is as follows:
public function qrcode() { Vendor('oath.base32'); $base32 = new \Base32(); $rand = random(16);//生成随机种子 $rand = $base32->encode($rand); $rand=str_replace('=','',$rand);//去除填充的‘=' $errorCorrectionLevel =intval(3) ;//容错级别 $matrixPointSize = intval(8);//生成图片大小 //生成二维码图片 Vendor('phpqrcode.phpqrcode'); $object = new \QRcode(); $text = sprintf("otpauth://totp/%s?secret=%s", $user, $rand); $object->png($text, false, $errorCorrectionLevel, $matrixPointSize, 2); 生成的种子$rand保存到数据库的temp_seed字段 }
random is a function that generates a random string. The code $rand=str_replace('=','',$rand) is because the base32 decoding algorithm in Google Mobile Token does not fill the '=' sign.
The code to verify user dynamic password is as follows:
从数据库读取temp_seed Vendor('oath.oath'); $object = new \Google2FA(); if($object->verify_key($temp_seed, $otp)){ 验证成功,将数据库更新seed为temp_seed,auth_type为1,last_otp为otp }
2), dynamic password login
User dynamic password login verification Code:
Read the auth_type, seed, last_otp fields from the database.
if($auth_type==1){//动态口令 //防止重复认证 if($lat_otp == $otp) { 动态口令重复使用返回 } Vendor('oath.oath'); $object = new \Google2FA(); if(!$object->verify_key($seed, $otp)) { 动态口令不正确 } else { 登录成功,将数据库更新last_otp为$otp,last_logintime为time() } }
4. Test verification
Download google authtication, use a static password to log in to the system, and enter the password change page.
Open google authentication, scan the QR code, and the dynamic password will be displayed.
Save the content and activate the dynamic password successfully!
Then you can use your dynamic password to log in to the system!
Summary: The above is the entire content of this article, I hope it will be helpful to everyone's learning.
Related recommendations:
PHP access to Alipay instant payment function
PHP two-dimensional array deduplication algorithm graphic and text explanation
phpDetailed explanation of three methods to obtain POST data
The above is the detailed content of PHP integrated dynamic password authentication (recommended). For more information, please follow other related articles on the PHP Chinese website!

What’s still popular is the ease of use, flexibility and a strong ecosystem. 1) Ease of use and simple syntax make it the first choice for beginners. 2) Closely integrated with web development, excellent interaction with HTTP requests and database. 3) The huge ecosystem provides a wealth of tools and libraries. 4) Active community and open source nature adapts them to new needs and technology trends.

PHP and Python are both high-level programming languages that are widely used in web development, data processing and automation tasks. 1.PHP is often used to build dynamic websites and content management systems, while Python is often used to build web frameworks and data science. 2.PHP uses echo to output content, Python uses print. 3. Both support object-oriented programming, but the syntax and keywords are different. 4. PHP supports weak type conversion, while Python is more stringent. 5. PHP performance optimization includes using OPcache and asynchronous programming, while Python uses cProfile and asynchronous programming.

PHP is mainly procedural programming, but also supports object-oriented programming (OOP); Python supports a variety of paradigms, including OOP, functional and procedural programming. PHP is suitable for web development, and Python is suitable for a variety of applications such as data analysis and machine learning.

PHP originated in 1994 and was developed by RasmusLerdorf. It was originally used to track website visitors and gradually evolved into a server-side scripting language and was widely used in web development. Python was developed by Guidovan Rossum in the late 1980s and was first released in 1991. It emphasizes code readability and simplicity, and is suitable for scientific computing, data analysis and other fields.

PHP is suitable for web development and rapid prototyping, and Python is suitable for data science and machine learning. 1.PHP is used for dynamic web development, with simple syntax and suitable for rapid development. 2. Python has concise syntax, is suitable for multiple fields, and has a strong library ecosystem.

PHP remains important in the modernization process because it supports a large number of websites and applications and adapts to development needs through frameworks. 1.PHP7 improves performance and introduces new features. 2. Modern frameworks such as Laravel, Symfony and CodeIgniter simplify development and improve code quality. 3. Performance optimization and best practices further improve application efficiency.

PHPhassignificantlyimpactedwebdevelopmentandextendsbeyondit.1)ItpowersmajorplatformslikeWordPressandexcelsindatabaseinteractions.2)PHP'sadaptabilityallowsittoscaleforlargeapplicationsusingframeworkslikeLaravel.3)Beyondweb,PHPisusedincommand-linescrip

PHP type prompts to improve code quality and readability. 1) Scalar type tips: Since PHP7.0, basic data types are allowed to be specified in function parameters, such as int, float, etc. 2) Return type prompt: Ensure the consistency of the function return value type. 3) Union type prompt: Since PHP8.0, multiple types are allowed to be specified in function parameters or return values. 4) Nullable type prompt: Allows to include null values and handle functions that may return null values.


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

MantisBT
Mantis is an easy-to-deploy web-based defect tracking tool designed to aid in product defect tracking. It requires PHP, MySQL and a web server. Check out our demo and hosting services.

SAP NetWeaver Server Adapter for Eclipse
Integrate Eclipse with SAP NetWeaver application server.

MinGW - Minimalist GNU for Windows
This project is in the process of being migrated to osdn.net/projects/mingw, you can continue to follow us there. MinGW: A native Windows port of the GNU Compiler Collection (GCC), freely distributable import libraries and header files for building native Windows applications; includes extensions to the MSVC runtime to support C99 functionality. All MinGW software can run on 64-bit Windows platforms.

PhpStorm Mac version
The latest (2018.2.1) professional PHP integrated development tool

Atom editor mac version download
The most popular open source editor