服务主体名称 (SPN) 是否绑定到特定计算机?

发布于 2024-07-10 20:16:52 字数 5381 浏览 6 评论 0原文

目前,我的 GSS 演示应用程序(在服务器端)收到 KrbException:解密字段的完整性检查失败 (31)。 现在我正在寻找这个原因。 我怀疑,这是由于

  1. 客户端和服务器应用程序在同一台计算机(本地主机)上运行和/或
  2. SPN 是为另一台计算机(计算机)生成的。

第二个意味着服务主体是为计算机 xxx0815.domain.net,因此 SPN 为 HTTP/[电子邮件受保护]。 而我的机器不是那样的,但是我已经拿到了keytab文件,这样服务器的登录方法就成功了。

我的怀疑是正确的还是我犯了另一个错误?

服务器配置及源码:
server.conf

Server { 
    com.sun.security.auth.module.Krb5LoginModule 
        required 
        isInitiator=false 
        doNotPrompt=true 
        useKeyTab=true 
        keyTab="gssdemo.keytab" 
        storeKey=true 
        principal="HTTP/[email protected]" 
        debug=true; 
};

GSSServer.java(省略了样板内容)

    GSSManager manager = GSSManager.getInstance();
    GSSName serverName = manager.createName(getServerName(), null);
    GSSCredential serverCred = manager.createCredential(serverName,
                                                        GSSCredential.INDEFINITE_LIFETIME,
                                                        createKerberosOid(),
                                                        GSSCredential.ACCEPT_ONLY);
    GSSContext context = manager.createContext(serverCred);
    System.out.println("Context created successfully. Now incoming tokens could be accepted.");

    ServerSocket serverSocket = new ServerSocket(55555);
    SocketAdapter ca = new SocketAdapter(serverSocket.accept());

    while (!context.isEstablished()) {
        byte[] inToken = ca.readToken();
        byte[] outToken = context.acceptSecContext(inToken, 0, inToken.length);

        if (outToken != null) {
            ca.sendToken(outToken);
        }
    }

    System.out.println("Context established");
    System.out.println("Connected user is: " + context.getSrcName());
    context.dispose();

客户端配置和源代码:
client.conf

Client {
    com.sun.security.auth.module.Krb5LoginModule
        required
        useTicketCache=true
        debug=true;
};

GssClient.java(省略样板)

    GSSManager manager = GSSManager.getInstance();
    GSSName clientName = manager.createName(getClientName(), null);
    GSSCredential clientCred = manager.createCredential(clientName,
                                                        8 * 3600,
                                                        createKerberosOid(),
                                                        GSSCredential.INITIATE_ONLY);
    GSSName serviceName = manager.createName("HTTP/[email protected]", null);

    GSSContext context = manager.createContext(serviceName,
                                               createKerberosOid(),
                                               clientCred,
                                               GSSContext.DEFAULT_LIFETIME);
    context.requestMutualAuth(true);
    context.requestConf(false);
    context.requestInteg(true);

    System.out.println("Establishing context");
    SocketAdapter ca = new SocketAdapter(new Socket("localhost", 55555));

    byte[] inToken = new byte[0];
    while (true) {
        byte[] outToken = context.initSecContext(inToken, 0, inToken.length);

        if (outToken != null) {
            ca.sendToken(outToken);
        }

        if (context.isEstablished()) {
            break;
        }

        inToken = ca.readToken();
    }

    System.out.println("Context established: " + context.isEstablished());

    context.dispose();

我已经检查了传出和传入的网络数据 - 两侧都是相同的,因此我可以排除那里的问题(我对输出进行了 BASE64 编码,然后通过流发送它我认为那里不会出太多问题......)。

我得到的异常:

Caused by: GSSException: Failure unspecified at GSS-API level (Mechanism level: Integrity check on decrypted field failed (31))
    at sun.security.jgss.krb5.Krb5Context.acceptSecContext(Krb5Context.java:741)
    at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:323)
    at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:267)
    at de.westlb.mrm.sandbox.gss.GssServer.acceptAndEstablish(GssServer.java:88)
    at de.westlb.mrm.sandbox.gss.GssServer.run(GssServer.java:66)
    ... 4 more
Caused by: KrbException: Integrity check on decrypted field failed (31)
    at sun.security.krb5.internal.crypto.DesCbcEType.decrypt(DesCbcEType.java:154)
    at sun.security.krb5.internal.crypto.DesCbcMd5EType.decrypt(DesCbcMd5EType.java:33)
    at sun.security.krb5.internal.crypto.DesCbcEType.decrypt(DesCbcEType.java:125)
    at sun.security.krb5.internal.crypto.DesCbcMd5EType.decrypt(DesCbcMd5EType.java:33)
    at sun.security.krb5.EncryptedData.decrypt(EncryptedData.java:168)
    at sun.security.krb5.KrbApReq.authenticate(KrbApReq.java:267)
    at sun.security.krb5.KrbApReq.<init>(KrbApReq.java:134)
    at sun.security.jgss.krb5.InitSecContextToken.<init>(InitSecContextToken.java:79)
    at sun.security.jgss.krb5.Krb5Context.acceptSecContext(Krb5Context.java:724)
    ... 8 more

At the moment I am getting a KrbException: Integrity check on decrypted field failed (31) with my GSS demo application (on the server side). Now I am looking for the reason for this. I have the suspicion, that it comes from the fact that

  1. the client and the server application run on the same machine (localhost) and/or
  2. the SPN was generated for another machine (computer)

The second means that the service principal was generated for a machine xxx0815.domain.net, so the SPN is HTTP/[email protected]. And my machine is not that one, but I have got the keytab file so that the server's login method succeeds.

Do I suspect correctly or am I making another mistake?

Server configuration and source code:
server.conf

Server { 
    com.sun.security.auth.module.Krb5LoginModule 
        required 
        isInitiator=false 
        doNotPrompt=true 
        useKeyTab=true 
        keyTab="gssdemo.keytab" 
        storeKey=true 
        principal="HTTP/[email protected]" 
        debug=true; 
};

GSSServer.java (omitted the boilerplate stuff)

    GSSManager manager = GSSManager.getInstance();
    GSSName serverName = manager.createName(getServerName(), null);
    GSSCredential serverCred = manager.createCredential(serverName,
                                                        GSSCredential.INDEFINITE_LIFETIME,
                                                        createKerberosOid(),
                                                        GSSCredential.ACCEPT_ONLY);
    GSSContext context = manager.createContext(serverCred);
    System.out.println("Context created successfully. Now incoming tokens could be accepted.");

    ServerSocket serverSocket = new ServerSocket(55555);
    SocketAdapter ca = new SocketAdapter(serverSocket.accept());

    while (!context.isEstablished()) {
        byte[] inToken = ca.readToken();
        byte[] outToken = context.acceptSecContext(inToken, 0, inToken.length);

        if (outToken != null) {
            ca.sendToken(outToken);
        }
    }

    System.out.println("Context established");
    System.out.println("Connected user is: " + context.getSrcName());
    context.dispose();

Client configuration and source code:
client.conf

Client {
    com.sun.security.auth.module.Krb5LoginModule
        required
        useTicketCache=true
        debug=true;
};

GssClient.java (boilerplate omitted)

    GSSManager manager = GSSManager.getInstance();
    GSSName clientName = manager.createName(getClientName(), null);
    GSSCredential clientCred = manager.createCredential(clientName,
                                                        8 * 3600,
                                                        createKerberosOid(),
                                                        GSSCredential.INITIATE_ONLY);
    GSSName serviceName = manager.createName("HTTP/[email protected]", null);

    GSSContext context = manager.createContext(serviceName,
                                               createKerberosOid(),
                                               clientCred,
                                               GSSContext.DEFAULT_LIFETIME);
    context.requestMutualAuth(true);
    context.requestConf(false);
    context.requestInteg(true);

    System.out.println("Establishing context");
    SocketAdapter ca = new SocketAdapter(new Socket("localhost", 55555));

    byte[] inToken = new byte[0];
    while (true) {
        byte[] outToken = context.initSecContext(inToken, 0, inToken.length);

        if (outToken != null) {
            ca.sendToken(outToken);
        }

        if (context.isEstablished()) {
            break;
        }

        inToken = ca.readToken();
    }

    System.out.println("Context established: " + context.isEstablished());

    context.dispose();

I have checked the outgoing and incoming network data - it's the same on both sides so I can rule out a problem there (I have BASE64-encoded the output and then just send it through the streams. I think there is not much that can go wrong there...).

The exception I get:

Caused by: GSSException: Failure unspecified at GSS-API level (Mechanism level: Integrity check on decrypted field failed (31))
    at sun.security.jgss.krb5.Krb5Context.acceptSecContext(Krb5Context.java:741)
    at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:323)
    at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:267)
    at de.westlb.mrm.sandbox.gss.GssServer.acceptAndEstablish(GssServer.java:88)
    at de.westlb.mrm.sandbox.gss.GssServer.run(GssServer.java:66)
    ... 4 more
Caused by: KrbException: Integrity check on decrypted field failed (31)
    at sun.security.krb5.internal.crypto.DesCbcEType.decrypt(DesCbcEType.java:154)
    at sun.security.krb5.internal.crypto.DesCbcMd5EType.decrypt(DesCbcMd5EType.java:33)
    at sun.security.krb5.internal.crypto.DesCbcEType.decrypt(DesCbcEType.java:125)
    at sun.security.krb5.internal.crypto.DesCbcMd5EType.decrypt(DesCbcMd5EType.java:33)
    at sun.security.krb5.EncryptedData.decrypt(EncryptedData.java:168)
    at sun.security.krb5.KrbApReq.authenticate(KrbApReq.java:267)
    at sun.security.krb5.KrbApReq.<init>(KrbApReq.java:134)
    at sun.security.jgss.krb5.InitSecContextToken.<init>(InitSecContextToken.java:79)
    at sun.security.jgss.krb5.Krb5Context.acceptSecContext(Krb5Context.java:724)
    ... 8 more

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

饮湿 2024-07-17 20:16:52

如果完整性检查失败,则表明数据未正确发送/接收(这是一条不正确的错误消息)。 换句话说,发生了一些修改。

我知道您说您已经在网络级别检查了发送的数据是否与接收的数据匹配,但是您确定它在发送之前或接收之后没有损坏吗? 我建议您首先检查您的代码。

编辑:为了回答您的问题,服务主体(实际上是任何票证)可以绑定到特定机器,但这通常是通过 IP 地址完成的。 无论如何,类似的事情应该会导致不同的更高级别的错误。

您收到的错误听起来像是一开始就无法解密票证。 可能的原因是它使用了错误的密钥,这可能与您复制密钥表有关。 使用错误的票证也可能导致错误的密钥(因为 kerberos 基本上提供了密钥管理协议)。 您是否有可能缓存了旧的/不正确的票证?

If the integrity check fails that suggests that the data is not being sent / received correctly (that or this is an incorrect error message). In other words some modification has occurred.

I know you say you have checked that the sent data matches the received data at the network level, however are you sure it is not corrupted prior to send, or after receipt? I would suggest you review your code for this first.

edit: In answer to your question, a service principal (really, any ticket) can be bound to a specific machine, but this is normally done in terms of IP address. In any case something like that should result in a different higher level error.

The error you're getting sounds like it is having trouble decrypting the ticket in the first place. A possible cause of that is that it is using the wrong key, which may be related to your copying the keytab. A wrong key can also be caused by using the wrong ticket (as kerberos basically provides a key management protocol). Is it possible you have cached an old/incorrect ticket?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文