3. 目录服务与LDAP

在身份安全工程师的面试中,LDAP 几乎是绕不开的话题。很多候选人能说出“LDAP 是轻量级目录访问协议”,但一旦面试官追问“目录树怎么设计”“Schema 里 MUST 和 MAY 有什么区别”“绑定操作有哪几种”“过滤器语法怎么写”,回答就开始含糊。这一节我们把 LDAP 从“是什么”讲到“实际怎么用”,并给出面试中高频追问的应对思路。

一、目录服务与 LDAP 的定位

目录服务是一种针对“读多写少”场景优化的数据存储,典型用途是保存用户、组、设备、组织单元等身份对象。它的核心特征是树状层次结构、面向属性的查询、以及为查询性能而设计的索引机制。LDAP 是访问目录服务的协议,当前主流实现包括 OpenLDAP、389 Directory Server、Microsoft Active Directory 的 LDAP 接口,以及云上的 Azure AD / Entra ID 的 LDAP 兼容能力。

需要区分两个概念:目录服务是数据模型与存储,LDAP 是访问协议。面试中如果只谈协议不谈数据模型,往往会被认为理解不深。目录服务的设计目标不是事务一致性,而是高并发读取和快速查找,因此它不适合存放大对象或高频变更的数据。

二、目录结构:DIT 与命名模型

LDAP 的数据组织成一棵目录信息树(DIT,Directory Information Tree)。每个节点是一个条目(Entry),条目由 DN(Distinguished Name)唯一标识。DN 是从条目到树根的路径,例如:

uid=zhangsan,ou=people,dc=example,dc=com

其中 dc=example,dc=com 是后缀(suffix),ou=people 是组织单元,uid=zhangsan 是叶子条目。RDN(Relative Distinguished Name)是 DN 中最左侧的一段,如 uid=zhangsan。面试中常问“DN 和 RDN 的区别”,答案就是 DN 是完整路径,RDN 是相对父节点的单段名称。

目录结构设计要结合组织实际。常见做法是按对象类型分层,如 ou=people、ou=groups、ou=devices;也可以按部门分层,如 ou=engineering,ou=people。前者查询简单,后者更贴近组织变更。实际项目中,很多企业采用“按类型分层 + 部门属性”的混合方式,既保证查询效率,又保留组织维度。

三、Schema:对象类与属性定义

Schema 是目录的“数据字典”,规定了条目可以包含哪些对象类(objectClass)和属性(attribute)。每个对象类定义了一组 MUST 属性和 MAY 属性。MUST 是必须存在的属性,MAY 是可选属性。例如 inetOrgPerson 对象类要求 MUST 包含 cn 和 sn,MAY 包含 mail、telephoneNumber、uid 等。

Schema 还定义了属性的语法(syntax)和匹配规则(matching rule)。语法决定属性值的类型,如 Directory String、IA5 String、Integer;匹配规则决定查询时如何比较,如 caseIgnoreMatch 表示忽略大小写。这一点在面试中经常被追问:为什么 uid 查询有时区分大小写,有时不区分?答案取决于属性使用的匹配规则。

实际配置中,OpenLDAP 的 Schema 通常以文件形式加载,如 core.schema、cosine.schema、inetorgperson.schema。自定义 Schema 需要定义 attributeType 和 objectClass,并确保 OID 唯一。面试中如果被问到“如何扩展 Schema”,可以回答:先确认现有 Schema 是否已满足需求,若需新增属性,定义 attributeType 并指定语法和匹配规则,再定义 objectClass 引用该属性,最后通过 ldapadd 加载并验证。

四、绑定操作:认证的入口

绑定(Bind)是客户端向目录服务证明身份的过程。LDAP 支持多种绑定方式:

  • 匿名绑定:不提供凭证,通常只有只读权限,用于公开查询。
  • 简单绑定:用 DN 和明文密码认证,是最常见的方式,但必须配合 TLS 使用。
  • SASL 绑定:支持 GSSAPI、DIGEST-MD5、EXTERNAL 等机制,适合集成 Kerberos 或证书认证。

面试中常问“简单绑定和 SASL 绑定的区别”。简单绑定只验证 DN 和密码,SASL 则提供更丰富的认证机制和协商过程。实际项目中,如果企业已部署 Kerberos,SASL/GSSAPI 是更优选择,因为它支持单点登录且不传输密码。

绑定操作的结果可以通过 ldapwhoami 验证。例如:

ldapwhoami -x -D "uid=zhangsan,ou=people,dc=example,dc=com" -W
Enter LDAP Password:
dn:uid=zhangsan,ou=people,dc=example,dc=com

如果返回 dn 信息,说明绑定成功;如果返回“Invalid credentials (49)”,说明 DN 或密码错误。面试中如果被问到“绑定失败如何排查”,可以从 DN 是否正确、密码是否过期、账户是否被锁定、是否要求 TLS、ACL 是否限制绑定等角度回答。

五、查询语法:过滤器与搜索范围

LDAP 查询的核心是过滤器(Filter)和搜索范围(Scope)。搜索范围有三种:base 只查当前条目,one 查直接子条目,sub 查整棵子树。过滤器使用波兰前缀表示法,常见操作符包括:

  • (&(objectClass=person)(uid=zhangsan)):与操作,同时满足两个条件。
  • (|(uid=zhangsan)(uid=lisi)):或操作,满足任一条件。
  • (!(mail=*)):非操作,mail 属性不存在。
  • (cn=*张*):通配符匹配,包含“张”的 cn。
  • (createTimestamp>=20240101000000Z):大于等于比较。

实际查询示例:查找 ou=people 下所有 mail 以 example.com 结尾的用户,返回 uid 和 mail:

ldapsearch -x -H ldap://ldap.example.com -b "ou=people,dc=example,dc=com" -s sub \
  "(&(objectClass=inetOrgPerson)(mail=*@example.com))" uid mail

结果中每个条目以 dn 开头,后跟请求的属性。如果结果为空,需要检查过滤器语法、搜索范围、ACL 权限以及属性是否存在。面试中常问“sub 和 one 的区别”,以及“为什么查询结果比预期少”,前者考范围理解,后者考 ACL、索引和过滤器逻辑。

六、面试常见追问与应对

追问一:LDAP 和数据库有什么区别? 回答要点:LDAP 是树状层次模型,读多写少,查询用过滤器,适合身份目录;关系数据库是二维表模型,支持事务和复杂关联,适合业务数据。LDAP 不适合高频写入和复杂事务。

追问二:为什么 LDAP 查询要限制返回属性? 因为目录条目可能包含大量属性,限制返回属性可以减少网络传输和客户端处理开销,同时避免泄露敏感属性。实际项目中,ACL 也会限制某些属性的可见性。

追问三:如何优化 LDAP 查询性能? 可以从索引、搜索范围、过滤器写法、连接复用等角度回答。例如为常用查询属性建立索引,避免使用前导通配符(如 (cn=*张)),尽量缩小搜索范围,使用连接池复用连接。

追问四:LDAP 注入是什么?如何防范? LDAP 注入是通过构造恶意过滤器改变查询逻辑。防范措施包括:对用户输入进行转义,使用参数化查询,限制绑定账户权限,启用最小权限 ACL。面试中如果能给出转义示例,如将 * 转义为 \2a,会更有说服力。

七、可直接使用的排查清单

以下清单可用于实际 LDAP 问题排查,也可作为面试中回答“如何系统排查”的参考:

检查项命令或方法判断依据
网络连通性telnet ldap.example.com 389端口可达,无防火墙拦截
绑定是否成功ldapwhoami -x -D "DN" -W返回 dn 则成功,49 则凭证错误
搜索范围是否正确ldapsearch -s base/one/sub结果数量与预期一致
过滤器语法检查括号配对和操作符无语法错误,返回预期条目
ACL 权限查看 slapd.conf 或 cn=config绑定账户有读取目标属性的权限
属性是否存在ldapsearch 返回所有属性目标属性在结果中可见

掌握以上内容后,面对 LDAP 相关面试题,可以从数据模型、Schema、绑定、查询、性能和安全六个维度展开,既体现知识广度,也展示实际排查能力。建议在练习时用 OpenLDAP 或在线 LDAP 测试服务实际执行绑定和查询命令,观察返回结果,加深对过滤器语法和搜索范围的理解。