Rust安全支持提供者接口(SSPI)库sspi的使用,实现Windows身份验证与安全通信
Rust安全支持提供者接口(SSPI)库sspi的使用,实现Windows身份验证与安全通信
sspi-rs是一个Rust实现的安全支持提供者接口(SSPI)。它提供了平台无关的安全支持提供者(SSP)实现,并在Windows环境下能够使用微软原生库。
概述
sspi-rs遵循MSDN文档规范工作。目前已经实现了NT LAN Manager (NTLM),可用于平台无关的执行。您也可以通过实现SspiImpl
特性来创建自己的SSP。
易用性
一些SSPI函数可能比较复杂,因此sspi-rs通过使用构建器模式提供了更便捷的使用方式。
示例
使用SSP非常简单,只需创建一个安全提供者的实例并调用其函数即可。
以下是获取凭证句柄及其有效时间戳的示例:
use sspi::{CredentialUse, Ntlm, Sspi, Username, builders::EmptyInitializeSecurityContext, SecurityBuffer, ClientRequestFlags, DataRepresentation, BufferType, SspiImpl};
fn main() {
let account_name = "example_user";
let computer_name = "example_computer";
let mut ntlm = Ntlm::new();
let username = Username::new(&account_name, Some(&computer_name)).unwrap();
let identity = sspi::AuthIdentity {
username,
password: String::from("example_password").into(),
};
let mut acq_cred_result = ntlm
.acquire_credentials_handle()
.with_credential_use(CredentialUse::Outbound)
.with_auth_data(&identity)
.execute()
.unwrap();
let mut output_buffer = vec![SecurityBuffer::new(Vec::new(), BufferType::Token)];
// 第一次调用initialize_security_context时,输入缓冲区应为空
let mut input_buffer = vec![SecurityBuffer::new(Vec::new(), BufferType::Token)];
// 为第一次调用initialize_security_context创建构建器
// 目标名称应以协议开头,例如"HTTP/example.com"或"LDAP/example.com"
let mut builder = EmptyInitializeSecurityContext::<<Ntlm as SspiImpl>::CredentialsHandle>::new()
.with_credentials_handle(&mut acq_cred_result.credentials_handle)
.with_context_requirements(ClientRequestFlags::CONFIDENTIALITY | ClientRequestFlags::ALLOCATE_MEMORY)
.with_target_data_representation(DataRepresentation::Native)
.with_target_name("LDAP/example.com")
.with_input(&mut input_buffer)
.with_output(&mut output_buffer);
// 调用initialize_security_context
// 注意:initialize_security_context_impl返回一个生成器,对于NTLM,
// 这个生成器永远不会yield,因为NTLM不需要与第三方进行网络通信
// 但Negotiate和Kerberos需要网络通信,因此使用生成器允许
// 调用者通过generator.resume()方法提供网络信息
let _result = ntlm
.initialize_security_context_impl(&mut builder)
.resolve_to_result()
.unwrap();
// ...将输出缓冲区中的令牌与服务器交换,并重复此过程直到服务器满意或抛出错误
}
获取Windows提供的SSP的示例:
let mut negotiate = SecurityPackage::from_package_type(
SecurityPackageType::Other(String::from("Negotiate"))
);
完整示例
下面是一个完整的NTLM身份验证示例,展示了如何使用sspi-rs库进行Windows身份验证:
use sspi::{
AuthIdentity, BufferType, ClientRequestFlags, CredentialUse, DataRepresentation,
Ntlm, SecurityBuffer, Sspi, SspiImpl, Username,
builders::EmptyInitializeSecurityContext,
};
fn main() -> Result<(), Box<dyn std::error::Error>> {
// 1. 创建NTLM实例
let mut ntlm = Ntlm::new();
// 2. 设置用户凭证
let account_name = "your_username";
let computer_name = "your_computer_name";
let username = Username::new(&account_name, Some(&computer_name))?;
let identity = AuthIdentity {
username,
password: String::from("your_password").into(),
};
// 3. 获取凭证句柄
let mut acq_cred_result = ntlm
.acquure_credentials_handle()
.with_credential_use(CredentialUse::Outbound)
.with_auth_data(&identity)
.execute()?;
// 4. 准备输入输出缓冲区
let mut output_buffer = vec![SecurityBuffer::new(Vec::new(), BufferType::Token)];
let mut input_buffer = vec![SecurityBuffer::new(Vec::new(), BufferType::Token)];
// 5. 创建初始化安全上下文构建器
let mut builder = EmptyInitializeSecurityContext::<<Ntlm as SspiImpl>::CredentialsHandle>::new()
.with_credentials_handle(&mut acq_cred_result.credentials_handle)
.with_context_requirements(
ClientRequestFlags::CONFIDENTIALITY |
ClientRequestFlags::ALLOCATE_MEMORY
)
.with_target_data_representation(DataRepresentation::Native)
.with_target_name("LDAP/your_server.com")
.with_input(&mut input_buffer)
.with_output(&mut output_buffer);
// 6. 初始化安全上下文
let result = ntlm
.initialize_security_context_impl(&mut builder)
.resolve_to_result()?;
println!("NTLM authentication token generated: {:?}", output_buffer[0].buffer);
// 7. 这里通常会与服务器交换令牌,完成身份验证流程
// ...
Ok(())
}
使用Windows原生SSP的完整示例
use sspi::{
AuthIdentity, BufferType, ClientRequestFlags, CredentialUse, DataRepresentation,
SecurityPackage, SecurityPackageType, SecurityBuffer, Sspi, SspiImpl, Username,
builders::EmptyInitializeSecurityContext,
};
fn main() -> Result<(), Box<dyn std::error::Error>> {
// 1. 创建Negotiate SSP实例
let mut negotiate = SecurityPackage::from_package_type(
SecurityPackageType::Other(String::from("Negotiate"))
)?;
// 2. 设置用户凭证
let account_name = "your_username";
let computer_name = "your_computer_name";
let username = Username::new(&account_name, Some(&computer_name))?;
let identity = AuthIdentity {
username,
password: String::from("your_password").into(),
};
// 3. 获取凭证句柄
let mut acq_cred_result = negotiate
.acquire_credentials_handle()
.with_credential_use(CredentialUse::Outbound)
.with_auth_data(&identity)
.execute()?;
// 4. 准备输入输出缓冲区
let mut output_buffer = vec![SecurityBuffer::new(Vec::new(), BufferType::Token)];
let mut input_buffer = vec![SecurityBuffer::new(Vec::new(), BufferType::Token)];
// 5. 创建初始化安全上下文构建器
let mut builder = EmptyInitializeSecurityContext::<
<SecurityPackage as SspiImpl>::CredentialsHandle
>::new()
.with_credentials_handle(&mut acq_cred_result.credentials_handle)
.with_context_requirements(
ClientRequestFlags::CONFIDENTIALITY |
ClientRequestFlags::ALLOCATE_MEMORY
)
.with_target_data_representation(DataRepresentation::Native)
.with_target_name("HTTP/your_server.com")
.with_input(&mut input_buffer)
.with_output(&mut output_buffer);
// 6. 初始化安全上下文
let result = negotiate
.initialize_security_context_impl(&mut builder)
.resolve_to_result()?;
println!("Negotiate authentication token generated: {:?}", output_buffer[0].buffer);
// 7. 这里通常会与服务器交换令牌,完成身份验证流程
// ...
Ok(())
}
项目使用情况
以下项目使用了sspi-rs:
- Devolutions Gateway
- IronRDP
- Python SSPI Library
- NetExec
- LDAP client library
- Remote Desktop Manager
许可证
采用以下任一许可证:
- Apache License, Version 2.0
- MIT license
贡献
除非您明确说明,否则根据Apache-2.0许可证提交的任何贡献都将按上述双重许可,不附加任何额外条款或条件。
1 回复
Rust安全支持提供者接口(SSPI)库sspi的使用
概述
sspi
是一个Rust库,提供了对Windows安全支持提供者接口(SSPI)的绑定。SSPI是Windows平台用于身份验证和安全通信的核心API,支持多种安全协议如NTLM、Kerberos等。
主要功能
- Windows集成身份验证
- 安全通信通道建立
- 客户端和服务器端身份验证
- 凭证管理
- 消息加密/解密
安装
在Cargo.toml中添加依赖:
[dependencies]
sspi = "0.6"
基本使用方法
1. 客户端身份验证示例
use sspi::{ClientRequestFlags, SecurityBuffer, Sspi, SspiImpl, SecurityPackageType};
use sspi::winapi::SecBufferDesc;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = SspiImpl::new_sspi();
// 初始化安全上下文
let mut output_buffer = vec![SecurityBuffer::new(Vec::new(), 0)];
let mut client_flags = ClientRequestFlags::empty();
client.initialize_security_context(
None,
None,
"server.example.com",
client_flags,
0,
SecurityPackageType::Negotiate,
None,
&mut output_buffer,
)?;
// 处理服务器响应并继续身份验证
// ...
Ok(())
}
2. 服务器端身份验证示例
use sspi::{AcceptSecurityContext, ServerRequestFlags, SecurityBuffer, Sspi, SspiImpl};
use sspi::winapi::SecBufferDesc;
fn authenticate_client(token: &[u8]) -> Result<(), Box<dyn std::error::Error>> {
let mut server = SspiImpl::new_sspi();
let mut input_buffer = vec![SecurityBuffer::new(token.to_vec(), 0)];
let mut output_buffer = vec![SecurityBuffer::new(Vec::new(), 0)];
let mut server_flags = ServerRequestFlags::empty();
server.accept_security_context(
None,
None,
&mut input_buffer,
server_flags,
0,
&mut output_buffer,
)?;
// 处理客户端响应并完成身份验证
// ...
Ok(())
}
3. 安全消息交换
use sspi::{EncryptMessage, Sspi, SspiImpl, SecurityBuffer};
use sspi::winapi::SecBufferDesc;
fn encrypt_message(sspi: &mut SspiImpl, message: &[u8]) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
let mut buffers = vec![
SecurityBuffer::new(message.to_vec(), 0),
SecurityBuffer::new(Vec::new(), 0),
];
sspi.encrypt_message(0, &mut buffers, 0)?;
Ok(buffers[0].buffer)
}
fn decrypt_message(sspi: &mut SspiImpl, encrypted: &[u8]) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
let mut buffers = vec![
SecurityBuffer::new(encrypted.to_vec(), 0),
SecurityBuffer::new(Vec::new(), 0),
];
sspi.decrypt_message(&mut buffers极狐GitLab 15.9 发布,带来多项功能改进与安全增强