#c# #wcf #wcf-security
#c# #wcf #wcf-безопасность
Вопрос:
У меня есть простая служба WCF, настроенная для обеспечения безопасности транспорта и учетных данных клиента сертификата. Я подключаю к нему средство проверки пользовательского сертификата и выдает исключение FaultException. Моя проблема заключается в том, что сообщение esception не доходит до клиента: я получаю только исключение MessageSecurityException без какой-либо ошибки… Если я включу свою службу в net.tcp (самостоятельно размещенную), я получу сообщение об ошибке, также без сбоев.
Вот часть моего web.config :
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="wsHttpEndpointBinding" messageEncoding="Text">
<reliableSession enabled="false" />
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="SecureService.Server.ChunkStreamService">
<endpoint binding="wsHttpBinding" bindingConfiguration="wsHttpEndpointBinding" behaviorConfiguration="myBehavior" name="wsHttpEndPoint" contract="SecureService.Server.IChunkStreamService" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="myBehavior">
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="false" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceCredentials>
<clientCertificate>
<authentication customCertificateValidatorType="SecureService.Server.CPSValidator, SecureService.Server" certificateValidationMode="Custom" />
</clientCertificate>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
и мой валидатор :
public class CPSValidator : System.IdentityModel.Selectors.X509CertificateValidator
{
public override void Validate(System.Security.Cryptography.X509Certificates.X509Certificate2 certificate)
{
throw new FaultException("Certificate is not from a trusted issuer");
}
}
Есть идеи?
Заранее спасибо за любую помощь!
Комментарии:
1. AFAIK этап проверки сертификата выполняется на другом уровне — намного ниже механизмов обработки ошибок WCF, это происходит на уровне SSL, который в данном случае находится непосредственно поверх TCP / IP…
2. Но я прочитал в msdn (что, очевидно, не работает) «Примечание: чтобы вернуть ошибки аутентификации обратно клиенту, создайте исключение FaultException в методе Validate». ( msdn.microsoft.com/en-us/library/ms733806.aspx )
3. Я провел тест с аутентификацией по имени пользователя и пользовательским валидатором: отправка FaultException позволяет повторно получить сообщение на стороне клиента… Разница с моей проверкой сертификата заключается в том, что я использую TransportWithMessageCredential : может быть, в этом смысл?
4. что-то вроде этого: аутентификация имени пользователя происходит на уровне сервиса, в то время как проверка сертификата происходит на более низком уровне (таким образом, на сетевом уровне, который ничего не знает о пользовательских исключениях)…
5. Хорошо: итак, есть ли способ выполнить проверку подлинности TransportWithMessageCredential и сертификата? Снизит ли это уровень безопасности?
Ответ №1:
Насколько я знаю, любое исключение, которое вы создаете в валидаторе, никогда не доходит до клиента. Клиент всегда получает исключение MessageSecurityException. Клиенту правильно отправляются только исключения, которые происходят на уровне сервиса (в реализации сервиса) и сопоставляются с FaultContract.
С уважением, Пабло.
Комментарии:
1. следовательно, нет способа объяснить клиенту, что произошло? (истекший / отозванный / ненадежный … сертификат или другая неизвестная проблема)
Ответ №2:
Как ответили Яхия и Пабло, проверка сертификата не выполняется на уровне обслуживания. Поэтому FaultException не может достичь клиента. Но это верно только потому, что я использую режим безопасности транспорта. Чтобы отправить сообщение обратно клиенту, мне пришлось изменить режим безопасности с Transport на TransportWithMessageCredentials, например :
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" proxyCredentialType="None" realm="" />
<message clientCredentialType="Certificate" negotiateServiceCredential="true" algorithmSuite="Default" />
</security>
Таким образом, проверка сертификата выполняется на уровне сервиса, так что сообщение об ошибке может быть отправлено клиенту через FaultException.
Ответ №3:
Вы пробовали включить диагностику WCF на сервере, чтобы выявить проблемы в конвейере WCF до того, как вызов попадет в саму службу?
<system.diagnostics>
<sources>
<source name="System.ServiceModel" switchValue="Verbose" propagateActivity="true">
<listeners>
<add name="traceListener" type="System.Diagnostics.XmlWriterTraceListener" initializeData="log.evtlog" />
</listeners>
</source>
</sources>
<trace autoflush="true"/>
Комментарии:
1. К сожалению, это не дает мне больше информации о том, что происходит, и почему мои сообщения об ошибках не поступают на сторону клиента. Похоже, Яхия и Пабло правы, когда говорят, что FaultContract существует только на уровне обслуживания.