Node.js https.get 或 https.request 中的 Kerberos 身份验证

Posted

技术标签:

【中文标题】Node.js https.get 或 https.request 中的 Kerberos 身份验证【英文标题】:Kerberos authentication in Node.js https.get or https.request 【发布时间】:2013-12-04 14:54:19 【问题描述】:

我正在尝试编写一个简单的脚本,该脚本从内部网络上的工具请求一些数据。代码如下:

#!/usr/bin/node

var https = require('https');
var fs = require('fs');

var options = 
  host: '<link>',
  port: 443,
  path: '<path>',
  auth: 'username:password',
  ca: [fs.readFileSync('../.cert/newca.crt')]
;

https.get(options, function(res) 
  console.log("Got response: " + res.statusCode);
  res.on('data', function (d) 
    console.log('BODY: ' + d);
  );
).on('error', function(e) 
  console.log("Got error: " + e.message);
);

现在的问题是,如何使用 Kerberos 票证进行身份验证,而不是在 auth: 中以纯文本形式提供我的凭据?

【问题讨论】:

【参考方案1】:

来自http://docs.oracle.com/cd/E24191_01/common/tutorials/authn_kerberos_service.html

消息级标准的客户端令牌位置:Kerberos 服务票证可以在 Authorization HTTP 标头中发送,也可以在 在消息本身内部,例如,在一个 元素。或者,它可能包含在消息中 属性。选择以下选项之一:

所以您提供的是票证而不是您的用户名:密码

或者,您可以如下所述将信息放在消息正文中或作为消息属性

var request = https.request(options, function(resource) 
  var chunks = [];
   resource.on('data', function (chunk) 
     chunks.push(chunk);
   );
   resource.on('end', function () 
     var data = chunks.join('');
     console.log(data);
   );


request.on('error',...)
request.send('<body-with-ticket>');
request.end();

编辑:

“”部分是我在哪里使用票证的示例,将其放在多类型正文中并发送,或者使用 WWW-Authenticate 标头发送它

例如。将其添加到 https.request 的选项中

options = 
    host: 'hostname',
    port: 443, 
    'WWW-Authenticate': 'Negotiate ' + ticketdata
;

google 有一些关于其工作原理的漂亮图表: https://developers.google.com/search-appliance/kb/secure/kerberos-diagram

【讨论】:

感谢您的解决方案,即使我知道我们可以设置 HTTP 请求的自定义标头并发送 kerberos 凭据(准确地说,我们需要将 'WWW-Authenticate' 设置为 kerberos 票证。但是 问题是从KRB5CCNAME文件(kerberos票据)中获取内容,这个文件内容是加密的。 基本上我需要实用程序来读取 KRB5CCNAME 文件并设置身份验证头。我会自己编写这个实用程序,但对 Kerberos 知之甚少,如果您能给我一些启发,我将不胜感激! “您提供票证”是什么意思。我是否只是指向像auth: 'ticket', 这样的票证文件。可以发一下代码吗? 我今天一定很慢,抱歉; ticketdata 是什么?我从 Google 链接中了解到,它是 Kerberos 票证在哈希中的表示(正确吗?),但我从哪里得到它?【参考方案2】:

在 Paul Scheltema 的回答中,您需要从操作系统的深度获取票证数据。您(或代表您的模块)必须使用 GSS-API 让 Active Directory 为您生成票证数据。

这种机制在 Chrome 中是有的,但似乎 Node.js 中没有(只有 Chrome 的 javascript 引擎),所以你可能需要添加一个模块,例如:

Passport-Kerberos:https://www.npmjs.org/package/passport-kerberos 和 http://passportjs.org/guide/ Kerberos (npm install kerberos) 在 github 上的 Node.js 源代码中,有迹象表明有人一直在为此使用 Bones 模块 (https://github.com/joyent/node/search?q=kerberos&ref=cmdform)。 3 年前,使用 DES(这种编码类型非常弱,已被弃用多年)

要安装/编译此类模块,您可能需要 Visual Studio。


要设置环境, - 在所有计算机上,您必须在端口 88 (Kerberos) 和 53 (dns) 上启用 tcp 和 udp。 - 必须在 Windows Server 上运行 Active Directory(ldap、dns、kdc) - 在页面 https://www.npmjs.org/package/passport-kerberos 他们使用术语 REALM。这是一个域名,大写

【讨论】:

我知道这可以用一个像 passport-kerberos 这样的模块来完成,但是那个模块是怎么做到的呢?我不能绕过模块并简单地实现相同的逻辑,保持简单的脚本没有任何依赖关系吗? 逻辑:使用GSS-API/SSPI函数形成对域控制器的请求。此请求必须包含用户身份验证信息(从 Kerberos 缓存中获取,受操作系统高度保护),以及转换为 userPrincipal 表单(使用 dns)的 URL。如果 Active Directory 在 LDAP 中有这样的 userPrincipal 并且身份验证数据正确,则会生成 Kerberos 票证。这张票应该被包装到 SPNEGO 中,Base64 编码,这是 Paul Scheltema 回答中的“票证数据”。通常这是由网络浏览器为我们完成的。当它不存在时,在 node.js 中,需要一个模块。 好的,我想真的没有办法快速简单地做到这一点,并且必须有一些模块依赖项。感谢您的回答! 几个月前研究过 Kerberos,肯定会有一些模块依赖,除非你想深入研究 passport-kerberos 的源代码(甚至是 Chromium 源代码)并重新实现它.我可能会在某个时候自己做这件事(假设这个特定的项目上升到最顶端),因为我在 npm 中看到的唯一 Kerberos 模块只允许您根据活动目录验证凭据(基本上,允许您使用 Kerberos在服务器上下文中),它们并没有让您实际与远程服务器作为客户端进行协商【参考方案3】:

我已经使用“kerberos”模块,版本 0.0.12 使它工作。我用工作示例创建了一个要点:

https://gist.github.com/dmansfield/c75817dcacc2393da0a7

基本上,您使用三种方法来获取“Authorization”标头数据:

authGSSClientInit,需要服务名称,例如HTTP@somehost.com authGSSClientStep,它需要存在凭据缓存(在 Linux 上,您可以通过执行“kinit”来获得此缓存,并且可以使用“klist”进行验证),并且实际上会返回您需要的 base64 内容(没有前导的“Negotiate” " 字符串) authGSSClientClean,释放所有分配的内存结构

然后您创建一个“授权”标头(不是上面显示的 WWW-Authenticate,这是服务器发回的内容),它应该可以工作。

另请注意:通常,Web 浏览器请求资源,在响应中返回带有 WWW-Authenticate: Negotiate 标头的 401,然后使用“授权”标头中提供的票证数据重新请求资源。每个资源都会发生这种两步舞。我不确定这是否意味着什么。

【讨论】:

【参考方案4】:

如果您使用的是 Windows,则可以使用 SSPI 接口。它以项目node-expose-sspi 暴露在Node 上。

SSPI 接口允许您使用 SSO(NTLM 和 Kerberos)编写任何客户端或服务器。

https://github.com/jlguenego/node-expose-sspi

注意:我是 node-expose-sspi 的作者。

【讨论】:

【参考方案5】:

2020 UPD:

较新版本的kerberos npm 包的方法要少得多。但我让它工作:

const kerberos = require('kerberos').Kerberos;
const fetch = require('node-fetch');

(async () => 
    const client = await kerberos.initializeClient("HTTP@site.internal.net", 
        mechOID: kerberos.GSS_MECH_OID_SPNEGO,
    )

    const ticket = await client.step("")

    const resp = await fetch("https://site.internal.net/api/v1/hello", 
        headers: 
            'Authorization': 'Negotiate ' + ticket
        
    )

    console.log(await resp.json())
)();

在 Windows 和 Linux 上完美运行,应该也可以在 macOS 上运行。

【讨论】:

idk 为什么你被否决了,当我将 mechOID 更改为 GSS_MECH_OID_KRB5 时,这对我来说非常有效。我使用的是 macOS Catalina 10.15.7 (19H15) 聚会迟到了,但这里有一个问题。在传递参数时我们如何传递密码?我正在尝试在休息环境中进行这项工作。对于令牌调度的工作方式非常困惑。一些建议或任何注释? 这是 SSO。操作系统认为您已获得授权,因此它仅在系统调用后提供 SPNEGO 令牌(此库执行此操作)。【参考方案6】:

在 Windows 上。这个answer 似乎是正确的,只是可能需要一些调整。

const client = await kerberos.initializeClient("HTTP/site.internal.net@DOMAIN.HERE", 
    mechOID: kerberos.GSS_MECH_OID_SPNEGO,
)

适用于 GSS_MECH_OID_KRB5 和 GSS_MECH_OID_SPNEGO。 从命令行使用 klist,您将获得现有 kerberos 票证、其站点(例如 site.internal.net)和域(例如 DOMAIN.HERE)的概览。

kerberos 流程是您首先获得带有 WWW-Authenticate: Negotiate 标头的 401。然后,您应该使用 'Authorization': 'Negotiate ' + ticket 向以 401 响应的 url(可以是相同的 url,可以是重定向 url)发出第二个请求,如示例所示。不要忘记重用第一次请求中的任何 Cookies 来维护会话。

完整的请求可能如下所示:

const kerberos = require('kerberos').Kerberos;
const fetch = require('node-fetch');

(async () => 
    const client = await kerberos.initializeClient("HTTP/site.internal.net@DOMAIN.HERE", 
        mechOID: kerberos.GSS_MECH_OID_SPNEGO, // or GSS_MECH_OID_KRB5
    )

    const ticket = await client.step("")

    // 401 here, get cookies
    const resp1 = await fetch("https://site.internal.net/api/v1/hello")

    // ... code to handle cookies ...

    const resp2 = await fetch("https://site.internal.net/api/v1/hello", 
        headers: 
            'Authorization': 'Negotiate ' + ticket,
            'Cookie': // ... add cookies from first request ..
        
    )

    console.log(await resp2.json())
)();

【讨论】:

以上是关于Node.js https.get 或 https.request 中的 Kerberos 身份验证的主要内容,如果未能解决你的问题,请参考以下文章

了解 node.js 中的请求获取

如何在Node.js中从简单的HTTPS请求构造和提取值?

如何在没有任何第三方模块的情况下在 Node Js 中发布 https 帖子?

安装node.js

Node.js 安装配置

Node.js的安装与配置