2015-12-14 28 views
17

Webアプリケーションはサーバー上で実行されており、XDomainRequest経由で(IE9のために)http要求を送信します。SSL証明書はlocalhostでは動作しますが、コンピュータ名またはIPアドレスでは動作しません

コンソールアプリケーションがソケットリスナー経由でポートでリッスンするクライアントコンピュータが多数あります。彼らはリンクをクリックしたとき、クライアントのオープンウェブ彼らの IE9ブラウザとアプリケーションとは、Webページには、そのようにリクエストを送信します。

https://localhost:portNumber/applicationName/doSomething」 「https://computerName:portNumber/applicationName/doSomething」 「https://ipAddress:portNumber/applicationName/doSomething

第二と第三の要求があります他のユーザーのコンピュータのアプリケーションをコンソールにします。

問題は、ローカルホストにリクエストがあると、コンソールアプリケーションに着信データの読み取りと応答の返送に関する問題がないことです。しかし、 リクエストにコンピュータ名またはIPアドレスが含まれている場合は、ブラウザに認証の警告が表示され、 をクリックする必要があります。「このWebサイト(推奨しません)」リンクをクリックしてください。

コードで3つの異なる証明書を作成すると考えました。 しかし、3つのsslstreamを使用しても、真正証明書を選択することはできません。真正証明書を作成してからデータを受信するからです。だから私たちが着信要求を捕まえるとき、認証は既に行われていなければなりません。

もう1つの方法は、ソケットリスナーまたはsslstreamにこれらの3つの要求をすべてlocalhostであるかのように動作させることです。したがって、それぞれの認証はlocalhostとして行われます。しかし、私はそれのための実際の方法を見つけることができませんでした。

ここにコードがあります。多分SslStreamの使い方が間違っているので、私はコードを与えます。

using System; 
using System.Net.Sockets; 
using System.Net; 
using System.Configuration; 
using System.Security.Cryptography.X509Certificates; 
using System.Windows.Forms; 
using System.IO; 
using System.Net.Security; 
using System.Security.Authentication; 
using System.Threading; 
using System.Text; 

namespace StackOverFlowProject 
{ 
    class StackOverFlowSample 
    { 
     private static ManualResetEvent _manualResetEvent = new ManualResetEvent(false); 
     private static X509Certificate _cert = null; 

     static void Main(string[] args) 
     { 
      StackOverFlowSample stackOverFlowSample = new StackOverFlowSample(); 
      stackOverFlowSample.StartListening(); 
     } 

     private void StartListening() 
     { 
      GetCertificate(); 

      IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, 1234); 

      if (localEndPoint != null) 
      { 
       Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 

       if (listener != null) 
       { 
        listener.Bind(localEndPoint); 
        listener.Listen(10); 

        Console.WriteLine("Socket listener is running. Waiting for requests..."); 

        listener.BeginAccept(new AsyncCallback(AcceptCallback), listener); 
       } 
      } 
     } 

     private static void GetCertificate() 
     { 
      byte[] pfxData = File.ReadAllBytes(Application.StartupPath + @"\" + "localhost.pfx"); 

      _cert = new X509Certificate2(pfxData, "password", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable); 
     } 


     private void AcceptCallback(IAsyncResult result) 
     { 
      Socket listener = null; 
      Socket handler = null; 
      StateObject state = null; 
      SslStream sslStream = null; 

      _manualResetEvent.Set(); 

      listener = (Socket)result.AsyncState; 

      handler = listener.EndAccept(result); 

      state = new StateObject(); 

      if (handler.RemoteEndPoint != null) 
      { 
       state.clientIP = ((IPEndPoint)handler.RemoteEndPoint).Address.ToString(); 
      } 

      sslStream = new SslStream(new NetworkStream(handler, true)); 
      sslStream.AuthenticateAsServer(_cert, false, SslProtocols.Tls, true); 

      sslStream.ReadTimeout = 100000; 
      sslStream.WriteTimeout = 100000; 

      state.workStream = sslStream; 

      if (state.workStream.IsAuthenticated) 
      { 
       state.workStream.BeginRead(state.buffer, 0, StateObject.BufferSize, ReceiveCallback, state); 
      } 

      listener.BeginAccept(new AsyncCallback(AcceptCallback), listener); 
     } 

     private void ReceiveCallback(IAsyncResult result) 
     { 
      StateObject stateObject = null; 
      SslStream sslStreamReader = null; 

      byte[] byteData = null; 

      stateObject = (StateObject)result.AsyncState; 
      sslStreamReader = stateObject.workStream; 

      int byteCount = sslStreamReader.EndRead(result); 

      Decoder decoder = Encoding.UTF8.GetDecoder(); 
      char[] chars = new char[decoder.GetCharCount(stateObject.buffer, 0, byteCount)]; 
      decoder.GetChars(stateObject.buffer, 0, byteCount, chars, 0); 
      stateObject.sb.Append(chars); 

      if (byteCount > 0) 
      { 
       stateObject.totalReceivedBytes += byteCount; 

       string[] lines = stateObject.sb.ToString().Split('\n'); 

       if (lines[lines.Length - 1] != "<EOF>") 
       { 
        // We didn't receive all data. Continue reading... 
        sslStreamReader.BeginRead(stateObject.buffer, 0, stateObject.buffer.Length, new AsyncCallback(ReceiveCallback), stateObject); 
       } 
       else 
       { 
        Console.WriteLine("We received all data. Sending response..."); 

        byteData = Encoding.UTF8.GetBytes("Hello! I received your request!"); 

        string httpHeaders = "HTTP/1.1" + "\r\n" 
            + "Cache-Control: no-cache" + "\r\n" 
            + "Access-Control-Allow-Origin: *" + "\r\n" 
            + "\r\n"; 

        byte[] byteHttpHeaders = Encoding.UTF8.GetBytes(httpHeaders); 

        byte[] concat = new byte[byteHttpHeaders.Length + byteData.Length]; 
        Buffer.BlockCopy(byteHttpHeaders, 0, concat, 0, byteHttpHeaders.Length); 
        Buffer.BlockCopy(byteData, 0, concat, byteHttpHeaders.Length, byteData.Length); 

        stateObject.sslStreamReader = sslStreamReader; 

        sslStreamReader.BeginWrite(concat, 0, concat.Length, new AsyncCallback(SendCallback), stateObject); 
       } 
      } 
     } 

     private void SendCallback(IAsyncResult ar) 
     { 
      SslStream sslStreamSender = null; 

      StateObject stateObject = (StateObject)ar.AsyncState; 

      sslStreamSender = stateObject.sslStreamReader; 
      sslStreamSender.EndWrite(ar); 

      Console.WriteLine(stateObject.totalReceivedBytes.ToString() + " bytes sent to " + stateObject.clientIP + " address"); 

      sslStreamSender.Close(); 
      sslStreamSender.Dispose(); 
     } 

    } 

    public class StateObject 
    { 
     public SslStream workStream = null; 

     public SslStream sslStreamReader = null; 

     public const int BufferSize = 1024; 
     public byte[] buffer = new byte[BufferSize]; 
     public StringBuilder sb = new StringBuilder(); 

     public string clientIP = ""; 

     public int totalReceivedBytes = 0; 
    } 
} 
+1

これは、証明書のCNがlocalhostであるためです。検証が機能するように、要求のホスト名と一致する適切な証明書を使用する必要があります。 –

+0

ウェブサイトを実行しているコンピュータの名前がserver1であるとします。証明書はCN = server1情報を持っていますか? –

+0

しかし、certmgrでPFXファイルを開くと、CNがlocalhost以外のものに設定されていることがわかります。 –

答えて

1

あなたが遭遇している証明書の警告は、実際にはSSL証明書の共通名(ドメイン名)がWebサイト/サーバーへのアクセスに使用されたURL /アドレスと一致しないことを示す名前の不一致エラーです。あなたの使用シナリオで

https://www.sslshopper.com/ssl-certificate-name-mismatch-error.html

、あなたはコンピュータ名を活用し、簡単なドメインモデルを支持してローカルホストとIPアドレスから離れて移行することをお勧めします。 (例えば。computerName.someDomain.com

次に、プロセス間通信の認証に使用できるワイルドカード証明書(例:*.someDomain.com)を取得できます。

https://www.sslshopper.com/best-ssl-wildcard-certificate.html

5

あなたのセキュリティ男は正しいです。これを実現しようとしている方法はSSLで動作しません。

証明書がある場合は、1つのCNを認証するように設定されています。したがって、単純化した例です。 Googleには証明書があります。 https://*.google.comを認証します。つまり、google.comへのリクエストは有効な証明書を持っているとみなされます。あなたのブラウザは満足しています。

これで、コマンドプロンプト(ping google.com)が開きます。 ipアドレスを取得してください(私の場合は216.58.210.14となりました)。 「https://216.58.210.14」と入力します。あなたのブラウザは、サイトが安全でないと不平を言っています。その理由は、以前のリクエストに対応したサーバと同じものかもしれませんが、CNがGoogleではないため、証明書によると有効ではありません。 comのIPアドレスです。

サービスに接続する必要がある場合(127.0.0.1、10.92.1.4、およびmyserver.comなど)、それぞれのケースで有効な証明書が必要です。

+0

3つの異なる認証ファイルが必要な場合、またはこれらの3つのオプションがある認証ファイルを作成することができますか? –

+0

あなたの最後の文章が私を混乱させました。残りはOKです。 –

+0

証明書は定義上、1つのドメインに対してのみ動作します。だから、それぞれに1つ必要です。 IPを特定のドメインにマッピングするエントリをホストファイルに追加することで、これを回避できますが、すべてのユーザーマシンでIPを実行する必要があります。 –

1

私は何をお使いの"https://computerName:portNumber/applicationName/doSomething"手段を確認していません。したがって、証明書の権利を使用している場合、またはコードにアクセスしているか使用しているパス/接続が正しいかどうかは不明です。 https://technet.microsoft.com/en-us/library/dd891009.aspx

これは、TCPに限定されない任意のプロトコルにアクセスできます。 https://technet.microsoft.com/en-us/library/cc784450(v=ws.10).aspx

  • ワイルドカードSSL証明書は、管理者は、単一のSSL証明書と同じドメインにサブドメイン無制限の数を確保することができます。ワイルドカードSSL証明書は* .yourdomain.comに対して発行され、サブドメインごとに多数のSSL証明書を購入する必要がなく、1つのIPアドレスのみを使用する必要があるため、コスト削減効果が得られます。
  • 一般的なSSL証明書は、1つの完全修飾ドメイン名のみを保護します。ユニファイドコミュニケーション証明書を使用すると、1つの証明書に複数のホスト名(サブジェクト代替名またはSAN)を割り当てることができます。柔軟性を最大限に高めるために、マルチドメインSSL証明書ではサブジェクト別名(SAN)フィールドを使用できるため、1つのSSL証明書を使用して最大100の異なるドメイン名、サブドメイン、パブリックIPアドレスを保護できますIPアドレス。

**値は、アクセスするホスト名またはドメイン名と正確に一致する必要があります。それ以外の場合は、証明書がインポートされ、信頼された後でもブラウザ証明書のエラーが表示されます。例:以前にhttp://101.10.10.1:9000/を使用してサイトにアクセスしていて、新しい証明書の共通名が「mydomain」の場合は、ショートカットをhttp://mydomain:9000/に更新する必要があります。 mydomain:9000の証明書を作成した場合次に、サーバーのアドレス指定を行うホスト名またはCNAMEを使用します。これはとても重要です。 Webサーバーの実際のホスト名がmysubdomain.mydomain.comの場合、ユーザーはwww.mydomain.comを使用してボックスのアドレスを指定し、後者の名前を使用して「Common Name」(CNAME)の質問に答えます。

**あなたがopenssl s_time -connect remote.host:443(特定のSSLを使用して、私はOpenSSLを引用しています、トラブルシューティングするためのコマンド)またはopenssl s_time -connect remote.host:443 -www /test.html -new を使用して接続することができれば、あなたのためにSSL対応のWebサーバーが使用できない場合**チェックs_serverオプションを使用してエミュレートすることができます。

# on one host, set up the server (using default port 4433) openssl s_server -cert mycerti.pem -www # on second host (or even the same one), run s_time openssl s_time -connect mydomain:9001 -www/-new -ssl3

または

# on second host (or even the same one), run s_time openssl s_time -connect mydomain:9001 -www/-new -ssl3

**証明書が使用されているか確認してください? $ openssl s_client -connect [ip_or_dns_name]:[port] $ man s_client

0

私が提案していますソリューションは、仮定をしている:

  • サイトは、あなたがどんな問題なくネットワーク全体のマシン名でアプリケーションにアクセスすることができますIIS

  • でホストされています。

  • インターネット上のwebappにアクセスする必要はありません(認定された機関からの証明書が必要です)。

試してみてください。

I:

  1. などのIISで自己署名証明書を作成します。 IISを開いて、サーバー証明書を次のように選択します。 enter image description here

    ii。次のような自己署名証明書を作成します。 enter image description here

    iii。

    • ウェブサイトを選択するには、バインディングをクリックします。 HTTPS

      enter image description here

      IV

ため

  • [編集]をクリックしますバインディング。今、あなたはマシン名を持つあなたのアプリケーションにアクセスすることができ

    enter image description here

    :証明書を使用して結合を編集サイトは、あなたは次のように作成しました。

    同じ手順でインターネット用のドメイン証明書を繰り返すことはできますが、認定された認証局が証明書を登録/提供する必要があります。

    マシン名とネットワーク上の両方のローカル&でアプリケーションにアクセスできることに注意してください。証明書は単一のホスト名/共ドメインに対して発行されるので、ローカルマシンでもlocalhostの代わりにマシン名を使用してください。

  • 関連する問題