• MySQL知识库 :: stored routines
  • Checking Password Complexity

  • Discussion

    Currently there are no built-in functions or procedures within MySQL to check a password's complexity. However, with MySQL 5.0 or greater it is possible to create a function that will check the complexity of a string that is to be used as a password.

    Best Practice

    The following is an example function which checks that a password conforms to these requirements:

    • Password length
    • Password is not simple (based on dictionary)
    • Password contains an upper case character
    • Password contains a lower case character
    • Password contains a digit
    • Password contains punctuation
    • Password is not the same as the username
    delimiter //
    
    DROP FUNCTION password_complexity//
    
    CREATE FUNCTION password_complexity( password VARCHAR(64) )
      RETURNS VARCHAR(256)
      SQL SECURITY INVOKER
    BEGIN
      DECLARE message VARCHAR(256);
      DECLARE count INT;
      DECLARE username VARCHAR(64);
    
      -- check the password length  
      IF LENGTH(password) < 8 THEN
         SET message = 'Password should be at least 8 characters';
      END IF;
    
      -- check whether the password is too simple by comparing it against
      -- a table that holds a dictionary of simple words (admin.dict)
      SELECT COUNT(*) INTO count FROM admin.dict WHERE word = password;
      IF count > 0 THEN
        SET message = CONCAT_WS(',',message,' Password too simple');
      END IF;
    
      -- check for a lower case character  
      IF password NOT RLIKE '[[:lower:]]' THEN
         SET message = CONCAT_WS(',',message,
                               ' Password should contain lower case character');
      END IF;
    
      -- check for an upper case character  
      IF password NOT RLIKE '[[:upper:]]' THEN
         SET message = CONCAT_WS(',',message,
                                ' Password should contain upper case character');
      END IF;
    
      -- check for a digit  
      IF password NOT RLIKE '[[:digit:]]' THEN
         SET message = CONCAT_WS(',',message,
                                ' Password should contain a digit');
      END IF;
    
      -- check for punctuation  
      IF password NOT RLIKE '[[:punct:]]' THEN
         SET message = CONCAT_WS(',',message,
                                 ' Password should contain punctuation');
      END IF;
    
      -- lastly check whether username and password are the same 
      -- if it is, admonish!
      SET username = substring_index(CURRENT_USER(), '@', 1);
      IF username = password THEN
         SET message = 'Username and password are the same!';
      END IF;
    
      -- if message is still NULL then password is OK
      IF message IS NULL THEN
         SET message = 'Password is acceptible!';
      END IF;
    
      RETURN(message);
    END;
    //

    Note that the function uses a table that holds a list of simple passwords within a word column, this simple table can be built as below:

    CREATE TABLE dict (word VARCHAR(128), KEY (word));

    There is also a sample data set of simple passwords attached to this article (dict.txt). This can be loaded to the dict table with the LOAD DATA INFILE statement:

    LOAD DATA INFILE '/path/to/dict.txt'
    INTO TABLE dict
    LINES TERMINATED BY '\r\n';

    Here is some sample output:

    SELECT password_complexity('mark@2201');
    
    +-----------------------------------------------+
    | password_complexity('mark@2201')              |
    +-----------------------------------------------+
    |  Password should contain upper case character |
    +-----------------------------------------------+
    1 row in set (0.00 sec)