Python 请求、Kerberos 和 NTLM

Python requests, Kerberos and NTLM

我最近在做一个项目,我需要访问 asp.net 网络 API 才能获取一些数据。到目前为止,我获得此 API 访问权限的方法是在代码中手动设置 cookie,然后使用请求获取我需要的信息。我现在的任务是使这个过程自动化。我使用网络选项卡中的 Chrome 开发人员工具获取 cookie。现在很明显,cookie 每隔一段时间就会更改一次,所以我一直在尝试制作一些可以自动更改内部 cookie 的东西。

我应该提一下,完成这项工作的网络是 air-gaped 并且在内部获取 python 库有点乏味,所以我试图避免这种情况。这也是这里获取代码示例非常复杂的原因。

log-in 进程在此 Web 应用程序中的工作方式如下(来自 chrome 开发工具的数据):

  1. 进入 URL 后,有一堆似乎什么都不做的重定向。
  2. 向 /login.aspx 发出请求,其中 returns a "set-cookie: 'sessionId=xyz'" header 并重定向到 /LandingPage.aspx
  3. 向 /LandingPage.aspx 发出请求,其中 returns 一个“set-cookie” header 带有一堆 cookie(ASP.NET 等').这些是我使 python 脚本访问 API.
  4. 所需的 cookie

上面写的是浏览器做事的方式,当我试图在 python 请求中模仿它时,我从 /login.aspx 获得了第一个 cookie,但是当它重定向到 /LandingPage.aspx,我得到一个 401 Unauthorized 带有以下 headers:

WWW-Authenticate: Negotiate
WWW-Authenticate: NTLM

阅读完一些内容后,我了解到这些响应 header 与 NTLM 和 Kerberos 协议相关(附带问题:如果它同时响应 header 是否意味着我需要提供两种身份验证还是其中一种就足够了?)。

快速 google 搜索得出,在这些提到的响应之后,应该遵循带有 Kerberos/NTLM 令牌(我不知道如何获取)的请求,以便获得 200 响应。我觉得这很奇怪,因为浏览器不会发出任何这些请求,网络应用程序只是向它提供 cookie,而它似乎没有传输任何 NTLM 或 Kerberos 数据。

我已经想到了一些方法来克服这个问题,希望你能帮助我弄清楚这是否可行。

  1. 尝试获取 python 的 requests-kerberos 或 requests-ntlm 库并使用它们来解决此问题。我想听听您对这是否可行的意见。但是因为上面提到的,我不太愿意使用这种方法。

  2. 以某种方式使用 PowerShell 获取这些令牌,然后以某种方式在没有上述库的情况下在 python 请求中使用这些令牌。但我也不知道这是否有效。

如果有人能进一步解释这里发生的总体过程,我将不胜感激,当然也非常感谢任何帮助解决此问题的人。

非常感谢!

Trying to get the requests-kerberos or requests-ntlm libraries for python and using those to overcome this problem. I would like your opinion to whether this would work. I am reluctant to use this method though, because of what was mentioned above.

是的,requests-kerberos 可以。 HTTP 协商意味着 Kerberos 几乎 100% 的时间。

对于 Linux 我 稍微 更喜欢 requests-gssapi,它基于维护得更好的 'gssapi' 后端,但目前它仅限于 Unix-ish 系统——而 requests-kerberos 具有通过 'winkerberos' 后端支持 Windows 的优势。但这并不重要;两者都能很好地完成工作。

如果可以避免,请不要使用 NTLM。您的域管理员将很高兴能够尽快关闭 NTLM domain-wide。

Somehow using PowerShell to get these tokens and then somehow using these tokens in python requests without the above mentioned libraries. But I have no idea if this would work either.

从技术上讲这是可能的,但通过 PowerShell(或一般的 .NET)执行此操作会绕过 long 方法。您可以使用 Python 的 sspi 模块实现完全相同的效果,该模块直接与处理 Kerberos 票证获取(和 NTLM,就此而言)的实际 Windows SSPI 接口对话。

gssapi 模块相当于 Linux,spnego 模块是两者的 cross-platform 包装器。)

你可以 see a few examples here – OP 有一个 .NET 示例,答案有 Python.

但请记住,Kerberos 令牌不仅包含服务票证,还包含 一次性使用 身份验证器(以防止重放攻击),因此您需要获取新令牌对于每个 HTTP 请求。

所以不要重新发明轮子,直接使用requests-kerberos,它会在需要时自动调用SSPI来获取令牌。

it says that in order for requests-kerberos to work there has to be a TGT cached already on the PC. This program is supposed to run for weeks without being interfered with and to my understanding these tickets expire after about 10 hours.

这是所有 Kerberos 使用的典型情况,而不仅仅是 requests-kerberos。

如果您 运行 Windows 上的应用程序来自交互式会话,则 Windows 将根据需要自动更新 Kerberos 票据(它会将您的密码缓存在 LSA 内存中目的)。但是,不要 运行 long-term 交互式会话中的任务...

如果您 运行 Windows 上的应用程序作为 服务, 则它将使用“机器凭据”又名“计算机帐户”( see details), LSA 将再次保留门票 up-to-date.

如果您 运行 Linux 上的应用程序,那么您可以创建一个 keytab 来存储应用程序的客户端凭据。 (这不需要域管理员权限,您只需要知道应用程序帐户的密码即可。)

在 Linux 上,至少有 4 种不同的方法可以将密钥表用于 long-term 作业:k5start(third-party,但很常见); KRB5_CLIENT_KTNAME(built-in 到 MIT Kerberos,但仅在最新版本中); gss-proxy(来自 RedHat,可能已经是 OS 的一部分);或基本的 cronjob,只需 re-runs kinit 每 4-6 小时获取新票。

I find this pretty weird considering the browser doesn't make any of these requests and the web app just gives it the cookies without it seemingly transferring any NTLM or Kerberos data.

很有可能,你可能忽略了它。

请注意,某些 SSO 系统使用 JavaScript 来动态探测浏览器是否正确设置了 Kerberos 身份验证 – 如果主页真的没有发送令牌,那么它可能是一个 iframe 或一个AJAX/XHR 请求确实如此。