背景:
トラフィックが通過するときに SSL を復号化するロード バランサーの背後にある IIS 7.0 でホストされているサービスがあります。
サービスに必要なセキュリティ モードは混合モード、つまり TransportWithMessageSecurity です。
クライアントが SSL 経由でロード バランサーと通信できるようにしながら、サービスが HTTP トラフィックを受け入れられるようにするために、カスタム HttpTransportBindingElement をチャネル スタックに追加するユーザー定義バインディングを作成しました。
カスタム HttpTransportBindingElement は、メッセージの暗号化と署名が可能であることをフレームワークにアサートします。したがって、トランスポートはメッセージの署名/暗号化を行っていると主張しているため、HTTP 経由でトラフィックが入ってきても、フレームワークは文句を言いません。 ..そうではないのに。
(すべての関係者にとって、これはセキュリティ的に許容できると判断されました。なぜなら、メッセージは本来 SSL 経由でロード バランサーに到達するはずだったからです... )
問題:
svcutil.exe を使用してクライアント プロキシを生成すると、生成された自動生成された app.config ファイルには、HTTP 経由でアドレス指定されるサービスへのエンドポイントが含まれます。これは HTTPS 経由である必要があります。
さらに、 <customBinding> ノード内の <transport> 要素は、 <httpsTransport> 要素である必要がある場合、 <httpTransport> 要素として定義されます。
これは、サーバー上のフレームワークによって生成された WSDL が、カスタム HttpTransportBindingElement (上記で説明したように) を使用した結果として、HTTPS ではなく HTTP アドレスで構築されているためだと思われます。
クライアント用に自動生成された app.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.serviceModel>
<bindings>
<customBinding>
<binding name="myBindingEndpoint">
<!-- WsdlImporter encountered unrecognized policy assertions in ServiceDescription 'http://tempuri.org/': -->
<!-- <wsdl:binding name='myBindingEndpoint'> -->
<!-- <sp:HttpToken xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">..</sp:HttpToken> -->
<security defaultAlgorithmSuite="Default" authenticationMode="CertificateOverTransport"
requireDerivedKeys="true" securityHeaderLayout="Strict" includeTimestamp="true"
keyEntropyMode="CombinedEntropy" messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10">
<localClientSettings cacheCookies="true" detectReplays="false"
replayCacheSize="900000" maxClockSkew="00:05:00" maxCookieCachingTime="Infinite"
replayWindow="00:05:00" sessionKeyRenewalInterval="10:00:00"
sessionKeyRolloverInterval="00:05:00" reconnectTransportOnFailure="true"
timestampValidityDuration="00:05:00" cookieRenewalThresholdPercentage="60" />
<localServiceSettings detectReplays="false" issuedCookieLifetime="10:00:00"
maxStatefulNegotiations="128" replayCacheSize="900000" maxClockSkew="00:05:00"
negotiationTimeout="00:01:00" replayWindow="00:05:00" inactivityTimeout="00:02:00"
sessionKeyRenewalInterval="15:00:00" sessionKeyRolloverInterval="00:05:00"
reconnectTransportOnFailure="true" maxPendingSessions="128"
maxCachedCookies="1000" timestampValidityDuration="00:05:00" />
<secureConversationBootstrap />
</security>
<textMessageEncoding maxReadPoolSize="64" maxWritePoolSize="16"
messageVersion="Default" writeEncoding="utf-8">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
</textMessageEncoding>
<httpTransport manualAddressing="false" maxBufferPoolSize="524288"
maxReceivedMessageSize="65536" allowCookies="false" authenticationScheme="Anonymous"
bypassProxyOnLocal="false" decompressionEnabled="true" hostNameComparisonMode="StrongWildcard"
keepAliveEnabled="true" maxBufferSize="65536" proxyAuthenticationScheme="Anonymous"
realm="" transferMode="Buffered" unsafeConnectionNtlmAuthentication="false"
useDefaultWebProxy="true" />
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="http://myserver/GAEASSLWcfService/ServiceOverSSL.svc"
binding="customBinding" bindingConfiguration="myBindingEndpoint"
contract="IServiceOverSSL" name="myBindingEndpoint" />
</client>
</system.serviceModel>
</configuration>
回避策:
<httpTransport /> を <httpsTransport /> に変更し、HTTPS を使用するようにエンドポイントのアドレスを変更するだけで問題が解決します。
しかし、サービスの利用者に .config ファイルを変更するように指示する必要はありません... サービスの使用は、可能な限りシームレスにする必要があります...
質問:
クライアントプロキシが正しいアドレスとトランスポート要素で自動的に生成されるようにするにはどうすればよいですか?
参考文献: 「ロードバランサ/ssl デクリプタの背後にあるサービス」とカスタム HttpTransportBindingElement の解決策について知りたい場合は、ユーザー定義バインディングの構築に関する ZZZ によるこの投稿 XXX と、一部に関する ZZZ によるこの投稿 XXX を参照してください。ロード バランシング/SSL アクセラレータの背後にあるサービスを公開する際のその他の問題について説明します。