5

我正在使用 jTDS 连接到 SQLServer。jTDS 在内部使用 GSS 获取 kerberos 的服务票证并建立安全上下文。由于我的应用程序寿命很长,并且我的连接在整个过程中保持活动状态,因此我需要更新 kerberos 的服务票证,以允许 SQL 服务器自行更新它们(kdc 策略设置为在 12 小时后过期所有票证)。

jTDS 为获取 kerberos 令牌所做的(或多或少)如下:

GSSManager manager = GSSManager.getInstance();

// Oids for Kerberos5
Oid mech = new Oid("1.2.840.113554.1.2.2");
Oid nameType = new Oid("1.2.840.113554.1.2.2.1");

// Canonicalize hostname to create SPN like MIT Kerberos does
GSSName serverName = manager.createName("MSSQLSvc/" + host + ":" + port, nameType);

GSSContext gssContext = manager.createContext(serverName, mech, null, GSSContext.DEFAULT_LIFETIME);
gssContext.requestMutualAuth(false);
gssContext.requestCredDeleg(true);

byte[] ticket = gssContext.initSecContext(new byte[0], 0, 0);

我怀疑我得到的票是不可更新的。我正在通过执行以下操作来检查:

ExtendedGSSContext extendedContext = (ExtendedGSSContext) gssContext;
boolean[] flags = (boolean[]) extendedContext.inquireSecContext(InquireType.KRB5_GET_TKT_FLAGS);
System.out.println("Renewable = " + flags[8]);

在我们的特定配置中,GSS 正在从 JAAS 登录模块获取 kerberos TGT。我们将以下变量设置为 false -Djavax.security.auth.useSubjectCredsOnly=false,并且在 login.cfg 文件中我们配置了以下登录模块:

com.sun.security.jgss.krb5.initiate {
   com.sun.security.auth.module.Krb5LoginModule required
      useKeytTab=true
      keyTab="/home/batman/.batman.ktab"
      principal="batman@GOTHAMCITY.INT"
      storeKey=true
      doNotPrompt=true
      debug=false
};

我注意到的另一件事是该getLifetime()方法GSSContext似乎不起作用。无论票证的实际生命周期是多少,它总是返回 2147483647(最大整数)。

我对分支 jTDS 驱动程序感到满意,因此如果需要,我可以修改它建立 GSS 上下文的方式。

我尝试了什么:

使用 GSS api 的本机实现:

这在获取可更新票证方面对我来说很好,但它带来了另一组问题(在确保正确设置票证缓存并且其中的票证正确更新方面)。如果我可以绕过这个选项,那就太好了。我在这里观察到的事情是,该getLifetime()方法实际上以票证的秒数返回了真实的生命周期。

重新实现 KerberosLoginModule:

基于对这个问题的回答Jaas - Requesting Renewable Kerberos Tickets我重新实现了 LoginModule 以在请求 TGT 之前设置KDCOptionRENEW KrbAsReqBuilder。从我获得可更新 TGT 的意义上说,这很好用,但 GSS 从该 TGT 获得的票仍然不可更新。如果我在 KDCOption 对象的构造函数中设置断点并在每个请求上手动设置 RENEW 标志(即使KrbTgsReq是由 GSS 完成的)它也可以工作,但要使该更改富有成效需要对 GSS 进行重大重写,我对此感到不舒服。

4

1 回答 1

1

对于管理员而言,Kerberos 票证具有生命周期这一事实是一项重要的安全功能。用户知道密码,因此他/她可以随时获得一张新票。但是对于入侵者来说,这是一个问题——票证到期后,它不能用来闯入系统。管理员希望这个生命周期尽可能短,但又不能太短(比如 1 小时),因为用户会产生比现在多 10 倍的登录请求,而且 ActiveDirectory 很难处理。

当我们需要使用 Kerberos 进行身份验证时,我们应该使用连接池(和 DataSource)。要在 jTDS 中使用此功能,您需要添加 ConnectionPoolImplementation(推荐:DBCP 或 c3p0,请参阅:http://jtds.sourceforge.net/features.html

如果您想使用旧的连接数据库的方式编写您的应用程序(没有数据源,即创建一个连接并使其保持活动状态,因为创建它的成本很高..),那么下一个障碍将是“更新生命周期”。在 ActiveDirectory 中,Kerberos 票证可以默认在 7 天内续订。AD 中有一个全局设置允许将其设置为 0(无限期更新生命周期),但您需要说服域管理员降低整个域的安全性,因为没有它就无法运行一项服务。

于 2015-04-19T13:06:30.527 回答