web-dev-qa-db-ja.com

クライアントサーバー認証-SSPIを使用していますか?

クライアントサーバーアプリケーションで作業していて、ユーザーのログオン資格情報を使用してクライアントがサーバーに対して自分自身を認証したいのですが、ユーザーにユーザー名とパスワードを入力させる必要はありません。安全にパスワードを処理する責任を負いたくないのは確かです。私はユーザーが彼らが彼らがそうであると彼らが言うとおりであることを私に証明することだけを必要とします、そしてそれから私のサーバーは先に進んでそれが好きなようにコマンドを許可/拒否することができます。

ユーザーはドメインの一部なので、ユーザーがログインしたときに作成したログオン資格情報を使用できるようにしたいと考えています。

私はどのような種類のWebサービスも使用していませんし、使用したくありません。私はクライアントソフトウェアとサーバーソフトウェアの両方を制御し、どちらも純粋なC#で記述されており、作業を完了するために適切なol 'ソケットを使用しています。

私は純粋なC#/。Netでこれを行うことを好みますが、安全でないC#とwin32 APIへのピンボークを使用することはできます。

私はWindowsでSSPIについて少し読んだことがありますが、この種のアプリケーション開発は初めてなので、暗闇の中で少し感じています。

誰かがこれを行う方法を知っていますか? SSPIはありますか? C#内からSSPIをどのように使用しますか?私のコードを移植可能に保つための.Netネイティブの方法はありますか?

27
antiduh

更新:

SSPIはこのための適切なアプローチです。 APIの使用はそれほど難しくありませんが、C#にラップするには適切なサイズのプロジェクトが必要です。

この質問を解決するために必要なビットを調査する過程で、.NetでSSPIを提供するプロジェクトを書きました。以下では、Windows SSPI APIとのインターフェイスの基本について説明し、誰でも私の結果を再現できるようにします。 .NETでSSPIを使用したい場合は、私が作成したプロジェクトを使用してこれを解決することをお勧めします。

NSspi-SSPI APIへの.Netインターフェイス

SSPIは、バイナリ形式のメッセージを含むソケット、カスタムXMLチャネル、.Net Remoting、何らかの形式のWCF、一体、シリアルポートなど、送信方法を決定する認証トークンを含む生のバイト配列を提供します。あなたはそれらに対処する方法を決めるようになります。 SSPIを使用すると、サーバーはクライアントを認証し、クライアントを安全に識別し、クライアントで確立されたセキュリティコンテキストを使用して暗号化/署名などの基本的なメッセージ処理手順を実行することもできます。

SSPI APIは次のとおりです: SSPI APIの概要

具体的には、次の関数を見てください。

  • AcquireCredentialsHandle
    • 何らかの形式の資格情報(現在のユーザーのログオンなど)のハンドルを取得します。サーバーとクライアントによって使用されます。
  • InitializeSecurityContext
    • クライアントがサーバーとのセキュリティコンテキストを確立するために使用します。
  • AcceptSecurityContext
    • サーバーがクライアントとのセキュリティコンテキストを確立するために使用します。

典型的なワークフローは、両側がAcquireCredentialsHandleを使用して資格を初期化することです。認証サイクルが開始され、次のように進行します。

  • クライアントはInitializeSecurityContextを呼び出し、入力トークンを提供しません。これにより、バイト配列の形式で出力トークンが返されます。 ISCは「ContinueNeeded」を返し、認証サイクルが完了していないことを示します。
  • クライアントは、必要な方法でトークンをサーバーに送信します。
  • サーバーは受け取ったトークンをAcceptSecurityContextへの入力としてフィードし、独自の出力トークンを生成します。 ASCは「ContinueNeeded」も返し、認証サイクルが完了していないことを示します。
  • 次に、サーバーはその出力トークンをクライアントに送信します。
  • クライアントは、新しい出力トークンを返すInitializeSecurityContextへの入力としてサーバートークンを提供します。
  • クライアントは新しい出力トークンをサーバーに送信します。
  • ...

このサイクルは、クライアントがInitializeSecurityContextが 'OK'を返し、サーバーがAcceptSecurityContextが 'OK'を返すまで続きます。各関数は 'OK'を返し、出力トークン(null以外の戻り値で示される)を提供して、データを反対側に送信する必要があることを示します。これは、クライアントが半分が完了したことを知る方法ですが、サーバーはまだ不完全です。サーバーがクライアントの前に完了する場合はその逆です。最初に完了する(「OK」を返す)側は、SSPIによって内部で使用されている特定のセキュリティパッケージに依存します。SSPIコンシューマーはこれを認識しておく必要があります。

上記の情報は、アプリケーションで「Windows統合認証」を提供し、私の結果を複製するために、だれでもSSPIシステムとやり取りするのに十分なはずです。

以下は、SSPI APIを呼び出す方法を学習したときの私の以前の回答です。


私はこの質問を忘れており、偶然にも数日前に気まぐれにこの問題に戻りました。私は1年か2年でこの問題を解決する必要があります:)

これは.Netでも可能です。現在、公開する.Net SSPIラッパーを開発しています。

私が見つけたいくつかのMicrosoftの SSPIサンプル に基づいて作業を行っています。

サンプルには、SSPI APIの必要な部分(REMSSPI.exeファイルから抽出されたMicrosoft\Samples\Security\SSPI\SSPIフォルダー内)を実装するC++/CLI管理のアセンブリが含まれています。次に、クライアントアプリケーションとサーバーアプリケーションの2つのUIがあり、どちらもこのAPIを使用してSSPI認証を実行するC#で記述されています。

UIは.Netリモーティング機能を使用してすべてを結び付けますが、SSPI APIを正しく理解している場合、クライアントとサーバーが交換する必要がある唯一の情報は、セキュリティコンテキストトークンデータを含むbyte []で構成されます。必要な通信インフラストラクチャに簡単に統合できます。私の場合、自分の設計のバイナリプロトコル。

サンプルを機能させるためのいくつかの注意事項-「SSPI」ライブラリソースがあり、VS 2005で最適にコンパイルできますが、2008年で機能するようにしています。 2010以降では、廃止された言語構成体を使用しているため、多少の手直しが必要になります。プラットフォームSDKの一部であるヘッダーファイルを変更する必要がある場合もあります。これは、unconst変数へのconstポインターの割り当てを利用しているためです。コンパイラーを幸せにするためのより良い方法がわかりません(私はC++ /以前はCLI)。

Microsoft\Samples\Security\SSPI\binフォルダーにコンパイル済みSSPI dllが含まれています。クライアント/サーバーのバイナリを機能させるには、そのdllをそれらのbinディレクトリにコピーする必要があります。それ以外の場合は、アセンブリの解決に失敗します。

要約すると:

  • here にアクセスして、REMSSPI.exeサンプルの自己解凍型Zipをダウンロードします。
  • REMSSPI.exeファイルを抽出します(2回..)
  • Microsoft\Samples\Security\SSPI\
    • bin\-コンパイル済みdllが含まれますMicrosoft.Samples.Security.SSPI.dll
    • SSPI\-DLLへのソースが含まれています
    • Sample\-UIソースコードが含まれています
      • bin\-ビルドUIサンプルが含まれています。ここにSSPI.dllファイルをコピーし、ControlPanel.Client.exeおよびControlPanel.Server.exeを実行します
23
antiduh

ニコラは正しいです。あなたがやっていることを達成するための.NETネイティブの方法はありません(少なくとも、低レベルの.NETソケットサポートを使用しない)。カバーの下でダイビングして相互運用の黒魔術を行うこともできますが、クライアントとサーバーの両方が制御下にある場合は、スタックを少し上に移動し、WCFなどのより高レベルのAPIを使用することを検討してください。 Windows統合認証を.NETネイティブでサポートしています。

質問と説明した環境に基づいて、NetTcpBindingを使用できます。NetTcpBindingは、高性能と、探している認証/ IDフローの配管を提供します(承認を処理するためのかなりクリーンな方法も提供します) ServiceAuthorizationManagerクラスを使用)。アプリ/サービスの詳細を知らなければ、私はあなたが望んでいることを実装するための「ハウツー」を提供することはおそらくできませんが、私はできる ドキュメントであなたを指す 例。

0
Andy Hopper

あなたは尋ねるかもしれません:「サーバーはどのようにしてクライアントが本人であるかを確認しますか?」

Answer:ハンドシェイクのすべてのラウンドトリップが正常に終了した場合、つまり両方

  • InitializeSecurityContextは「OK」を返します
  • AcceptSecurityContextは「OK」を返します

これは、クライアントのWindowsログイン資格情報が本物であることが確認されたことを意味します。

AcceptSecurityContextCtxtHandleセキュリティコンテキストを出力します(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ユーザー名です。

0
winnie_quest

WindowsIdentity(これはauthorizationに適しています)で完全に失敗しました。WCFが構成ファイル、エンドポイントセキュリティ、およびメッセージ/輸送セキュリティ。

NegotiateStream で試しましたか?与えられた例はあなたのニーズによりよく適合しているようです:読み取り/書き込みを許可する前に認証にKerberosを使用します。 CredentialCache.DefaultNetworkCredentialsを使用すると、パスワードを照会する必要がなくなります。

0
xum59