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 发布,带来多项功能改进与安全增强
回到顶部