How to enable Session with SSL wsHttpBinding in WCF

前端 未结 3 1477
-上瘾入骨i
-上瘾入骨i 2020-12-14 11:18

I have a WCF Service with wsHttpBindings and SSL enabled, but I\'d like to enable WCF sessions.

After changing SessionMode to required

SessionMode:         


        
相关标签:
3条回答
  • 2020-12-14 12:04

    If you want "sessions" with wsHttpBinding, you have to use either reliable messaging, or the security sessions. (source : how to enable WCF Session with wsHttpBidning with Transport only Security).

    WSHttpBinding supports session but only if either security (SecureConversation) or reliable messaging are enabled. If you are using transport security then it is not using WS-SecureConversation and WS-ReliableMessaging is turned off by default. Therefore the two protocols that WSHttpBinding uses for session are not available. You either need to use message security or turn on reliable session. (source : http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/57b3453e-e7e8-4875-ba23-3be4fff080ea/).

    We’ve disallowed RM over Https in the standard bindings because the way to secure an RM session is to use a security session and Https does not provide session.

    I found the msdn blurb about it here: http://msdn2.microsoft.com/en-us/library/ms733136.aspx The blurb is “The only exception is when using HTTPS. The SSL session is not bound to the reliable session. This imposes a threat because sessions sharing a security context (the SSL session) are not protected from each other; this might or might not be a real threat depending on the application.”

    However you can do it if you determine there is no threat. There is an RM over HTTPS sample via custom binding http://msdn2.microsoft.com/en-us/library/ms735116.aspx (source : http://social.msdn.microsoft.com/forums/en-US/wcf/thread/fb4e5e31-e9b0-4c24-856d-1c464bd0039c/).

    To sum up your possibilities you can either :

    1 - Keep wsHttpBinding, remove transport security and enable reliable messaging

      <wsHttpBinding>
        <binding name="bindingConfig">
          <reliableSession enabled="true" />
          <security mode="None"/>
        </binding>
      </wsHttpBinding>
    

    But you loose the SSL layer and then part of your security.

    2 - Keep wsHttpBinding, keep transport security and add message authentication

      <wsHttpBinding>
        <binding name="bindingConfig">
          <security mode="TransportWithMessageCredential">
            <message clientCredentialType="UserName"/>
          </security>
        </binding>
      </wsHttpBinding>
    

    You get to keep your SSL security layer but your client will have to provide credentials (of any form) and even if you don't validate them at the service side, fake ones must still be provided as WCF will reject any message not specifying credentials.

    3 - Use a custom binding with reliable messaging and HTTPS transport

      <customBinding>
        <binding name="bindingConfig">
          <reliableSession/>
          <httpsTransport/>
        </binding>
      </customBinding>
    

    I can't see any downside to this except the threat explained in MSDN, and it depends on your application.

    4 - Use other session providers If your application is hotsed in IIS, you could set

    <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
    

    and depend on the

    HttpContext.Current.Session
    

    for your state.

    Or implementing your own cookies.

    PS : Note that for all those WCF configuration, I only tested service activation, not calls.

    EDIT : As per user request, wsHttpBinding with TransportWithMessageCredential security mode implementing sessions (I'm not too familiar with VB.NET so pardon my syntax) :

    Service code snippet :

    <ServiceContract(SessionMode:=SessionMode.Required)>
    Public Interface IService1
    
        <OperationContract()> _
        Sub SetSessionValue(ByVal value As Integer)
    
        <OperationContract()> _
        Function GetSessionValue() As Nullable(Of Integer)
    
    End Interface
    
    <ServiceBehavior(InstanceContextMode:=InstanceContextMode.PerSession, 
        ConcurrencyMode:=ConcurrencyMode.Single)>
    Public Class Service1
        Implements IService1
    
        Private _sessionValue As Nullable(Of Integer)
    
        Public Sub SetSessionValue(ByVal value As Integer) Implements IService1.SetSessionValue
            _sessionValue = value
        End Sub
    
        Public Function GetSessionValue() As Nullable(Of Integer) Implements IService1.GetSessionValue
            Return _sessionValue
        End Function
    End Class
    
    Public Class MyUserNamePasswordValidator
        Inherits System.IdentityModel.Selectors.UserNamePasswordValidator
    
        Public Overrides Sub Validate(userName As String, password As String)
            ' Credential validation logic
            Return ' Accept anything
        End Sub
    
    End Class
    

    service Configuration snippet :

    <system.serviceModel>
      <services>
        <service name="WcfService1.Service1" behaviorConfiguration="WcfService1.Service1Behavior">
          <endpoint address="" binding="wsHttpBinding" contract="WcfService1.IService1" bindingConfiguration="bindingConf"/>
          <endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange"/>
        </service>
      </services>
      <bindings>
        <wsHttpBinding>
          <binding name="bindingConf">
            <security mode="TransportWithMessageCredential">
              <message clientCredentialType="UserName"/>
            </security>
          </binding>
        </wsHttpBinding>
      </bindings>
      <behaviors>
        <serviceBehaviors>
          <behavior name="WcfService1.Service1Behavior">
            <serviceMetadata httpsGetEnabled="true"/>
            <serviceDebug includeExceptionDetailInFaults="false"/>
            <serviceCredentials>
              <userNameAuthentication 
                userNamePasswordValidationMode="Custom"
                customUserNamePasswordValidatorType="WcfService1.MyUserNamePasswordValidator, WcfService1"/>
            </serviceCredentials>
          </behavior>
        </serviceBehaviors>
      </behaviors>
    </system.serviceModel>
    

    Client test code snippet :

    Imports System.Threading.Tasks
    
    Module Module1
    
        Sub Main()
            Parallel.For(0, 10, Sub(i) Test(i))
            Console.ReadLine()
        End Sub
    
        Sub Test(ByVal i As Integer)
            Dim client As ServiceReference1.Service1Client
            client = New ServiceReference1.Service1Client()
            client.ClientCredentials.UserName.UserName = "login"
            client.ClientCredentials.UserName.Password = "password"
            Console.WriteLine("Session N° {0} : Value set to {0}", i)
            client.SetSessionValue(i)
            Dim response As Nullable(Of Integer)
            response = client.GetSessionValue()
            Console.WriteLine("Session N° {0} : Value returned : {0}", response)
            client.Close()
        End Sub
    
    End Module
    
    0 讨论(0)
  • 2020-12-14 12:08

    By default, WSHttpBinding only allows security sessions. It is a concept of WCF and is not linked to Transport. A security session is not a session over https, but a session with mutual authentication. This is achieved by adding message security.

    Based upon your service, you should apply this config

     <bindings>
          <wsHttpBinding>
            <binding name="wsHttpBindingConfig">
              <security mode="TransportWithMessageCredential">
                <!-- configure transport & message security here if needed-->
              </security>
            </binding>
          </wsHttpBinding>
        </bindings>
    

    On clientside, here is a simple unit test

    [TestMethod]
        public void TestSecuritySession()
        {
            //remove this is certificate is valid
            ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback((sender, certificate, chain, sslPolicyErrors) => { return true; });
    
            var binding = new WSHttpBinding();
            binding.Security = new WSHttpSecurity() { Mode = SecurityMode.TransportWithMessageCredential};
            ChannelFactory<ITestService> Factory = new ChannelFactory<ITestService>(binding, new EndpointAddress("https://localhost/TestService.svc"));
    
            Factory.Open();
            var channel = Factory.CreateChannel();
    
            //call service here
    
            (channel as IClientChannel).Close();
    
            Factory.Close();
        }
    
    0 讨论(0)
  • 2020-12-14 12:10

    wsHttpBinding requires reliableSession to support WCF sessions, and reliable sessions require custom binding to support ssl. So asking for WCF sessions over ssl and with wsHttpBinding seems like out of the question as far as I can tell.

    0 讨论(0)
提交回复
热议问题