客户端 - 服务器身份验证 - 使用SSPI?

问题描述 投票:26回答:5

我正在研究客户端 - 服务器应用程序,我希望客户端使用用户的登录凭据向服务器验证自身,但我不希望用户必须输入他们的用户名和密码。我当然不想负责安全处理密码。我只需要用户向我证明他们是他们所说的人,然后我的服务器就可以继续执行并随意授予/拒绝命令。

我的用户是域的一部分,因此我希望能够使用他们登录时创建的登录凭据。

我没有使用任何类型的Web服务,也不想使用。我控制客户端和服务器软件,两者都是用纯C#编写的,并使用好的插槽来完成工作。

我更喜欢用纯C#/ .Net来做这件事,但我愿意使用不安全的C#和pinvokes到win32 API,如果这意味着我将完成工作。

我已经在Windows中阅读了一些关于SSPI的内容,但是由于这种应用程序开发对我来说很陌生,所以我在黑暗中有点感觉。

有人知道怎么做这个吗? SSPI是这样的吗?如何在C#中使用SSPI?是否有.Net原生方式,以便我的代码可以保持可移植性?

c# .net windows-authentication sspi
5个回答
23
投票

更新:

SSPI是正确的方法。 API不是很难使用,但需要一个体积适中的项目来包装到C#中。

在研究解决这个问题的必要部分的过程中,我写了一个项目,在.Net中提供SSPI。下面我将介绍与Windows SSPI API接口的基础知识,以便任何人都可以复制我的结果。如果您发现自己想在.Net中使用SSPI,我可能会建议您使用我创建的项目来解决此问题:

NSspi - A .Net interface to the SSPI API

SSPI为您提供包含身份验证令牌的原始字节数组,然后您可以决定如何传输 - 无论是通过带有二进制格式消息的套接字,自定义XML通道,.Net Remoting,某种形式的WCF,甚至是串行端口。你可以决定如何处理它们。使用SSPI,服务器可以对客户端进行身份验证,安全地识别客户端,甚至使用与客户端建立的安全上下文执行基本的消息处理过程,如加密/签名。

SSPI API在此处记录:SSPI API overview

具体来看看以下功能:

典型的工作流程是每一方都将使用AcquireCredentialsHandle初始化其凭据。然后,身份验证周期开始并按如下方式进行:

  • 客户端调用InitializeSecurityContext,不提供输入令牌,它以字节数组的形式返回输出令牌。 ISC返回“ContinueNeeded”以指示身份验证周期未完成。
  • 客户端以任何方式将令牌发送到服务器。
  • 服务器将接收到的令牌作为输入提供给AcceptSecurityContext,并生成自己的输出令牌。 ASC还返回“ContinueNeeded”以指示身份验证周期未完成。
  • 然后,服务器将其输出令牌发送到客户端。
  • 客户端提供服务器令牌作为InitializeSecurityContext的输入,InitializeSecurityContext返回新的输出令牌。
  • 客户端将其新输出令牌发送到服务器。
  • ...

此循环一直持续到客户端看到InitializeSecurityContext返回'OK'并且服务器看到AcceptSecurityContext返回'OK'。每个函数都可以返回'OK'并仍然提供输出标记(由非空返回指示),以指示它仍然必须将数据发送到另一侧。这就是客户知道它的一半完成但服务器仍然不完整的方式;如果服务器在客户端之前完成,则反之亦然。哪一方首先完成(返回'OK')取决于SSPI在引擎盖下使用的特定安全包,任何SSPI消费者都应该知道这一点。

上述信息应足以让任何人与SSPI系统连接,以便在其应用程序中提供“Windows集成身份验证”并复制我的结果。

下面是我之前的回答,因为我学习了如何调用SSPI API。


我忘记了这个问题,几天前巧妙地回到了这个问题。我确实需要在一两年内解决这个问题:)

它可能在.Net中,我目前正在开发一个我打算发布的.Net SSPI包装器。

我的工作是基于微软发现的一些SSPI samples

该示例包含一个C ++ / CLI托管程序集,该程序集实现了SSPI API的必要部分(在从REMSSPI.exe文件中提取的文件夹Microsoft\Samples\Security\SSPI\SSPI中)。然后,他们有两个UI,一个客户端应用程序和一个服务器应用程序,两者都是用C#编写的,它们使用这个API来执行SSPI身份验证。

UI使用.Net远程处理工具将它们连接在一起,但如果我正确理解SSPI API,客户端和服务器需要交换的唯一信息包含包含安全上下文令牌数据的byte [],它可以轻松集成到您想要的任何通信基础设施中;就我而言,是我自己设计的二进制协议。

关于让样本工作的一些注意事项 - 他们拥有'SSPI'库源代码,在VS 2005下最好编译,尽管我已经让它在2008年工作了; 2010或更高版本需要进行一些返工,因为它们使用的是不推荐使用的语言结构。您可能还需要修改作为平台SDK一部分的头文件,因为它们使用const指针赋值给非对象变量,而且我不知道让编译器满意的更好方法(我从未使用过C ++ / CLI之前)。

它们在Microsoft \ Samples \ Security \ SSPI \ bin文件夹中包含已编译的SSPI dll。要使客户端/服务器二进制文件工作,您必须将该dll复制到其bin目录,否则将失败的程序集解析。

总结一下:

  • here下载REMSSPI.exe样本自解压zip。
  • 解压缩REMSSPI.exe文件(两次..)
  • 微软\样本\安全\ SSPI \ bin\ - 包含已编译的dll Microsoft.Samples.Security.SSPI.dll SSPI\ - 包含dll的源代码 Sample\ - 包含UI源代码 bin\ - 包含构建UI示例。复制SSPI.dll文件并运行ControlPanel.Client.exeControlPanel.Server.exe

0
投票

尼古拉是对的;没有.NET本地方法来完成您正在做的事情(至少,不使用低级.NET套接字支持)。你当然可以潜入幕后做一些互操作黑魔法,但是如果客户端和服务器都在你的控制之下,你可能需要考虑稍微向上移动堆栈并使用更高级别的API,例如WCF。具有.NET本机支持Windows集成身份验证。

根据您的问题和您描述的环境,您将能够使用NetTcpBinding,它提供高性能以及您正在寻找的身份验证/身份流的管道(它还提供了一种相当干净的方式来处理授权使用ServiceAuthorizationManager类)。在不知道您的应用程序/服务的具体细节的情况下,我无法提供“如何”来实现您正在寻找的内容,但我可以使用point you at the docs这个有一个相当简单的例子。


0
投票

我完全错误地使用了WindowsIdentity(这有利于授权),因为我忘记了WCF处理了很多配置文件,端点安全性和消息/传输安全性。

你试过NegotiateStream吗?给定的示例似乎更符合您的需求:在允许任何读/写之前,它使用Kerberos进行身份验证。使用CredentialCache.DefaultNetworkCredentials应该避免您查询密码。


0
投票

您可能会问:“服务器如何确认客户是他们所说的人?”

答案:如果握手的所有往返都可以成功完成,即两者都完成

  • InitializeSecurityContext返回“OK”
  • AcceptSecurityContext返回“OK”

这意味着客户端的Windows登录凭据已被确认为真实的。

AcceptSecurityContext输出CtxtHandle安全上下文(通过第6个参数)。

此上下文句柄包括客户端的Windows登录用户名。服务器可以通过调用QueryContextAttributesEx获取客户端的Windows用户名:

SecPkgContext_NativeNames pinfo;
QueryContextAttributesEx(&m_securitycontext, SECPKG_ATTR_NATIVE_NAMES, &pinfo);

这填充了Native Names结构:

SecPkgContext_NativeNames 
{
   SEC_CHAR *sClientName;
   SEC_CHAR *sServerName;
}

pinfo.sClientName是客户端的真实登录用户名。

注意:之前的握手已经保证了安全上下文的真实性,因此服务器会认为pinfo.sClientName只是客户端的真实Windows用户名。


-2
投票

曾经尝试过使用WindowsIdentity吗? 纯C#/。Net,serializable和GetCurrent()返回执行帐户。


安全令牌 用户向您的应用程序提供一组索赔以及她的请求。在Web服务中,这些声明包含在SOAP信封的安全标头中。在基于浏览器的Web应用程序中,声明通过来自用户浏览器的HTTP POST到达,并且如果需要会话,则可以稍后在cookie中缓存。无论它们如何到达,它们都必须以某种方式序列化,这就是安全令牌的来源。安全令牌是由发布机构进行数字签名的一系列序列化声明。签名很重要 - 它可以确保用户不仅仅构成一堆索赔并将其发送给您。在不需要或不需要加密的低安全性情况下,您可以使用无符号令牌,但这不是我将在本文中关注的场景。 WIF的核心功能之一是能够创建和读取安全令牌。 .NET Framework中的WIF和底层管道处理所有加密繁重工作,并向您的应用程序提供一组您可以阅读的声明。

引自qazxsw poi

你的主要问题是:

“是否有纯C#/ .NET方式使用他们的登录凭据对用户进行身份验证?”

WindowsIdentity“是”您的域控制器发出的身份验证令牌,在我看来是目前最好的方法。


我在第一次发布时对WindowsIdentity知之甚少,但我也觉得这对你的问题和限制很有帮助。我做了很多阅读,最后来到了这个Windows Identity Foudation WhitePaper。 WIF的引入是不言自明的,WindowsIdentity是一套新的.NET框架,专为基于Windows /基于角色的安全问题而设计。 SSPI,Kerberos是整个Windows身份验证过程的一部分,用户/机器/进程获取的登录令牌由域控制器授予,无法通过“简单”实现新的WindowsIdentity对象来获取。如果存在这种非法的安装,整个Windows安全模型(域,UAC等)将会死亡。

这是一个(非常!)小控制台程序,如果您不属于“BUILTIN \ Administrateurs”(根据您自己的需要更改组名称),则抛出异常。每当“以管理员身份运行”时,程序完成且没有错误。 有一组非常大的权限,每个需求都是基于声明的(是xxx的身份标识?)

page

我希望这将有所帮助。

© www.soinside.com 2019 - 2024. All rights reserved.