只有负责决定是否允许访问的系统检查了适用截止时间,凭据才真的会到期。在资产清单里写一个日期,不会自动改变数据库或接口接受什么。较短有效期可以压缩被盗凭据继续建立新访问的时间窗口,但具体效果取决于认证机制,以及此前已经建立的会话、签发的其他凭据如何处理。秘密不是因为自身附带一行日期,就能独立让所有访问失效。
坏掉的样子 到期不会撤销已经发生的行为。复制出去的数据仍在外面,截止时间之前建立的会话也可能继续工作。攻击者还可能在原本有效的权限下建立另一条访问路径。因此,有效期只是限制后续使用的一种手段,还要结合权限范围、撤销机制、会话管理和对实际影响的调查。它并不能为一次泄漏造成的全部损失设定通用上限,也不能把过去的访问自动变成没有发生过。
PostgreSQL 的 VALID UNTIL 控制角色密码的有效时间,不控制角色是否存在,也不覆盖所有认证方式。使用非密码方式建立连接,就不会获得同样的截止检查。如果通过本地信任规则来测试密码到期,便可能误以为到期功能失效。判断结果之前,应先确认客户端实际命中了哪条认证路径,不能只看两次连接用了同一个用户名。
轮换与续期是两个不同变化。替换密码不一定改变到期日期,延长日期也不等于替换值。更新流程如果只修改其中一项,可能导致应用依然无法重新连接,也可能让原值继续有效。一个连接池里的旧连接查询成功,不足以证明新凭据能够完成新的认证,因为它可能根本没有重新交出密码接受检查。
快速验证 准备隔离的 Linux 实验环境,让 PostgreSQL 18 程序位于 PATH 中,以非 root 用户运行,并确认回环端口 55477 未被使用。将下列内容保存为脚本,用 sh 执行。它初始化一次性数据库集群,只使用明确虚构的密码,TCP 仅监听回环地址,退出时删除临时目录。本地信任认证只为展示另一条认证路径而启用,不应照搬到真实服务:
#!/bin/sh set -eu lab_root=$(mktemp -d /tmp/credential-expiry.XXXXXX) cleanup() { if test -f "$lab_root/data/postmaster.pid"; then pg_ctl -D "$lab_root/data" -m immediate -w stop >/dev/null fi rm -rf "$lab_root" } trap cleanup EXIT initdb -D "$lab_root/data" --locale=C --auth-local=trust --auth-host=scram-sha-256 >/dev/null pg_ctl -D "$lab_root/data" -l "$lab_root/server.log" \ -o "-k $lab_root -p 55477 -c listen_addresses=127.0.0.1" -w start >/dev/null admin() { psql -X -qAt -v ON_ERROR_STOP=1 -h "$lab_root" -p 55477 -d postgres "$@" } # Both passwords below are invented, disposable lab fixtures. admin <<'SQL' SET password_encryption='scram-sha-256'; CREATE ROLE article_expiry LOGIN PASSWORD 'LAB-ONLY-OLD-PASSWORD'; SQL mkfifo "$lab_root/input" PGPASSWORD=LAB-ONLY-OLD-PASSWORD psql -X -qAt -v ON_ERROR_STOP=1 \ -h 127.0.0.1 -p 55477 -U article_expiry -d postgres \ <"$lab_root/input" >"$lab_root/held.out" 2>"$lab_root/held.err" & held_pid=$! exec 3>"$lab_root/input" printf "SELECT 'ready';\n" >&3 attempt=0 until grep -qx ready "$lab_root/held.out"; do attempt=$((attempt + 1)) test "$attempt" -lt 100 sleep 0.05 done admin <<'SQL' SELECT format('ALTER ROLE article_expiry VALID UNTIL %L', clock_timestamp()+interval '1 second') \gexec SELECT pg_sleep(1.2); SELECT 'deadline passed='||(rolvaliduntil<clock_timestamp()) FROM pg_authid WHERE rolname='article_expiry'; SQL if PGPASSWORD=LAB-ONLY-OLD-PASSWORD psql -X -qAt -h 127.0.0.1 -p 55477 \ -U article_expiry -d postgres -c 'SELECT 1' >"$lab_root/new.out" 2>"$lab_root/new.err"; then exit 1 fi grep -q 'password authentication failed' "$lab_root/new.err" printf '%s\n' 'fresh SCRAM login rejected after expiry' printf "SELECT 'held after expiry='||current_user;\n" >&3 psql -X -qAt -v ON_ERROR_STOP=1 -h "$lab_root" -p 55477 \ -U article_expiry -d postgres -c "SELECT 'local trust login='||current_user" admin <<'SQL' SET password_encryption='scram-sha-256'; ALTER ROLE article_expiry PASSWORD 'LAB-ONLY-NEW-PASSWORD'; SQL if PGPASSWORD=LAB-ONLY-NEW-PASSWORD psql -X -qAt -h 127.0.0.1 -p 55477 \ -U article_expiry -d postgres -c 'SELECT 1' >"$lab_root/rotated.out" 2>"$lab_root/rotated.err"; then exit 1 fi grep -q 'password authentication failed' "$lab_root/rotated.err" printf '%s\n' 'rotating password alone preserves expired deadline' admin <<'SQL' SELECT format('ALTER ROLE article_expiry VALID UNTIL %L', clock_timestamp()+interval '1 hour') \gexec SQL if PGPASSWORD=LAB-ONLY-OLD-PASSWORD psql -X -qAt -h 127.0.0.1 -p 55477 \ -U article_expiry -d postgres -c 'SELECT 1' >"$lab_root/old.out" 2>"$lab_root/old.err"; then exit 1 fi grep -q 'password authentication failed' "$lab_root/old.err" printf '%s\n' 'old password rejected after rotation' PGPASSWORD=LAB-ONLY-NEW-PASSWORD psql -X -qAt -v ON_ERROR_STOP=1 \ -h 127.0.0.1 -p 55477 -U article_expiry -d postgres \ -c "SELECT 'new password login='||current_user" printf "SELECT 'held after rotation='||current_user;\n" >&3 printf '\\q\n' >&3 exec 3>&- wait "$held_pid" grep -qx 'held after expiry=article_expiry' "$lab_root/held.out" grep -qx 'held after rotation=article_expiry' "$lab_root/held.out" cat "$lab_root/held.out" 记录中的 PostgreSQL 18.6 实测输出确认截止时间已经过去。脚本把期限设为数据库当前时间的一秒之后,然后等待数据库时钟越过它,所以这里实际经历了到期,而不是只拿一个编造日期做字符串比较。随后,通过 SCRAM 密码认证建立的新连接被拒绝,验证了真正决定认证结果的服务端规则。
...