TLS/SSL を使ってソケット接続のセキュリティを確保する方法 (HTML)
[ この記事は、Windows ランタイム アプリを作成する Windows 8.x および Windows Phone 8.x 開発者を対象としています。Windows 10 向けの開発を行っている場合は、「最新のドキュメント」をご覧ください]
このトピックでは、Windows ストア アプリで StreamSocket の機能を使うとき、TLS/SSL を使ってストリーム ソケット接続のセキュリティを確保する方法について説明します。
理解しておく必要があること
テクノロジ
-
ソケットと WebSocket を使ったネットワーク通信を可能にします。
必要条件
- このトピックのコード例は、JavaScript で記述されています。ソケットと SSL/TLS の使用についての基本的な理解があることが条件となります。
SSL/TLS 接続の概要
Secure Sockets Layer (SSL) とより新しいトランスポート層セキュリティ (TLS) は、ネットワーク通信の認証と暗号化を実現するように設計された暗号化プロトコルです。これらのプロトコルは、ネットワーク データの送受信時に傍受や改ざんを防ぐように設計されています。 これらのプロトコルでは、クライアント/サーバー モデルを使ってプロトコル交換が行われます。また、デジタル証明書と証明機関を使って、サーバーが本物であることが確認されます。TLS プロトコルは、IETF の RFC 5246 に記載されています。 従来の SSL プロトコルは、Netscape Communications によって文書化されました。 SSL はこの両方のプロトコルを指すことがよくあります。
StreamSocket オブジェクトは、クライアントとサーバー間の通信に SSL/TLS を使うように構成できます。この SSL/TLS のサポートは、SSL/TLS ネゴシエーションで StreamSocket オブジェクトをクライアントとして使うことに制限されます。現在、サーバーとしての SSL/TLS ネゴシエーションは StreamSocket 用に実装されていないので、接続が受信されて作成済みの StreamSocket で SSL/TLS が有効になるとき、作成済みの StreamSocket と一緒に StreamSocketListener で SSL/TLS を使うことはできません。 SSL/TLS のクライアント サポートには、クライアント証明書を使う機能は含まれていません。
StreamSocket 接続のセキュリティを確保するには 2 つの方法があります。
- ConnectAsync - ネットワーク サービスへの最初の接続を確立してすぐに、すべての通信で SSL/TLS を使うようにネゴシエートします。
- UpgradeToSslAsync - 最初に暗号化なしでネットワーク サービスに接続します。アプリでデータが送受信される場合があります。その後、以降のすべての通信で SSL/TLS を使うように接続をアップグレードします。
ConnectAsync の使用
ネットワーク サービスへの最初の接続を確立してすぐに、すべての通信で SSL/TLS を使うようにネゴシエートします。protectionLevel パラメーターを渡すことができる ConnectAsync メソッドは 2 つあります。
- ConnectAsync(EndpointPair, SocketProtectionLevel) - StreamSocket オブジェクトで、EndpointPair オブジェクトと SocketProtectionLevel で指定したリモート ネットワークの宛先に接続する非同期操作を開始します。
- ConnectAsync(HostName, String, SocketProtectionLevel) - StreamSocket オブジェクトで、リモート ホスト名、リモート サービス名、SocketProtectionLevel で指定したリモートの宛先に接続する非同期操作を開始します。
上記のいずれかの ConnectAsync メソッドを呼び出すときに protectionLevel パラメーターが Windows.Networking.Sockets.SocketProtectionLevel.Ssl に設定されていると、StreamSocket では SSL/TLS を使って暗号化を行う必要があります。この値を指定すると暗号化が必要になり、NULL 暗号を使うことはできません。
これらの ConnectAsync メソッドで使う一般的な手順は同じです。
- StreamSocket を作成します。
- ソケットの詳細オプションが必要な場合は、StreamSocket.Control プロパティを使って、StreamSocket オブジェクトに関連付けられている StreamSocketControl インスタンスを取得します。 StreamSocketControl のプロパティを設定します。
- 上記のいずれかの ConnectAsync メソッドを呼び出し、リモートの宛先に接続する操作を開始してすぐに、SSL/TLS の使用をネゴシエートします。
次の例では、StreamSocket を作り、ネットワーク サービスへの接続を確立してすぐに、SSL/TLS を使うようにネゴシエートします。ネゴシエーションに成功すると、クライアントとネットワーク サーバー間で StreamSocket を使うすべてのネットワーク通信が暗号化されます。
// Define some global variables that can be used from
// multiple functions as needed
var clientSocket = null;
var serverHostName = null;
var serverServiceName = null;
function openClient() {
clientSocket = new Windows.Networking.Sockets.StreamSocket();
// Try to connect to contoso using HTTPS (port 443)
serverHostName = new Windows.Networking.HostName("www.contoso.com");
serverServiceName = "https";
// Call connectAsync method with SSL
clientSocket.connectAsync(serverHostName, serverServiceName, Sockets.SocketProtectionLevel.Ssl).done(onClientAccept, onConnectError);
}
// For simplicity, the sample omits implementation of the
// displayStatus method used to display status and error messages
// If the client connection was accepted, display
// a message to the user
function onClientAccept() {
socketSample.displayStatus("Client: connection completed.");
}
// The connection failed so display an error message
// Could retry the connection, but for this simple example
// just close the socket.
function onConnectError(reason) {
socketsSample.displayStatus(reason);
clientSocket.close();
clientSocket = null;
}
UpgradeToSslAsync の使用
ネットワーク サービスへの最初の接続を暗号化なしで確立します。アプリでデータが送受信される可能性があるため、以降のすべての通信で SSL/TLS を使うように接続をアップグレードします。次のメソッドが使われます。
- UpgradeToSslAsync - StreamSocket オブジェクトで SSL を使うようにアップグレードする非同期操作を開始します。
UpgradeToSslAsync メソッドは 2 つのパラメーターを受け取ります。protectionLevel パラメーターは、目的の保護レベルを示します。validationHostName パラメーターは、SSL へのアップグレード時の検証に使われるリモート ネットワークの宛先のホスト名です。 通常、validationHostName は、アプリが最初に接続を確立するときに使ったホスト名と同じです。上記の UpgradeToSslAsync メソッドを呼び出すときに protectionLevel パラメーターが Windows.System.Socket.SocketProtectionLevel.Ssl に設定されていると、StreamSocket では SSL/TLS を使って暗号化を行う必要があります。この値を指定すると暗号化が必要になり、NULL 暗号を使うことはできません。
UpgradeToSslAsync メソッドで使う一般的な手順は次のとおりです。
- StreamSocket を作成します。
- ソケットの詳細オプションが必要な場合は、StreamSocket.Control プロパティを使って、StreamSocket オブジェクトに関連付けられている StreamSocketControl インスタンスを取得します。 StreamSocketControl のプロパティを設定します。
- データを暗号化せずに送受信する必要がある場合は、ここで送信します。
- UpgradeToSslAsync メソッドを呼び出して、SSL/TLS を使うように接続をアップグレードする操作を開始します。
次の例では、StreamSocket を作り、ネットワーク サービスへの接続を確立して最初のデータを送って、SSL/TLS を使うようにネゴシエートします。ネゴシエーションに成功すると、クライアントとネットワーク サーバー間で StreamSocket を使うすべてのネットワーク通信が暗号化されます。
// Define some global variables that can be used from
// multiple functions as needed
var clientSocket = null;
var serverHostName = null;
var serverServiceName = null;
function openClient() {
clientSocket = new Windows.Networking.Sockets.StreamSocket();
// Try to connect to contoso initially using HTTP
serverHostName = new Windows.Networking.HostName("www.contoso.com");
serverServiceName = "http";
// Call ConnectAsync method to establish initial connection
clientSocket.connectAsync(serverHostName, serverServiceName).done(onClientAccept, onConnectError);
}
// For simplicity, the sample omits implementation of the
// displayStatus method used to display status and error messages
// If the client connection was accepted, display
// a message to the user
function onClientAccept() {
socketSample.displayStatus("Client: connection completed.");
sendHello();
}
// The connection failed so display an error message
// We could retry the connection, but for this simple example
// we just close the socket.
function onConnectError(reason) {
socketsSample.displayStatus(reason);
clientSocket.close();
clientSocket = null;
}
// Send some data in a simple format that is
// the length of the string of data in a 4-byte integer
// followed by the string
function sendHello() {
if (!clientSocket) {
socketsSample.displayStatus("Client: you must connect the client before using it.");
return;
}
var writer = new Windows.Storage.Streams.DataWriter(socketsSample.clientSocket.outputStream);
var string = "Hello World ☺ ";
var len = writer.measureString(string); // Gets the UTF-8 string length.
writer.writeInt32(len);
writer.writeString(string);
socketsSample.displayStatus("Client: sending hello.");
writer.storeAsync().done(onStore, onSendError);
writer.detachStream(); // Detach stream, if not, DataWriter destructor will close it.
}
function onStore() {
socketsSample.displayStatus("Client: sent hello.");
upgradeClient();
}
function onSendError(reason) {
socketsSample.displayStatus(reason);
clientSocket.close();
clientSocket = null;
}
function upgradeClient() {
if (!clientSocket) {
socketsSample.displayStatus("Client: you must connect the client before using it.");
return;
}
var validationName = serverHostName;
upgradeToSslAsync(SocketProtectionLevel.Ssl, serverHostName).done(onUpgradeAccept, onUpgradeError);
}
// If upgrade to SSL was successful, display message to user
function onUpgradeAccept() {
socketSample.displayStatus("Client: upgrade to SSL completed.");
}
// The upgrade connection failed so display an error message
// We could retry the upgrade possibly changing the validationHostname,
// but for this simple example we just close the socket.
function onUpgradeError(reason) {
socketsSample.displayStatus(reason);
clientSocket.close();
clientSocket = null;
}
注釈
SocketProtectionLevel 列挙体には複数の値を指定できます。
PlainSocket - 暗号化なしのプレーン ソケット。
Ssl - SSL/TLS を使って暗号化を行う必要があるソケット。この値を指定すると暗号化が必要になり、NULL 暗号を使うことはできません。
この値では、SSL 3.0 プロトコルおよび TLS 1.0 プロトコルと、システムにインストールされているすべての暗号化 (NULL 暗号を除く) がサポートされます。
SslAllowNullEncryption - SSL/TLS を使って暗号化を行うことが優先されるソケット。この値を指定すると、完全な暗号化を使うことが優先されますが、サーバー構成に基づいて NULL 暗号 (暗号化なし) を使うこともできます。
BluetoothEncryptionAllowNullAuthentication - 暗号化を使うことが優先されるが、ターゲット サーバーの構成に基づいて NULL 暗号 (暗号化なし) を使うこともできる Bluetooth ソケット。
BluetoothEncryptionWithAuthentication - 暗号化を使う必要がある Bluetooth ソケット。この値を指定すると暗号化が必要になり、NULL 暗号を使うことはできません。
Ssl3AllowWeakEncryption - SSL を使って暗号化を行う必要がある TCP ソケット。この値では、SSL 3.0 プロトコルと、システムにインストールされているすべての暗号化 (NULL 暗号を除く) がサポートされます。この値を指定すると、セキュリティで保護されていないと考えられる RC4 や他の弱い暗号を使うことができます。
Tls10 - SSL を使って暗号化を行う必要がある TCP ソケット。この値では、TLS 1.0 プロトコルと、システムにインストールされているすべての暗号化 (RC4、他の弱い暗号、NULL 暗号を除く) がサポートされます。
Tls11 - SSL を使って暗号化を行う必要がある TCP ソケット。この値では、TLS 1.1 プロトコルおよび TLS 1.0 プロトコルと、システムにインストールされているすべての暗号化 (RC4、他の弱い暗号、NULL 暗号を除く) がサポートされます。
Tls12 - SSL を使って暗号化を行う必要がある TCP ソケット。この値では、TLS 1.2、TLS 1.1、TLS 1.0 の各プロトコルと、システムにインストールされているすべての暗号化 (RC4、他の弱い暗号、NULL 暗号を除く) がサポートされます。
SslAllowNullEncryption を指定すると NULL 暗号 (暗号化なし) を使うことができ、ネットワーク通信が暗号化されない可能性があるので、この値は通常は使いません。SslAllowNullEncryption の値を指定すると、SSL/TLS ネゴシエーションで、サーバーのデジタル証明書と証明機関に基づいてサーバーを検証できます。
ConnectAsync または UpgradeToSslAsync を使って実際にネゴシエートされる SSL の強度は、StreamSocketinformation.ProtectionLevel プロパティを取得して特定できます。
関連トピック
その他
辞書/リファレンス
StreamSocket.UpgradeToSslAsync
StreamSocketinformation.ProtectionLevel
サンプル