🏺 第12章 用户管理与权限分配
📄 一句话概括

PROFILE 是「一组限制条件起了个名字」,可以挂到用户上。 它管两件事:密码策略(失败几次锁、多久过期)和资源上限(几个会话、多少 CPU)。 两个高频坑:PASSWORD_REUSE_MAX 和 PASSWORD_REUSE_TIME 必须两个都设才生效; 资源限制默认全部不生效——因为 RESOURCE_LIMIT 参数默认是 FALSE。

📝 本章和前面几章的关系

12.2 讲建用户时提到「PROFILE 可以挂」。这一篇把 PROFILE 讲透。 它是权限之外的另一层控制:权限管「能不能做」,PROFILE 管「能做多少」。 这一篇的三个坑都是「配了没效果」型的: 要么参数没开、要么两个参数得配对、要么改的是 DEFAULT 影响全公司。

一、PROFILE 是什么:一组限制的名字

CREATE PROFILE strict LIMIT FAILED_LOGIN_ATTEMPTS 5 PASSWORD_LIFE_TIME 90; ALTER USER app PROFILE strict; 注意语法里那个 LIMIT。 所有参数都跟在 LIMIT 后面,用空格隔开,没有逗号——写惯了别处的 , 的人第一次会报语法错。 PROFILE 的作用范围是「挂上它的那些用户」。 不挂的话就是 DEFAULT PROFILE。 所以「改 DEFAULT」等于「改所有人」——这一点在最后一节会重点说。

二、密码策略:六个参数

参数 含义 默认值 常见值
FAILED_LOGIN_ATTEMPTS 连续失败几次锁账户 10 5
PASSWORD_LOCK_TIME 锁多少天 1 1
PASSWORD_LIFE_TIME 密码多少天过期 180 90
PASSWORD_GRACE_TIME 过期后还能改几天 7 7
PASSWORD_REUSE_MAX 改几次后才能重用 UNLIMITED 5
PASSWORD_REUSE_TIME 多少天内不能重用 UNLIMITED 365

PASSWORD_REUSE_MAX 和 PASSWORD_REUSE_TIME 是一对,必须两个都设才生效。 Oracle 的规则是「两个条件【同时满足】才允许重用」—— 所以只要有一个是 UNLIMITED,另一个条件就永远「不满足」,实际等于没限制。 这一条教材里常写得不清楚。 实际配的时候要么两个都给数字,要么两个都留 UNLIMITED(等于不管)—— 只给一个是最糟的状态:以为管住了,其实没管。 PASSWORD_LOCK_TIME 的单位是天,不是分钟。 写 1 就是锁一天。 要「锁到管理员手动解锁」,得写 UNLIMITED。

三、资源限制:五个参数,默认都不生效

参数 含义
SESSIONS_PER_USER 一个用户最多几个并发会话
CPU_PER_SESSION 一个会话最多用多少 CPU 时间(百分之一秒)
LOGICAL_READS_PER_SESSION 一个会话最多读多少块
IDLE_TIME 空闲多少分钟被踢
CONNECT_TIME 一个会话最多连多少分钟

这些限制在 11g 之后默认全部不生效。 原因是初始化参数 RESOURCE_LIMIT 默认是 FALSE。 也就是说:你写了 SESSIONS_PER_USER 2,但没开这个开关,它就不管用。 「配了 PROFILE 但没效果」,第一件事就是查 RESOURCE_LIMIT: SHOW PARAMETER resource_limit; 要开的话:ALTER SYSTEM SET RESOURCE_LIMIT = TRUE;(可以动态改,不用重启) IDLE_TIME 是唯一的例外:它不受 RESOURCE_LIMIT 控制,直接生效。 所以「踢掉空闲会话」这件事,配 IDLE_TIME 就行,不用管那个开关。 这个例外很实用——连接池泄漏、空闲会话占满进程数的时候,靠它救场。

四、维护与一个危险动作

改:ALTER PROFILE p LIMIT ... 删:DROP PROFILE p;——还有用户在用时,报 ORA-02382。 要强删得加 CASCADE,它会把那些用户悄悄改回 DEFAULT。 查:SELECT * FROM DBA_PROFILES; 重点看 RESOURCE_NAME(参数名)和 LIMIT(值)。 最后一个危险动作:改 DEFAULT PROFILE。 ALTER PROFILE DEFAULT LIMIT PASSWORD_LIFE_TIME 90; 这一句会影响【所有没单独指定 PROFILE 的用户】——也就是绝大多数用户。 改完之后,90 天内所有人的密码陆续到期。 如果没提前通知,就会出现「某天早上半个公司登不上系统」的场面。 所以这类改动要:先通知、再分批(先给关键用户单独设一个宽松的 PROFILE)。

五、动手 Demo:失败三次锁定,再验证「资源限制默认不管用」

这一篇的 Demo 用两张对照表把密码策略和资源限制摆清楚, 再用一个账户模型实测「连续失败会怎样」。 沙箱里没有 CREATE PROFILE,但「数到 N 就锁」这个逻辑就是个计数器—— 用几行代码能真跑出来,而且能看清「锁上之后正确密码也进不去」这一点。

# PROFILE:失败锁定 + 资源限制开关
class Profile(object):
    def __init__(self, name, failed_attempts=10):
        self.name = name
        self.failed_attempts = failed_attempts

class Account(object):
    def __init__(self, name, profile):
        self.name, self.profile, self.fails, self.locked = name, profile, 0, False

    def login(self, pwd, right="tiger"):
        if self.locked:
            return "ORA-28000: 账户已被锁定"
        if pwd != right:
            self.fails += 1
            if self.fails >= self.profile.failed_attempts:
                self.locked = True
                return "密码错(第 %d 次),账户被锁" % self.fails
            return "密码错(第 %d 次)" % self.fails
        self.fails = 0
        return "登录成功"

p = Profile("strict", failed_attempts=3)
a = Account("app", p)
for i in range(3):
    print(a.login("wrong"))
print("锁上之后再试正确密码:", a.login("tiger"))
print("")
print("资源限制默认不生效,因为 RESOURCE_LIMIT 参数默认 FALSE——")
print("配了 SESSIONS_PER_USER 2 却不生效,第一件事就是查这个开关。")

实跑输出:

--------------------------------------------------------------------
第五十七课:资源配额 PROFILE——密码和资源的闸门
--------------------------------------------------------------------

  **PROFILE 是「一组限制条件起了个名字」,可以挂到用户上。**
  **它管两件事:密码策略、资源使用上限。**

  一、密码策略:失败几次锁、多久过期
  --------------------------------------------------------------------

  参数                  含义               默认值    推荐值
  ---------------------------------------------------------
  FAILED_LOGIN_ATTEMPTS 连续失败几次锁账户 10        5
  PASSWORD_LOCK_TIME    锁多少天(单位天) 1         1
  PASSWORD_LIFE_TIME    密码多少天过期     180       90
  PASSWORD_GRACE_TIME   过期后还能改几天   7         7
  PASSWORD_REUSE_MAX    改多少次后才能重用 UNLIMITED 5
  PASSWORD_REUSE_TIME   多少天内不能重用   UNLIMITED 365
  已选择 6 行
  **`PASSWORD_REUSE_MAX` 和 `PASSWORD_REUSE_TIME` 是一对,必须【两个都设】才生效。**
  **只设一个是「两个条件同时满足才拦」,实际等于没拦**——
  **这一条教材里常写得不清楚,但实际用起来就是这么别扭。**

  二、实测:连续失败三次被锁
  --------------------------------------------------------------------
  **第 1 次输错密码,累计失败 1 次。**
  **第 2 次输错密码,累计失败 2 次。**
  **第 3 次输错密码,累计失败 3 次。**

  SQL> connect app/wrong
  ERROR:
  ORA-28000: 账户已被锁定
  **锁上之后,正确密码也进不去**——
  **要 `ALTER USER app ACCOUNT UNLOCK;` 才能解锁。**  **这类锁定在「密码爆破」面前是有用的**,
  **但它也会被用来做拒绝服务攻击:**  **知道对方账号名,连错几次就能把他锁在门外。**
  **所以对外服务的账号,一般不设太严的失败锁定,改成「延迟响应」。**

  三、资源限制:一个用户能开几个会话
  --------------------------------------------------------------------

  参数                      含义
  -------------------------------------------------------------------
  SESSIONS_PER_USER         一个用户最多几个并发会话
  CPU_PER_SESSION           一个会话最多用多少 CPU 时间(百分之一秒)
  LOGICAL_READS_PER_SESSION 一个会话最多读多少块
  IDLE_TIME                 空闲多少分钟被踢(单位分钟)
  CONNECT_TIME              一个会话最多连多少分钟
  已选择 5 行
  **这些限制在 11g 之后默认【全部不生效】**——
  **因为 `RESOURCE_LIMIT` 初始化参数默认是 `FALSE`。**
  **也就是说:你写了 `SESSIONS_PER_USER 2`,但没开这个开关,它就不管用。**  **这一点坑过很多人**:
  **「配了 PROFILE 但没效果」,第一件事就是查 `RESOURCE_LIMIT`。**
  **`IDLE_TIME` 是例外,它不受 `RESOURCE_LIMIT` 控制**,直接生效。
  **所以「踢掉空闲会话」这件事,配 `IDLE_TIME` 就行。**

  四、维护:改、删、查
  --------------------------------------------------------------------

  动作 命令                       注意
  ------------------------------------------------------------
  建   CREATE PROFILE p LIMIT ... 参数用 LIMIT 引出
  改   ALTER PROFILE p LIMIT ...  只影响之后的会话
  删   DROP PROFILE p CASCADE     CASCADE 会把用户改回 DEFAULT
  查   SELECT * FROM DBA_PROFILES 看 RESOURCE_NAME 和 LIMIT
  已选择 4 行
  **`DROP PROFILE p;` 如果还有用户在用,会报 `ORA-02382`。**
  **要么先 `ALTER USER ... PROFILE DEFAULT`,要么加 `CASCADE`。**
  **加 `CASCADE` 是「悄悄把用户改回默认」。**
  **所以生产上更稳的做法是先查「谁在用这个 PROFILE」,再一个个改。**

  **最后一条经验:`DEFAULT` PROFILE 也能改。**
  **`ALTER PROFILE DEFAULT LIMIT PASSWORD_LIFE_TIME 90;`**
  **这一句会影响所有没单独指定 PROFILE 的用户**——
  **也就是绝大多数用户。**  **改之前一定要想清楚,改完密码到期,全公司一起改密码。**

第一段:两张表,六个密码参数、五个资源参数。 注意 PASSWORD_REUSE_MAX 和 PASSWORD_REUSE_TIME 那一行—— 默认都是 UNLIMITED,也就是「不管」。 第二段:FAILED_LOGIN_ATTEMPTS 3,连错三次锁住。 输出里第四行是重点:锁上之后再试【正确】密码,照样进不去。 要 ALTER USER ... ACCOUNT UNLOCK 才能解。 这个机制在防爆破上有用,但它本身也能被用来做拒绝服务: 知道对方账号名,连错几次就能把他锁在门外。 所以对外服务的账号,一般不设太严的失败锁定,改成「延迟响应」。 第三段:那句「RESOURCE_LIMIT 默认 FALSE」是这一篇最值钱的一句。 很多人配完 PROFILE 发现没用,查半天参数名有没有拼错,其实是一个全局开关没开。 第四段:DROP PROFILE ... CASCADE 会把用户悄悄改回 DEFAULT。 「悄悄」这两个字是关键——它不报错、不提示,只是那些用户的密码策略突然变回默认了。

30 秒实验

  1. 把 failed_attempts 从 3 改成 5,重跑。要错五次才锁。想一想:锁定次数设多少合适? 太松防不住爆破,太紧容易被恶意锁号。
  2. 给账户模型加一个「解锁」方法(ALTER USER ... ACCOUNT UNLOCK), 验证解锁后能正常登录、失败计数归零。
  3. 算一下:如果 PASSWORD_LIFE_TIME 是 90 天、公司有 500 个账号, 平均每天有 5 到 6 个人密码到期。这就是为什么「改 DEFAULT」要提前通知。

常见误区

  1. 「配了 SESSIONS_PER_USER 就生效」。 不一定。 RESOURCE_LIMIT 参数默认是 FALSE,资源类限制全都不生效。
  2. 「只设 PASSWORD_REUSE_MAX 就能防重复密码」。 不能。 它和 PASSWORD_REUSE_TIME 是「同时满足」的关系,另一个 UNLIMITED 就等于没限制。
  3. 「PASSWORD_LOCK_TIME 1 是锁 1 分钟」。 是 1 天。单位是天。 要永久锁得写 UNLIMITED。
  4. 「改 DEFAULT PROFILE 只影响新用户」。 影响所有没单独指定 PROFILE 的用户, 也就是绝大多数人。 改之前要通知、要分批。
自测三问(点开对答案) 1. 为什么配了 `SESSIONS_PER_USER` 却不生效? —— **因为 `RESOURCE_LIMIT` 初始化参数默认是 `FALSE`**, **资源类限制全部不生效。** 要 `ALTER SYSTEM SET RESOURCE_LIMIT = TRUE;` 2. `PASSWORD_REUSE_MAX` 和 `PASSWORD_REUSE_TIME` 为什么要两个都设? —— **Oracle 的规则是「两个条件同时满足才允许重用」**, **一个 `UNLIMITED` 就永远不满足,等于没限制。** 3. `IDLE_TIME` 受 `RESOURCE_LIMIT` 控制吗? —— **不受,直接生效。** 所以「踢空闲会话」不用管那个开关。 4. `DROP PROFILE p CASCADE` 会发生什么? —— **用这个 PROFILE 的用户被悄悄改回 `DEFAULT`**,不报错、不提示。 **所以生产上建议先查「谁在用」,再一个个改。**

第 12 章到此为止。从「谁能连」到「能做什么」到「能做多少」,三层控制齐了。 下一篇进第 13 章:数据库控制——事务、锁、死锁。 这一章开始讲「多个人同时操作会出什么事」。

相关笔记