Oracle Databaseのパスワード・ポリシー設定

# 1. はじめに

Oracle Databaseには、ユーザー・プロファイルを通じてパスワード・ポリシーを設定することができます。
パスワード・ポリシーは、次の手順で設定します。
1. パスワード・ポリシー関数の作成(既存のパスワード・ポリシー関数の利用も可能です)
2. ユーザー・プロファイルのpassword_verify_functionパラメーターに、パスワード・ポリシーを設定

パスワード・ポリシーを設定する方法は次のとおりです。

```sql
-- 新規にprofileを作成する際にパスワード・ポリシー関数を指定する場合
create profile profile名 limit password_verify_function password_policy_function名;

-- 既存のprofileにパスワード・ポリシー関数を設定する場合
alter profile profile名 limit password_verify_function password_policy_function名;
```

profile名に指定されているユーザーにパスワード・ポリシーが反映されます。
新規ユーザーを作成する際にパスワード・ポリシーが設定されたprofileを指定した場合、identified句で指定するパスワードがパスワード・ポリシーを満たすか検証されます。
既存ユーザーに設定されているprofileにパスワード・ポリシー関数を設定した場合、現在のパスワードには影響なく、次回パスワード変更時にパスワード・ポリシーを満たすか検証されます。

既存のprofileにパスワード・ポリシーを無効にする場合は、password_verify_functionにnullを指定します。

```sql
-- 既存のprofileへの設定時
alter profile profile名 limit password_verify_function null;
```

# 2. 既存のパスワード・ポリシーについて

Oracle Database 19cには、4つのパスワード・ポリシーが定義されています。

|   #|パスワード・ポリシー関数          |パスワード長|文字種別                                            |前回のパスワードとの違い |その他   |
|---:|----------------------------------|------------|----------------------------------------------------|-------------------------|---------|
|   1|verify_function_11G               |8文字以上   |数字と英字をそれぞれ1つ以上                         |3文字以上                |*1       |
|   2|ora12c_verify_function            |8文字以上   |数字と英字と特殊文字をそれぞれ1つ以上               |3文字以上                |*2       |
|   3|ora12c_strong_verify_function     |9文字以上   |数字と英大文字と英小文字と特殊文字をそれぞれ2つ以上 |4文字以上                |         |
|   4|ora12c_stig_verify_function       |15文字以上  |数字と英大文字と英小文字と特殊文字をそれぞれ1つ以上 |8文字以上                |         |

*1 パスワードがユーザー名と同一でない、ユーザー名の逆順と同一でない、ユーザー名に数字1から100を追加したパスワードでない、サーバー名と同一でない、サーバー名に数字1から100を追加したパスワードでない、文字列oracleが含まれていない、パスワードを単純にしすぎない。
*2 パスワードがユーザー名と同一でない、ユーザー名の逆順と同一でない、文字列oracleが含まれていない。
※ どのポリシーにおいても、ダブルクォーテーション(")をパスワードに含むことはできません。

[[19c][セキュリティ・ガイド] > [3.2.6 パスワードの複雑度の管理]](https://docs.oracle.com/cd/F19136_01/dbseg/configuring-authentication.html#GUID-00BED08C-E064-4824-9697-C7219CB8D3AB)

# 3. カスタム・パスワード・ポリシーの作成

既存のパスワード・ポリシー関数は、下記スクリプト内で定義されています。

```bash
$ORACLE_HOME/rdbms/admin/catpvf.sql
```

カスタム・パスワード・ポリシーを作成する場合、このスクリプトの内容を参考に作成するとよいでしょう。
では、次のようなパスワード・ポリシーを作成してみます。

パスワード・ポリシー関数名：my_password_verify_function
パスワード長：12文字以上
文字種別    ：数字と英大文字と英子文字と特殊文字をそれぞれ2文字以上
前回のパスワードとの違い：10文字以上

## 3.1 パスワード・ポリシーの作成

スクリプト $ORACLE_HOME/rdbms/admin/catpvf.sql 内で定義されている関数 ora12c_strong_verify_function を基に作成します。

```sql:my_password_verify_function
-- sysユーザーで実行
create or replace function my_password_verify_function(
  username     varchar2,
  password     varchar2,
  old_password varchar2
) return boolean IS
  differ       integer;
  complexity   boolean;
  lang         varchar2(512);
  message      varchar2(512);
  ret          number;

begin
  -- utl_lmsメッセージ用の言語設定
  lang := sys_context('userenv','lang');
  lang := substr(lang,1,instr(lang,'_')-1);

  -- パスワードの複雑さチェック
  complexity := ora_complexity_check(
    password  => password, 
    chars     => 12, -- パスワード長:12文字以上
    uppercase => 2,  -- 英大文字:2文字以上
    lowercase => 2,  -- 英子文字:2文字以上
    digit     => 2,  -- 数字    :2文字以上
    special   => 2   -- 特殊文字:2文字以上
  );

  if not complexity then
    return(false);
  end if;

  -- 前回パスワードとの違い確認
  if old_password is not null then
    differ := ora_string_distance(old_password, password);
    if differ < 10 then
       ret := utl_lms.get_message(28211, 'RDBMS', 'ORA', lang, message);
       raise_application_error(-20000, utl_lms.format_message(message, '10'));
    end if;
  end if;

  return(true);
end;
/
show errors;

GRANT EXECUTE ON my_password_verify_function TO PUBLIC;

```

ここのmy_password_verify_functionの引数にあるold_passwordは、password句でのパスワードの変更の場合に値が入ります。
つまり、前回パスワードとの違い確認はpassword句へのパスワード変更の場合のみ検証され、alter user句でのパスワード変更の場合は検証されません。

## 3.2 ユーザー・プロファイルの作成

パスワード・ポリシー my_password_verify_functionを設定するユーザー・プロファイルを新規に作成します。

```sql
-- sysユーザーで実行
create profile my_profile limit password_verify_function my_password_verify_function;

-- ユーザー・プロファイルの確認
set pagesize 50000
select * from dba_profiles where profile = upper('my_profile') and resource_name = upper('password_verify_function');
```

# 4. カスタム・パスワード・ポリシーの確認

データベース・ユーザーを作成するタイミングで、パスワード・ポリシーを確認します。

```sql
create user passwd_test
  identified by Password_Test
  default tablespace users
  quota unlimited on users
  profile my_profile
;
```

パスワード Password_Test はパスワードポリシーに反している(文字種別)ため、上記DDLは失敗します。

```
create user passwd_test
*
行1でエラーが発生しました。:
ORA-28003: 指定されたパスワードのパスワード照合に失敗しました。 ORA-20000: password must
contain 2 or more digits
```

ORA-20[0-9][0-9][0-9]は、raise_application_errorから発行されるエラーです。
マニュアルには載っていないので、都度内容を確認して対応する必要があります。

次のように、数字と英大文字と英子文字と特殊文字を2文字以上ずつ設定すると、ユーザーが作成できます。

```sql
create user passwd_test
  identified by Password_Test#99
  default tablespace users
  quota unlimited on users
  profile my_profile
;
```

# 参考

[[19c][セキュリティ・ガイド] > [3.2.6 パスワードの複雑度の管理]](https://docs.oracle.com/cd/F19136_01/dbseg/configuring-authentication.html#GUID-00BED08C-E064-4824-9697-C7219CB8D3AB)
[[19c][SQL言語リファレンス] > [ALTER PROFILE]](https://docs.oracle.com/cd/F19136_01/sqlrf/ALTER-PROFILE.html)
[[19c][SQL言語リファレンス] > [CREATE PROFILE]](https://docs.oracle.com/cd/F19136_01/sqlrf/CREATE-PROFILE.html)