跳转到主要内容

创建NTLM认证结构

项目描述

Build StatusBuild statusCoverage Status

关于这个库

这个库处理NTLM认证的底层细节,用于与使用NTLM进行认证的服务进行认证。它将按照所需顺序创建和解析3种不同的消息类型,并生成一个可以附加到HTTP头部的base64编码值。

此库的目的是提供完整的NTLM支持,包括消息的签名和密封,以及支持MIC以增强消息的完整性,并能够自定义和设置发送消息的限制。请参阅功能和支持的待办事项列表,以了解当前支持和不支持的内容。

功能

  • LM、NTLM和NTLMv2认证

  • NTLM1和NTLM2扩展会话安全

  • 在发送消息时设置NTLM兼容级别

  • 支持通道绑定令牌,需要传入证书的SHA256哈希值才能工作

  • 支持MIC以增强消息的完整性

  • 在认证发生后,支持带有签名和密封消息的会话安全

安装

ntlm-auth 支持 Python 2.6, 2.7 和 3.3+

安装时,请使用 pip

pip install ntlm-auth

从源码安装,请先下载源代码,然后运行

python setup.py install

用法

几乎所有用户都应该使用 requests-ntlm 而不是这个库。requests-ntlm 是一个插件,它使用这个库的底层,并提供了一个更易于使用和理解的功能。

如果您坚持直接使用 ntlm-auth 来计算消息结构,以下是如何实现的非常基本的概述。代码示例是伪代码,应根据您的需求进行修改。

当初始化 ntlm 上下文时,您必须提供 NTLM 兼容级别。不同认证级别之间的主要区别在于初始化 Ntlm 时提供的 ntlm_compatibility 变量。以下是对每个设置的概述;* 0 - LM 认证和 NTLMv1 认证 * 1 - LM 认证和 NTLMv1 认证带有扩展会话安全性 (NTLM2) * 2 - NTLMv1 认证带有扩展会话安全性 (NTLM2) * 3 - NTLMv2 认证(默认选择) * 4 - NTLMv2 认证 * 5 - NTLMv2 认证

从客户端的角度来看,3 级到 5 级是相同的,但它们在服务器处理认证的方式上有所不同,这超出了本项目的范围。此设置在该服务器上独立设置,因此当调用 Ntlm 时选择 3、4 或 5 实际上没有任何区别。有关更多详细信息,请参阅 LmCompatibilityLevel

扩展会话安全性是一种旨在提高 LM 和 NTLMv1 认证安全性的安全功能。它不能替代 NTLMv2,但比没有好,如果可能的话,当您需要 NTLMv1 兼容性时应该使用它。

所需的变量概述如下;* username - 要认证的用户名,不应有域前缀,即 USER 而不是 DOMAINUSER * password - 要认证的用户密码 * domain - 用户所在的域,即 DOMAIN。如果不在域环境中,则可以留空 * workstation - 您正在运行的工作站。如果您不想发送此信息,则可以留空 * cbt_data - (NTLMv2 仅限) 用于绑定到认证响应的 gss_channel_bindings.GssChannelBindingsStruct。如果不需要绑定,则可以是 None

LM 认证/NTLMv1 认证

LM 和 NTLMv1 认证是较老的认证方法,应尽可能避免使用。在选择这些认证方法之间几乎相同,除了您指定 ntlm_compatiblity 级别的地方。

import socket

from ntlm_auth.ntlm import NtlmContext

username = 'User'
password = 'Password'
domain = 'Domain' # Can be blank if you are not in a domain
workstation = socket.gethostname().upper() # Can be blank if you wish to not send this info

ntlm_context = NtlmContext(username, password, domain, workstation, ntlm_compatibility=0) # Put the ntlm_compatibility level here, 0-2 for LM Auth/NTLMv1 Auth
negotiate_message = ntlm_context.step()

# Attach the negotiate_message to your NTLM/NEGOTIATE HTTP header and send to the server. Get the challenge response back from the server
challenge_message = http.response.headers['HEADERFIELD']

authenticate_message = ntlm_context.step(challenge_message)

# Attach the authenticate_message ot your NTLM_NEGOTIATE HTTP header and send to the server. You are now authenticated with NTLMv1

NTLMv2

NTLMv2 认证是微软最新的 NTLM 认证方法,应该作为默认选项选择,除非您需要较老的认证方法。实现与 NTLMv1 相同,但增加了可选的 server_certificate_hash 变量,且未指定 ntlm_compatibility。

import base64
import socket

from ntlm_auth.gss_channel_bindings import GssChannelBindingsStruct
from ntlm_auth.ntlm import NtlmContext

username = 'User'
password = 'Password'
domain = 'Domain' # Can be blank if you are not in a domain
workstation = socket.gethostname().upper() # Can be blank if you wish to not send this info

# create the CBT struct if you wish to bind it with the auth response
server_certificate_hash = '96B2FC1EC30792619286A0C7FD62863E81A6564E72829CBC0A46F7B1D5D92A18'
certificate_digest = base64.b16decode(server_certificate_hash)
cbt_data = GssChannelBindingsStruct()
cbt_data[cbt_data.APPLICATION_DATA] = b'tls-server-end-point:' + certificate_digest

ntlm_context = NtlmContext(username, password, domain, workstation, cbt_data, ntlm_compatibility=3)
negotiate_message = ntlm_context.step()

# Attach the negotiate_message to your NTLM/NEGOTIATE HTTP header and send to the server. Get the challenge response back from the server
challenge_message = http.response.headers['HEADERFIELD']

authenticate_message = ntlm_context.step(challenge_message)

# Attach the authenticate_message ot your NTLM_NEGOTIATE HTTP header and send to the server. You are now authenticated with NTLMv1

签名/密封

NTLM 的所有版本都支持消息内容的签名(完整性)和密封(机密性)。此功能可以向发送和接收自服务器的消息添加这些改进。虽然如果服务器支持的话,它会加密数据,但它只使用 RC4 和 128 位密钥进行加密,这并不安全,在较老的系统上,此密钥长度可能是 56 位或 40 位。虽然该功能已经过测试并与微软文档相符,但尚未在集成环境中进行全面测试。再次提醒,这尚未经过彻底测试,并且仅通过了单元测试及其预期。

import base64
import socket

from ntlm_auth.ntlm import NtlmContext

username = 'User'
password = 'Password'
domain = 'Domain' # Can be blank if you are not in a domain
workstation = socket.gethostname().upper() # Can be blank if you wish to not send this info

# create the CBT struct if you wish to bind it with the auth response
server_certificate_hash = '96B2FC1EC30792619286A0C7FD62863E81A6564E72829CBC0A46F7B1D5D92A18'
certificate_digest = base64.b16decode(server_certificate_hash)
cbt_data = GssChannelBindingsStruct()
cbt_data[cbt_data.APPLICATION_DATA] = b'tls-server-end-point:' + certificate_digest

ntlm_context = NtlmContext(username, password, domain, workstation, cbt_data, ntlm_compatibility=3)
negotiate_message = ntlm_context.step()

# Attach the negotiate_message to your NTLM/NEGOTIATE HTTP header and send to the server. Get the challenge response back from the server
challenge_message = http.response.headers['HEADERFIELD']

authenticate_message = ntlm_context.step(challenge_message)

# Attach the authenticate_message ot your NTLM_NEGOTIATE HTTP header and send to the server. You are now authenticated with NTLMv1

# Encrypt the message with the wrapping function and send the message
enc_message = ntlm_context.wrap("Message to send", encrypt=True)
request.body = msg_data
request.send

# Receive the response from the server and decrypt
response_msg = response.content
response = ntlm_context.unwrap(response_msg)

队列

  • 如果运行在 Windows 上,则自动获取 Windows 版本;如果不是这种情况,则使用默认值。

  • 在初始化ntlm上下文时添加参数,如果服务器不支持用于封印的128位密钥则抛出异常并取消认证

  • 在初始化ntlm上下文时添加参数,对于较旧的服务器不发送MIC结构

  • 添加参数以独立验证从服务器返回的目标名称和传递的值

项目详情


下载文件

下载适合您平台的文件。如果您不确定选择哪个,请了解更多关于安装包的信息。

源分布

ntlm-auth-1.5.0.tar.gz (28.9 kB 查看哈希值)

上传时间

构建分布

ntlm_auth-1.5.0-py2.py3-none-any.whl (30.0 kB 查看哈希值)

上传时间 Python 2 Python 3

由以下提供支持