OceanBaseデータベースのOracleモードにおけるパスワードの複雑さポリシーは、Oracleデータベースのパスワードポリシーと互換性があります。悪意あるパスワード攻撃を防ぎ、データベースのセキュリティを向上させるため、OceanBaseデータベースユーザーは必要に応じてパスワードの複雑さ関数を設定し、ユーザーのログイン身元を検証できます。
適用対象
このドキュメントはOceanBaseデータベースのOracleモードにのみ適用されます。現在、OceanBaseデータベースCommunity EditionではMySQLモードのみが提供されています。MySQLモードにおけるパスワードの複雑さについては、パスワードの複雑さを参照してください。
前提条件
Oracleモードでは、ユーザーはProfileのPASSWORD_VERIFY_FUNCTIONプロパティを使用して、パスワードの複雑さが要件を満たしているかどうかを検証できます。ユーザーはまず、パスワードの複雑さを検証するためのPL関数を作成する必要があり、以下のインターフェースを満たす必要があります:
FUNCTION verify_function (username IN VARCHAR2,
password IN VARCHAR2,
old_password IN VARCHAR2)
RETURN BOOLEAN;
ユーザーの作成またはパスワードの変更時に、この検証関数が呼び出され、関数の実行結果に基づいて新しいパスワードが複雑さ要件を満たしているかどうかを判断します。
パスワードの複雑さを設定し、パスワードの複雑さ検証を有効にする
OceanBaseデータベースのOracleモードでは、パスワードの複雑さが要件を満たしているかどうかを検証するためにPASSWORD_VERIFY_FUNCTIONパラメータを提供します。
PASSWORD_VERIFY_FUNCTIONパラメータは、PLのパスワード複雑さ検証関数をCREATE PROFILEおよびALTER PROFILステートメントにパラメータとして渡すことを許可します。
注意
本番環境では、パスワード長を20桁に設定することを推奨します。これには、数字、大文字、小文字、特殊文字が含まれます。パスワードの複雑さが低いほど、ユーザー名を含む、繰り返し文字を使用するなど、解読される可能性が高くなります。セキュリティ上の理由から、ユーザーのパスワードは高い複雑さを持つ必要があります。
SYSユーザーでクラスタのOracleテナントにログインします。obclient -usys@oracle -h10.xxx.xxx.1 - P2881 -P*******PASSWORD_VERIFY_FUNCTIONパラメータに対応する関数を作成し、権限を付与します。以下は、パスワードの複雑さを次のルールに設定するための操作ガイドです。
パスワードの長さは、最小8文字以上、最大256文字以下です。
少なくとも1つの大文字、1つの小文字、1つの特殊文字を含みます。
パスワードはユーザー名、ユーザー名の逆順、またはサーバー名にすることはできません。
例:
delimiter // CREATE OR REPLACE FUNCTION complexity_check (password varchar2, chars integer := NULL, letter integer := NULL, upper_c integer := NULL, lower_c integer := NULL, digit integer := NULL, special integer := NULL) RETURN boolean IS digit_array varchar2(10) := '0123456789'; alpha_array varchar2(26) := 'abcdefghijklmnopqrstuvwxyz'; cnt_letter integer := 0; cnt_upper integer := 0; cnt_lower integer := 0; cnt_digit integer := 0; cnt_special integer := 0; flag boolean := FALSE; len INTEGER := NVL(length(password), 0); i integer ; ch CHAR(1); BEGIN -- Check that the password length does not exceed 2 * (max DB pwd len) -- The maximum length of any DB User password is 128 bytes. -- This limit improves the performance of the Edit Distance calculation -- between old and new passwords. IF len > 256 THEN raise_application_error(-20020, 'Password length more than 256'); END IF; -- Classify each character in the password. FOR i in 1..len LOOP ch := substr(password, i, 1); IF ch = '"' THEN flag := TRUE; ELSIF instr(digit_array, ch) > 0 THEN cnt_digit := cnt_digit + 1; ELSIF instr(alpha_array, LOWER(ch)) > 0 THEN cnt_letter := cnt_letter + 1; IF ch = LOWER(ch) THEN cnt_lower := cnt_lower + 1; ELSE cnt_upper := cnt_upper + 1; END IF; ELSE cnt_special := cnt_special + 1; END IF; END LOOP; IF flag = 1 THEN raise_application_error(-20012, 'password must NOT contain a ' || 'double-quote character, which is ' || 'reserved as a password delimiter'); END IF; IF chars IS NOT NULL AND len < chars THEN raise_application_error(-20001, 'Password length less than ' || chars); END IF; IF letter IS NOT NULL AND cnt_letter < letter THEN raise_application_error(-20022, 'Password must contain at least ' || letter || ' letter(s)'); END IF; IF upper_c IS NOT NULL AND cnt_upper < upper_c THEN raise_application_error(-20023, 'Password must contain at least ' || upper_c || ' uppercase character(s)'); END IF; IF lower_c IS NOT NULL AND cnt_lower < lower_c THEN raise_application_error(-20024, 'Password must contain at least ' || lower_c || ' lowercase character(s)'); END IF; IF digit IS NOT NULL AND cnt_digit < digit THEN raise_application_error(-20025, 'Password must contain at least ' || digit || ' digit(s)'); END IF; IF special IS NOT NULL AND cnt_special < special THEN raise_application_error(-20026, 'Password must contain at least ' || special || ' special character(s)'); END IF; RETURN(TRUE); END; // CREATE OR REPLACE FUNCTION verify_function (username varchar2, password varchar2, old_password varchar2) -- In this example, three function parameters are defined: username, password, and old_password. RETURN boolean IS differ integer; pw_lower varchar2(256); db_name varchar2(40); i integer; simple_password varchar2(10); reverse_user varchar2(32); BEGIN IF NOT complexity_check(password, 8, NULL, 1, 1, NULL, 1) THEN RETURN(FALSE); END IF; -- Check if the password contains the username pw_lower := LOWER(password); IF instr(pw_lower, LOWER(username)) > 0 THEN raise_application_error(-20002, 'Password contains the username'); END IF; -- Check if the password contains the username reversed reverse_user := ''; FOR i in REVERSE 1..length(username) LOOP reverse_user := reverse_user || substr(username, i, 1); END LOOP; IF instr(pw_lower, LOWER(reverse_user)) > 0 THEN raise_application_error(-20003, 'Password contains the username ' || 'reversed'); END IF; -- Check if the password contains the server name db_name := 'oceanbase'; IF instr(pw_lower, LOWER(db_name)) > 0 THEN raise_application_error(-20004, 'Password contains the server name'); END IF; -- Check if the password contains 'oracle' IF instr(pw_lower, 'oracle') > 0 THEN raise_application_error(-20006, 'Password too simple'); END IF; RETURN(TRUE); END; // delimiter ; obclient> GRANT EXECUTE ON verify_function TO PUBLIC; obclient> CREATE PUBLIC SYNONYM verify_function FOR sys.verify_function;関数の作成に関する操作の詳細については、関数の作成を参照してください。
UserのProfileで、
PASSWORD_VERIFY_FUNCTIONパラメータを指定し、パスワードの複雑さ検証を有効にします。ステートメントは次のとおりです:
obclient> ALTER PROFILE profile_name LIMIT PASSWORD_VERIFY_FUNCTION verify_function;ここで、
profile_nameはカスタムプロファイルを使用することも、DEFAULTプロファイルを使用することもできます。DEFAULTプロファイルを使用してPASSWORD_VERIFY_FUNCTIONパラメータを指定する例:obclient> ALTER PROFILE DEFAULT LIMIT PASSWORD_VERIFY_FUNCTION verify_function; Query OK, 0 rows affectedALTER PROFILEステートメントの詳細については、ALTER PROFILEを参照してください。完了したら、次のステートメントを実行して、パスワードの複雑さ検証が有効になっているかどうかを確認します。
返される値が
NULL場合、パスワードの複雑さ検証は有効になっていないことを意味し、指定した関数の値が返された場合、パスワードの複雑さ検証が有効になっていることを意味します。obclient> SELECT LIMIT FROM DBA_PROFILES WHERE RESOURCE_NAME='PASSWORD_VERIFY_FUNCTION' AND PROFILE='profile_name';例:
obclient> SELECT LIMIT FROM DBA_PROFILES WHERE RESOURCE_NAME='PASSWORD_VERIFY_FUNCTION' AND PROFILE='DEFAULT'; +-----------------+ | LIMIT | +-----------------+ | VERIFY_FUNCTION | +-----------------+ 1 row in set
パスワードの複雑さの設定が有効かどうかを確認する
SYSユーザーでクラスタのOracleテナントにログインします。obclient -usys@oracle -h10.xxx.xxx.1 - P2881 -P*******要件を満たすパスワードと要件を満たさないパスワードをそれぞれ使用して、ユーザー
sectest1を作成します。obclient> CREATE USER sectest1 IDENTIFIED BY ******; ERROR-20023: Password must contain at least 1 uppercase character(s) obclient> CREATE USER sectest1 IDENTIFIED BY ******; ERROR-20002: Password contains the username obclient> CREATE USER sectest1 IDENTIFIED BY ******; Query OK, 0 rows affected
パスワードの複雑さルールを確認する
パスワードの複雑さルールが設定された後、次回具体的なルールを確認する必要がある場合は、関数の内容を照会することで取得できます。
手順は以下のとおりです:
rootユーザーでクラスタのOracleテナントにログインします。
obclient -usys@oracle -h10.xxx.xxx.1 - P2881 -P*******DBA_SOURCEビューを使用して対応する関数を検索します。DBA_SOURCEビューには、システム内のすべてのストアドプロシージャと関数が記録されています。DBA_SOURCEビューとそのフィールドの詳細については、DBA_SOURCEを参照してください。例:
obclient> SELECT OWNER,NAME,TYPE FROM DBA_SOURCE WHERE TYPE='FUNCTION'; +-------+------------------+----------+ | OWNER | NAME | TYPE | +-------+------------------+----------+ | SYS | COMPLEXITY_CHECK | FUNCTION | | SYS | STRING_DISTANCE | FUNCTION | | SYS | VERIFY_FUNCTION | FUNCTION | +-------+------------------+----------+ 3 rows in setUSER_SOURCEビューを使用して、現在のユーザーが持つ関数VERIFY_FUNCTIONの内容を確認します。USER_SOURCEビューには、システム内の現在のユーザーが持つすべてのストアドプロシージャと関数が記録されています。USER_SOURCEビューとそのフィールドの詳細については、USER_SOURCEを参照してください。例:
obclient>SELECT TEXT FROM USER_SOURCE WHERE NAME='VERIFY_FUNCTION' AND TYPE='FUNCTION'\G *************************** 1. row *************************** TEXT: FUNCTION verify_function (username varchar2, password varchar2, old_password varchar2) -- この例では、3つの関数パラメータがカスタマイズされています---ユーザー名username、新しいパスワードpassword、古いパスワードold_password RETURN boolean IS differ integer; pw_lower varchar2(256); db_name varchar2(40); i integer; simple_password varchar2(10); reverse_user varchar2(32); BEGIN IF NOT complexity_check(password, 8, NULL, 1, 1, NULL, 1) THEN RETURN(FALSE); END IF; -- Check if the password contains the username pw_lower := LOWER(password); IF instr(pw_lower, LOWER(username)) > 0 THEN raise_application_error(-20002, 'Password contains the username'); END IF; -- Check if the password contains the username reversed reverse_user := ''; FOR i in REVERSE 1..length(username) LOOP reverse_user := reverse_user || substr(username, i, 1); END LOOP; IF instr(pw_lower, LOWER(reverse_user)) > 0 THEN raise_application_error(-20003, 'Password contains the username ' || 'reversed'); END IF; -- Check if the password contains the server name db_name := 'oceanbase'; IF instr(pw_lower, LOWER(db_name)) > 0 THEN raise_application_error(-20004, 'Password contains the server name'); END IF; -- Check if the password contains 'oracle' IF instr(pw_lower, 'oracle') > 0 THEN raise_application_error(-20006, 'Password too simple'); END IF; RETURN(TRUE); END 1 row in set
その他の関数管理に関する操作については、ストアドプロシージャと関数の管理を参照してください。