Self-Service Password 1.8.2 配置参数详解

Self-Service Password 1.8.2 全量配置参数详解:config.inc.php 十组参数逐项整理默认值与生产含义,LDAP 连接、密码策略、安全问题、Token、邮件、限流、Hook 审计逐组实测生效行为,附中文界面切换与限流触发实录及生产配置模板。

Self-Service Password密码管理LDAP身份认证PHP 应用2026/10/24

Self-Service Password 1.8.2 配置参数详解

目标:把 Self-Service Password(下文简称 SSP)1.8.2 的 config.inc.php 全量参数按官方默认值整理成表,逐组给出生产含义与实测生效行为,并提供一套可直接落地的生产配置模板。本文所有参数键名与默认值逐行取自 1.8.2 镜像内 /var/www/conf/config.inc.php(实测 542 行),生效行为均在 Ubuntu 22.04.4 + SSP 1.8.2 + OpenLDAP 2.4.57 环境实测验证。

一、环境信息

  • 操作系统:Ubuntu 22.04.4 LTS(x86_64),Docker 29.8.1 + Docker Compose v5.5.1
  • SSP:ltbproject/self-service-password:1.8.2(PHP 8.5.12 + Apache,ldap 扩展内置)
  • 目录端:osixia/openldap:latest(slapd 2.4.57),基准 DN dc=example,dc=org
  • 测试用户:alice、bob(inetOrgPerson,带 mail/mobile 属性)
  • 参数源文件:镜像内 /var/www/conf/config.inc.php(默认值)+ /var/www/conf/config.inc.local.php(覆盖层,本文实测配置)
  • 部署与栈结构见《Self-Service Password 1.8.2 Docker Compose 部署指南》;定位与选型见《Self-Service Password 1.8.2 介绍与选型指南》

二、前置条件

  1. 已按部署指南拉起 SSP + OpenLDAP 栈,SSP 页面可访问;
  2. 能进入 SSP 侧读默认配置与写覆盖配置(镜像内 /var/www/conf/ 目录);
  3. 目录端具备基础 ACL(安全问题重置链路需要 self 对 info,objectClass 的写权,见部署指南 4.2 节);
  4. 安全问题与邮件链路实测需要已注册邮箱的测试用户。

三、参数查看与修改方式

3.1 两层配置结构

SSP 的配置是「默认值 + 覆盖层」两层结构。镜像内主配置 /var/www/conf/config.inc.php 末尾自带覆盖机制(实测源码节选):

# Allow to override current settings with local configuration
if (file_exists (__DIR__ . '/conf/config.inc.local.php')) {
    require_once __DIR__ . '/conf/config.inc.local.php';
}
  • config.inc.php:官方默认值,升级会被镜像内容覆盖,禁止直接改;
  • config.inc.local.php:用户覆盖层,同目录、后加载、同名变量即覆盖,所有自定义都写这里;
  • 另有 HTTP 头触发的第三层(默认关闭):$header_name_extra_config="SSP-Extra-Config" 开启后,请求头 SSP-Extra-Config: xxx 可按需加载 conf/config.inc.xxx.php,适合多租户差异化配置。

3.2 查看当前生效值

容器内用 PHP 直接打印变量(实测):

docker exec self-service-password-182-web php -r 'require "/var/www/conf/config.inc.php"; echo $ldap_url, " | ", $hash, " | ", $mail_smtp_host, ":", $mail_smtp_port, "\n";'

实测回显:

ldap://openldap:389 | SSHA | mailsink:1025

输出为覆盖层生效后的值(mailsink:1025、SSHA 均来自 config.inc.local.php,非官方默认 localhost:25、clear),证明覆盖机制生效。

3.3 修改与生效方式

编辑覆盖文件后重启 SSP 使配置生效(实测):

docker compose restart ssp

配置文件为 PHP 语法,写错会直接导致页面 500——修改前建议 php -l config.inc.local.php 做语法检查。

四、参数总览

1.8.2 官方默认配置共 10 组约 130 个参数,分组总览如下(默认值逐行取自镜像内文件):

分组代表参数默认值要点
调试$debug / $debug_levelfalse;仅记录错误
LDAP 连接$ldap_url / $ldap_binddn / $ldap_baseldap://localhost;cn=manager,dc=example,dc=com
目录类型$ldap_type / $ldap_optionsopenldap;force_unlock/force_pwd_change/change_expired 均关
密码存储$hash / $hash_optionsclear(生产必须改);CRYPT 盐前缀 $6$
限流$use_ratelimitfalse(默认关闭)
密码策略$pwd_min_length 等 15 项全 0(不限制),仅 no_reuse/diff_login 默认开
改密身份$who_change_passworduser(以用户自身身份改密)
功能开关$use_change / $change_sshkey / $use_attributes改密开、SSH Key 改动关、属性页关
安全问题$use_questions / $answer_attribute开;答案存 info、extensibleObject 辅助类、答案加密
Token$use_tokens / $crypt_tokens / $token_lifetime开;加密;3600 秒
缓存$cache_type / $cache_token_expirationFile;token 缓存 3600 秒
邮件$mail_smtp_host / $mail_smtp_securelocalhost:25;tls + autotls(内网明文 SMTP 必改)
短信$use_sms / $sms_methodtrue(默认开!无网关时必须显式关);mail 方式
加密密钥$keyphrasesecret(1.8.2 强制要求改为随机串)
界面语言$lang / $allowed_langen;不限制语言
动作入口$default_actionchange
验证码$use_captcha / $captcha_classfalse;InternalCaptcha(另有 FriendlyCaptcha/ReCaptcha)
REST API$use_restapifalse
Hook$prehook / $posthook未启用
审计$audit_log_file未启用(默认仅 Apache 日志)

五、核心参数分类详解

5.1 LDAP 连接与目录类型

$ldap_url = "ldap://localhost";          # 目录地址,可写 ldap://host:389 或 ldaps://host:636
$ldap_starttls = false;                  # 连接后是否发起 STARTTLS
$ldap_binddn = "cn=manager,dc=example,dc=com";   # 搜索绑定 DN
$ldap_bindpw = 'secret';                 # 搜索绑定密码
$ldap_base = "dc=example,dc=com";        # 搜索基准
$ldap_login_attribute = "uid";           # 登录名属性
$ldap_fullname_attribute = "cn";         # 显示名属性
$ldap_filter = "(&(objectClass=person)($ldap_login_attribute={login}))";  # 用户过滤
$ldap_scope = "sub";                     # sub / one / base
$ldap_use_exop_passwd = false;           # LDAP EXOP PASSWD 扩展改密(RFC 3062)
$ldap_use_ppolicy_control = false;       # 携带 ppolicy 控制获取服务端策略消息
$ldap_network_timeout = 10;              # 网络超时秒
$ldap_page_size = 0;                     # 分页搜索大小,0=不分页
$ldap_type = "openldap";                 # openldap / activedirectory
$ldap_options['force_unlock'] = false;           # 改密后强制解锁(AD)
$ldap_options['force_pwd_change'] = false;       # 改密后强制下次登录改密(AD)
$ldap_options['change_expired_password'] = false; # 允许过期密码登录改密(AD)

实测要点(本文环境):$ldap_url = "ldap://openldap:389" + $ldap_binddn = "cn=admin,dc=example,dc=org" 指向同栈 OpenLDAP,改密/重置/答案保存全部走通;$ldap_use_exop_passwd = true 开启后改密落库为目录端 SSHA 散列(实测 userPassword:: e1NTSEF9…)。

💡 技术拓展:$ldap_type 决定写密码的方式。openldap 走标准 userPassword;activedirectory 走 unicodePwd 特殊编码(UTF-16LE 加引号包裹),且 ad_mode 相关选项(含解锁、过期改密)只在 AD 语义下有意义。对接 AD 时 force_pwd_change 很实用——SSP 改完密码顺手把「下次登录必须改密」标记打上,衔接新员工初始密码流程。

GSSAPI 支持:注释掉 $ldap_binddn/$ldap_bindpw,改设 $ldap_krb5ccname = "/path/to/krb5cc" 可用 Kerberos 票据缓存做服务端绑定(免密码配置,生产 AD/OpenLDAP 集成环境常用)。

5.2 密码存储与改密身份

$hash = "clear";        # SSHA/SSHA256/SSHA384/SSHA512/SHA*/SMD5/MD5/CRYPT/ARGON2/clear/auto
$hash_options['crypt_salt_prefix'] = "$6$";   # CRYPT 模式的盐前缀($6$ 即 SHA-512 crypt)
$hash_options['crypt_salt_length'] = "6";
$who_change_password = "user";   # user=用户自身身份改密;manager=用 $ldap_binddn 身份
$show_extended_error = false;    # 展示目录返回的扩展错误(如密码太短的具体原因)
  • $hash:只在 SSP 侧先散列再写目录时生效(普通 Modify 路径)。clear 意味着明文入目录——生产强烈建议 SSHA 或 ARGON2(OpenLDAP 2.4.57 支持前两者;ARGON2 需要目录端支持)。auto 会按当前密码的既有散列算法自动选择,适合渐进式迁移。
  • $who_change_password:默认 user——SSP 先用管理员搜索到用户 DN,再用用户自己的凭据绑定执行修改。这要求 ACL 允许 self 写 userPassword(OpenLDAP 默认 ACL 即满足)。设为 manager 则用 $ldap_binddn 写入,适合 AD 或受限 ACL 环境,但管理员密码的权限面变大(见《Self-Service Password 1.8.2 安全加固指南》的最小权限分析)。
  • $show_extended_error:开启后把 LDAP 服务端拒绝原因透出给用户,排障友好但可能泄露目录策略细节,建议内网开、对外关。

5.3 本地密码策略 pw_* 族

$pwd_min_length = 0;            # 最小长度
$pwd_max_length = 0;            # 最大长度
$pwd_min_lower = 0;             # 最少小写字母
$pwd_min_upper = 0;             # 最少大写字母
$pwd_min_digit = 0;             # 最少数字
$pwd_min_special = 0;           # 最少特殊字符
$pwd_special_chars = "^a-zA-Z0-9";  # 特殊字符的判定集合(正则字符类,此处=非字母数字)
$pwd_no_reuse = true;           # 禁止与当前密码相同
$pwd_diff_login = true;         # 禁止与登录名相同
$pwd_diff_last_min_chars = 0;   # 新旧密码至少差 N 个字符
$pwd_forbidden_words = array(); # 禁用词表(公司名等)
$pwd_forbidden_ldap_fields = array();  # 用户条目字段值不得出现在密码里(如 cn/sn/mail)
$pwd_complexity = 0;            # 至少命中几类字符(0-4)
$use_pwnedpasswords = false;    # 调 pwnedpasswords API 查泄露库(需出网)
$pwd_display_entropy = false;   # 显示熵进度条(需 php zxcvbn 模块)
$pwd_check_entropy = false;     # 强制熵校验
$pwd_min_entropy = 3;           # 最低熵值
$pwd_show_policy = "never";     # 策略提示展示:always/never/onerror
$pwd_show_policy_pos = "above"; # 提示位置:above/below 表单
$pwd_no_special_at_ends = false; # 首尾不得用特殊字符

实测(覆盖层设 min_length=8、四类字符各 1、show_policy=always):

  • 提交弱密码 abc123(有数字无大写无特殊)→ 页面返回实测回显:Your password does not have enough special characters;
  • 提交合规密码 N3wPass!2026 → Your password was changed;
  • 策略提示块按 above 位置渲染在表单上方。

⚠️ 注意:$pwd_special_chars = "^a-zA-Z0-9" 是取反字符类(正则语义),即「非字母数字都算特殊字符」,不是「仅限 ^ 字符」。自定义集合时写成如 "!@#$%^&*()" 则变成白名单语义。这是配置 SSP 策略最常被误解的一项。

策略执行顺序:SSP 本地策略先校验,通过后才提交目录($ldap_use_ppolicy_control 开启时服务端 ppolicy 再验一轮)。两层策略都要过,生产上建议本地策略做兜底、目录 ppolicy 做权威。

5.4 安全问题 questions 族

$use_questions = true;                     # 功能开关
$multiple_answers = false;                 # 允许多个答案
$multiple_answers_one_str = false;         # 多答案合并存一个字符串属性
$answer_objectClass = "extensibleObject";  # 保存答案时追加的辅助类
$answer_attribute = "info";                # 答案存储属性
$crypt_answers = true;                     # 答案加密存储(用 $keyphrase)
$questions_use_default = true;             # 是否包含内置问题(lang/$lang.inc.php 中 2 个)
$questions_count = 1;                      # 需回答的问题数(>1 必须配合 multiple_answers)
$question_populate_enable = false;         # 仅凭登录名即可回显注册问题(用户体验/枚举风险权衡)

实测(本文环境):

  1. 注册答案 teal(问题 What is your favorite color?)→ 页面回显 Your answer has been registered;
  2. 目录落库实测(ldapsearch (uid=alice) info objectClass):
objectClass: inetOrgPerson
objectClass: extensibleObject
info: 3vUCACQAzkDYd9EtvhkWagaFWLMkQ/mpTC2xpJuQ3J6zBve+L2siiUWGfnyPxDYob7EoDUgP

答案以 $keyphrase 加密写入 info,条目自动追加 extensibleObject。 3. 正确答案重置成功(Your password was changed + 新密码 ldapwhoami 认证通过);错误答案被拦(Your answer is incorrect)。 4. 连错 2 次后第 3 次(限流开启状态)→ 实测回显:太快了!请稍后再试(如果真的是您手动操作)。

⚠️ 注意:答案写入依赖两层目录条件——self 对 $answer_attribute(默认 info)的写权,以及对 objectClass 的写权(追加 extensibleObject 用)。ACL 只开前者会得到 error 50 (Insufficient access),这是 1.8.x 安全问题链路最常见的失败点(实测复现见部署指南十一.3)。

5.5 Token 与缓存

$use_tokens = true;            # 邮件重置功能开关
$crypt_tokens = true;          # token 加密(URL 里的 token 为加密串)
$token_lifetime = "3600";      # token 有效期(秒)
$cache_type = "File";          # File / Redis
$cache_namespace = "sspCache";
$cache_directory = null;       # null=系统临时目录
$cache_token_expiration = 3600;   # token 相关缓存对象寿命(建议 ≥ $token_lifetime)
$cache_form_expiration = 120;     # 表单校验步骤缓存寿命(如邮箱确认表单)
$reset_url = "http://ssp.example.com/";   # 重置链接的对外地址(必配)

实测:发送重置邮件后正文链接 host 为 ssp.example.com(即默认 $reset_url),token 为加密串;携 token 打开重置表单提交新密码成功,旧密码随之失效。$reset_url 生产必须改为对外真实地址(反代场景官方注释给出按 X-Forwarded-* 头动态推导的写法)。

Redis 缓存:$cache_type = "Redis" + $cache_redis_url = "redis:user:password@?host[redis1:6379]&timeout=5&dbindex=0",多实例部署时共享 token 状态必配(File 缓存只在单实例内一致)。

5.6 邮件 mail_* 族

$mail_attributes = array( "mail", "gosaMailAlternateAddress", "proxyAddresses" );  # 依次尝试的邮箱属性
$mail_address_use_ldap = false;   # 直接从目录取邮箱并隐藏输入框
$mail_from = "admin@example.com"; # 发件人
$mail_from_name = "Self Service Password";
$mail_signature = "";
$notify_on_change = false;        # 改密成功后发通知
$mail_protocol = 'smtp';          # smtp / mail(PHP mail())
$mail_smtp_debug = 0;
$mail_debug_format = 'error_log';
$mail_smtp_host = 'localhost';
$mail_smtp_auth = false;
$mail_smtp_user = '';
$mail_smtp_pass = '';
$mail_smtp_port = 25;
$mail_smtp_timeout = 30;
$mail_smtp_keepalive = false;
$mail_smtp_secure = 'tls';        # tls / ssl / ''(空=明文)
$mail_smtp_autotls = true;        # 服务端宣告 STARTTLS 时自动升级
$mail_smtp_options = array();
$mail_contenttype = 'text/plain';
$mail_wordwrap = 0;
$mail_charset = 'utf-8';
$mail_priority = 3;

实测(关键坑):官方默认 $mail_smtp_secure='tls' + $mail_smtp_autotls=true,对无 TLS 的内网 SMTP 发信报 send_mail: SMTP connect() failed.(实测 docker logs 回显)。显式 $mail_smtp_secure = ''; $mail_smtp_autotls = false; 后重测,改密通知实测到达(SUBJ: Your password has been changed),重置邮件实测到达(SUBJ: Reset your password)。

💡 技术拓展:tls 与 ssl 的区别沿 PHPMailer 语义——tls 是先明文连上再 STARTTLS 升级(587 端口常见),ssl 是连上即 TLS(465 端口常见)。内网无证书环境置空即可;对外公网 SMTP 建议保持 tls。

5.7 短信 sms 族

$use_sms = true;             # 默认开启!
$sms_use_ldap = false;       # 直接从目录取手机号
$sms_method = "mail";        # mail(邮件转短信网关)/ api(库调用)
$sms_api_lib = "";           # 内置 signal-cli / twilio / ovh 三个库,也可自写
$sms_attributes = array( "mobile", "pager", "ipPhone", "homephone" );
$sms_partially_hide_number = true;
$smsmailto = "{sms_attribute}@service.provider.com";   # 邮件网关地址模板
$smsmail_subject = "Provider code";
$sms_message = "{smsresetmessage} {smstoken}";
$sms_sanitize_number = false;    # 去除非数字字符
$sms_truncate_number = false;    # 截断号码
$sms_truncate_number_length = 10;
$sms_token_length = 6;
$sms_max_attempts_token = 3;

实测(禁用行为):$use_sms = false 后导航菜单仅剩「问题」「邮件」两个重置入口(实测中文界面回显),sendtoken 与 sendsms 页面互不影响。本文实验环境无短信网关,显式关闭;生产若启用,mail 方式零开发成本(对接运营商邮件转短信网关),api 方式需确认所用库的凭据与出网策略。

5.8 界面与语言

$show_help = true;
$lang = "en";                    # 默认语言
$date_timezone = "UTC";
$allowed_lang = array();         # 空=全部放行;非空=白名单外回落 $lang
$show_menu = true;               # 顶部导航
$show_pwd = false;               # 密码输入框的眼睛按钮
$logo = "images/ltb-logo.png";
$background_image = "images/unsplash-space.jpeg";
$favicon = "images/favicon.ico";
$custom_css = "";                # 例 "css/sample.css"(相对 htdocs/html)
$display_footer = true;
$custom_tpl_dir = "";            # 模板覆盖目录
$default_action = "change";      # change / sendtoken / sendsms / changecustompwdfield

实测:

  1. $lang = "zh-CN"(镜像内 /var/www/lang/ 实测共 28 个语言文件,含 zh-CN/zh-TW)后页面全量中文化——改密页标题「修改您的密码」,导航「问题」「邮件」;
  2. $default_action = "sendtoken" 后访问根路径 / 直接渲染邮件重置表单(实测表单字段 login + formtoken,标签「用户名」),不再落在改密页。

⚠️ 注意:企业内部统一门户建议同时设 $lang 与 $allowed_lang(如只留 array("zh-CN")),避免用户浏览器语言导致界面意外切换。

5.9 安全防护族

$keyphrase = "secret";           # token/答案加密密钥——1.8.2 强制修改
$login_forbidden_chars = "*()&|";   # 登录名禁用字符(防 LDAP 注入;空=只允许字母数字)
$obscure_usernotfound_sendtoken = true;   # sendtoken 不泄露「用户不存在」
$obscure_notfound_sendsms = true;
$use_captcha = false;            # 验证码开关
$captcha_class = "InternalCaptcha";   # 内置图形验证码;另支持 FriendlyCaptcha / ReCaptcha
$use_ratelimit = false;          # 限流开关
$max_attempts_per_user = 2;      # 同一登录名的尝试阈值
$max_attempts_per_ip = 2;        # 同一 IP 的尝试阈值
$max_attempts_block_seconds = "60";   # 触发后封锁秒数
$client_ip_header = 'REMOTE_ADDR';    # 反代场景改 HTTP_X_FORWARDED_FOR

两项实测:

  1. keyphrase 强制检查(1.8.2 新增行为):保持默认 secret 时首页直接报错、功能表单不渲染,实测回显:Token encryption requires a random string in keyphrase setting;改为随机串后恢复。keyphrase 变更会使存量 token 与安全问题答案全部失效(官方注释明确),换密钥需安排重置窗口。
  2. 限流:$use_ratelimit = true + $max_attempts_per_user = 2 下,同一登录名连续 2 次错误答案后,第 3 次请求被拦,实测回显:太快了!请稍后再试(如果真的是您手动操作),60 秒封锁期后恢复。

5.10 Hook 与审计

$prehook = "/usr/share/self-service-password/prehook.sh";    # 改密前钩子,退出码 0 才放行
$display_prehook_error = true;
$prehook_password_encodebase64 = false;   # 传给钩子的密码 base64 编码
$ignore_prehook_error = true;             # 钩子失败是否放行
$posthook = "/usr/share/self-service-password/posthook.sh";  # 改密后钩子
$display_posthook_error = true;
$posthook_password_encodebase64 = false;
$audit_log_file = "/var/log/self-service-password/audit.log";  # 审计日志(注释状态=未启用)
$reset_request_log = "/var/log/self-service-password";          # 重置请求日志(默认进 Apache 日志)
$debug = false;
$smarty_debug = false;

Hook 用途:改密前同步校验(如对接密码黑名单服务)、改密后联动(如通知 SSO 系统失效会话、写自有审计)。base64 编码选项避免密码在进程参数/环境变量中被特殊字符破坏。审计默认只在 Apache 访问日志留痕(实测可见 POST /index.php?action=change 记录与邮件发送失败 php:notice),开启 $audit_log_file 后有结构化审计文件——生产建议开启并纳入日志采集。

六、生产配置模板

适用场景:中型企业(目录用户 5000 以内)、OpenLDAP 目录、4GB 内存 / 50GB 磁盘的单实例部署,SSP 与目录同内网。以下模板可直接作为 config.inc.local.php 起步(${VAR} 为需替换项):

<?php
# ---- LDAP ----
$ldap_url = "ldap://${LDAP_HOST}:389";
$ldap_starttls = true;                       # 内网目录也开 STARTTLS
$ldap_binddn = "cn=ssp-search,ou=services,dc=example,dc=org";   # 专用只读绑定账号(见安全加固指南)
$ldap_bindpw = '${LDAP_BINDPW}';
$ldap_base = "dc=example,dc=org";
$ldap_login_attribute = "uid";
$ldap_fullname_attribute = "cn";
$ldap_filter = "(&(objectClass=inetOrgPerson)(uid={login}))";
$ldap_use_exop_passwd = true;
$ldap_use_ppolicy_control = true;

# ---- 密码存储与策略 ----
$hash = "SSHA";
$who_change_password = "user";
$pwd_min_length = 12;
$pwd_max_length = 128;
$pwd_min_lower = 1;
$pwd_min_upper = 1;
$pwd_min_digit = 1;
$pwd_min_special = 1;
$pwd_no_reuse = true;
$pwd_diff_login = true;
$pwd_diff_last_min_chars = 3;
$pwd_forbidden_words = array("example", "password", "qwer");
$pwd_forbidden_ldap_fields = array('cn', 'sn', 'mail');
$pwd_show_policy = "always";
$pwd_show_policy_pos = "above";

# ---- 重置通道 ----
$use_questions = true;
$use_tokens = true;
$use_sms = false;                            # 无短信网关即关
$use_ratelimit = true;
$max_attempts_per_user = 5;
$max_attempts_per_ip = 10;
$max_attempts_block_seconds = "300";
$use_captcha = true;

# ---- Token / 缓存 ----
$reset_url = "https://ssp.example.org/";
$token_lifetime = "1800";                    # 30 分钟
$cache_type = "File";                        # 多实例改 Redis
$cache_token_expiration = 3600;

# ---- 邮件 ----
$mail_from = "ssp@example.org";
$mail_from_name = "企业自助密码服务";
$mail_address_use_ldap = true;
$notify_on_change = true;
$mail_smtp_host = 'smtp.example.org';
$mail_smtp_port = 587;
$mail_smtp_auth = true;
$mail_smtp_user = 'ssp@example.org';
$mail_smtp_pass = '${SMTP_PASS}';
$mail_smtp_secure = 'tls';

# ---- 加密密钥 ----
$keyphrase = '${KEYPHRASE}';                 # openssl rand -hex 16 生成

# ---- 界面 ----
$lang = "zh-CN";
$allowed_lang = array("zh-CN");
$default_action = "change";

# ---- 审计 ----
$audit_log_file = "/var/log/self-service-password/audit.log";
$debug = false;

要点:密码类参数全部用环境变量占位注入(部署侧用 compose secrets/环境文件),禁止明文进代码仓;token_lifetime 收紧到 30 分钟、限流阈值按真实用户量放宽(per_user=5 允许手误,per_ip=10 兜底撞库);开 STARTTLS 前先确认目录端 TLS 证书链可信(见《Self-Service Password 1.8.2 安全加固指南》)。

七、常见问题

Q1:改完 config.inc.local.php 没生效? 配置在 PHP 进程启动时加载,必须重启 SSP(docker compose restart ssp)。另外检查三点:文件是否真的挂载到了 /var/www/conf/config.inc.local.php;语法是否正确(php -l 检查);变量名拼写是否与默认配置完全一致(如 $use_questions 而非 $questions_use,拼错的变量会被静默忽略——本文实测环境中 $questions_use 即为无效键,正确键为 $use_questions)。

Q2:安全问题答案保存报 Insufficient access(error 50)? 见 5.4 与部署指南十一.3:ACL 需同时允许 self 写 info 与 objectClass(extensibleObject 追加)。只开 info 还会遇到 error 65(attribute 'info' not allowed),因为 extensibleObject 尚未追加成功。

Q3:邮件发送失败 SMTP connect() failed? 官方默认 $mail_smtp_secure='tls'。内网无 TLS 的 SMTP 显式置空 $mail_smtp_secure 并设 $mail_smtp_autotls = false;公网 587 保持 tls,465 用 ssl。

Q4:弱密码能过本地策略却被目录拒绝? 目录侧 ppolicy(OpenLDAP ppolicy overlay 或 AD 策略)在 SSP 本地策略之外独立生效。开启 $ldap_use_ppolicy_control = true + $show_extended_error = true 可把服务端拒绝原因透出,对照调整两边阈值。

Q5:token 链接打开报无效? 三种实测可能:超过 $token_lifetime(默认 3600 秒);$keyphrase 变更导致旧 token 解不开;$reset_url 与实际访问域名不一致导致 token 校验上下文错位。逐一核对。

八、参考链接