Sécurisation du service WCF à l'aide de basicHttpBinding qui prend en charge la diffusion en continu

StackOverflow https://stackoverflow.com/questions/845423

  •  21-08-2019
  •  | 
  •  

Question

Ma question concerne le meilleur moyen (également appelé & "le moins pénible &") de sécuriser l'accès à un service WCF uniquement accessible aux utilisateurs internes de notre société. L'objectif est de s'assurer que le service est uniquement accessible via une seule application Windows Form installée par chacun de nos utilisateurs. Lorsque le service est appelé, je souhaite que le service puisse valider qu'il a été appelé à partir de l'application autorisée.

Le service à sécuriser utilise basicHttpBinding, qui prend en charge la diffusion en continu. Je suis donc limité à la sécurité au niveau du transport.

Vous trouverez ci-dessous des versions simplifiées des sections <bindings> et <services> du fichier de configuration de mon service.

<bindings>
  <basicHttpBinding>
    <binding name="Service1Binding" transferMode="Streamed"/>    
  </basicHttpBinding>
</bindings>

<services>
    <service name="WCFServiceSecurity.Service1" 
        behaviorConfiguration="WCFServiceSecurity.Service1Behavior">
        <endpoint address=""
            binding="basicHttpBinding"
            contract="WCFServiceSecurity.IService1"
            bindingConfiguration="Service1Binding"/>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
    </service>
</services>

Quelqu'un peut-il donner des détails sur les actions que je devrais entreprendre afin de mettre en œuvre la sécurité sur ce service?

Remarque: je suis nouveau à la WCF et ne connais pas du tout la sécurité, alors faites-le moi savoir si je n'ai pas fourni suffisamment de détails.

UPDATE:

As suggéré par marc_s , J'aimerais sécuriser le service WCF en utilisant une sorte de mécanisme de nom d'utilisateur / mot de passe. Cela donne un peu plus de direction vers une réponse, mais je suis toujours un peu flou sur comment faire cela.

Étant donné que mon service nécessite l'activation de la diffusion en continu, je dois utiliser basicHttpBinding et la sécurité de niveau transport (non?); de plus, la méthode contenue dans mon service ne peut accepter qu'un objet Stream.

Tenant compte de ces contraintes et de ma préférence pour la validation du nom d'utilisateur / mot de passe ...

  • Comment dois-je modifier le fichier de configuration de mon service pour forcer la fourniture des informations d'identification de nom d'utilisateur / mot de passe?
  • Comment mon service va-t-il valider les informations d'identification fournies?
  • Comment mon application client transmettra-t-elle les informations d'identification au service lors d'un appel?
  • Cela nécessitera-t-il l'utilisation de SSL et, le cas échéant, tous les ordinateurs clients auront également besoin d'un certificat?

UPDATE:

Après avoir expliqué les difficultés que je rencontrais avec la sécurisation de ce service pour mon patron, on m'a donné le feu vert pour essayer la voie de l'authentification Windows. Malheureusement, je n'ai pas eu la chance de mettre en œuvre ce type d'authentification avec mon service Streamed (argh). Après avoir apporté les modifications appropriées (comme indiqué ici , la seule exception étant que mon transferMode="Streamed") et l’accès à mon service, l’erreur suivante m'a été présentée:

  

La diffusion en continu des demandes HTTP ne peut pas être utilisée avec l'authentification HTTP. Désactivez le streaming des demandes ou spécifiez une authentification HTTP anonyme.

Je suis ensuite tombé sur la citation suivante ici qui offre des éclaircissements:

  

Vous ne pouvez pas effectuer d'authentification de transport. avec diffusion en continu. Si vous devez utiliser la transmission en continu des requêtes HTTP, vous devrez exécuter le programme sans sécurité.

     

La sécurité fonctionne comme suit:

     

Le client WCF envoie une requête http au serveur.

     

Le serveur répond par un message disant: & "Vous n'êtes pas autorisé, envoyez-moi un identifiant de base / digest / etc. &";

     

Le client reçoit cette réponse et renvoie son message avec les informations d'identification ajoutées.

     

Maintenant, le serveur reçoit le message, vérifie les informations d'identification et continue.   Request Streaming n'est pas conçu pour fonctionner avec ce modèle de sécurité. Si c'était le cas, ce serait très lent, car le client enverrait l'intégralité du flux, recevrait du serveur le message qu'il n'était pas autorisé, puis il lui faudrait renvoyer l'intégralité du flux avec des informations d'identification.

Alors maintenant je cherche un aviss, comment sécuriseriez-vous votre service WCF compatible avec la diffusion en continu? Comme indiqué précédemment, un mécanisme de type nom d'utilisateur / mot de passe serait préférable. N'hésitez pas à sortir des sentiers battus avec celui-ci ...

Toute aide est grandement appréciée!

Était-ce utile?

La solution

Eh bien, j'ai constaté beaucoup de problèmes liés à la sécurité / diffusion en continu tout en travaillant sur ce problème. Le hack (euh ... euh ... solution de contournement) que j’ai finalement choisi est de créer un nouveau DataContract qui hérite de MemoryStream et l’a décoré avec une propriété BaseStream (pour conserver les données que je veux diffuser en streaming) avec les propriétés appropriées utilisées pour authentification simple.

Voici le DataContract résultant:

[DataContract]
[KnownType( typeof( MemoryStream ) )] 
public class StreamWithCredentials : MemoryStream
{
    [DataMember]
    public Stream BaseStream { get; set; }

    [DataMember]
    public string Username { get; set; }

    [DataMember]
    public string Password { get; set; }
}

Le DataContract ci-dessus finit par être le paramètre d'entrée de la méthode de mon service. La première action entreprise par mon service consiste à authentifier les informations d'identification fournies par rapport à des valeurs valides connues et à poursuivre le cas échéant.

Maintenant, je sais que ce n'est pas l'option la plus sûre, mais ma directive était d'éviter l'utilisation de SSL ( dont je ne suis même pas sûr que ce soit possible en tout cas, comme indiqué ici ) pour ce processus interne.

Cela étant dit, c’était la meilleure solution au problème mentionné ci-dessus que je pouvais trouver, espérons que cela aidera toute autre personne touchée par ce problème.

Merci à tous ceux qui ont répondu.

Autres conseils

There's a number of things you could do:

  • add a certificate to each and every machine that's allowed to use your service, and check for that certificate. That only allows you to exclude "unauthorized" machines - you cannot limit it to a specific application
  • same as above, but include the certificate embedded in your winforms app and send it from there (do not store it in the machine's certificate store)
  • require a username / password that only that particular app of yours knows about and can transmit to your service; e.g. someone else would not be able to present the appropriate credentials

EDIT 2: OK, so the username/password approach seems to get out of hand.... what if you just have basic transport security (SSL) for basic protection, and then use the MessageContract to define header and body of your SOAP message, include a specific value in the header, and then just check for that presence of the element in the header in your service?

Something like that:

[DataContract]
class YourRequestData
{
 ...
}

[MessageContract]
public class YourRequest
{
  [MessageBodyMember]
  public YourRequestData bodyData { get; set; }

  [MessageHeader]
  public string AppThumbprint { get; set; }
}

And then on your server in your code just check for the presence and the validity of that AppThumbprint code:

public Stream RequestStream(YourRequest request)
{
  if(AppThumbprintIsValid(request.AppThumbprint))
  {
     .... begin your streaming
  }
}

That might end up being a lot easier than the username/password security scenario.

Marc

Please correct me if I am wrong, but:

if you are using forms authentication for your WCf service (on asp.net), just add a login method to your service, in it you create the required cookie (formsAuthentication.Authenticate()). which is automatically sent with the response, the client can then call the stream API without needing extra parameters (a requirement for it to be STREAM) and you can check the identity in the streaming api before you fire off the returning stream.

As for securing access to the whole WCF, I get the feeling that embedding a certificate in the .net app is one way to go. they would have to ildump your app to get at it.

you can tell asp.net/wcf not to provide the wsdl, or more accurately, to not automatically generate the wsdl. Without wsdl access it gets much harder for them to generate a proxy....

If you want to use basicHttpBinding (for interop) you can only pass your credential at the message level. You have to set your security configuration to TransportWithMessageCredential.

To do that you have to create a SSL channel, so you need a certificate at server side, and it's not necesary for a cliente to have one.

It is possible to use Windows authentication with Streaming and SSL, but you must use TransportWithMessageCredential:

<basicHttpBinding>
    <binding name="FileService.FileServiceBinding" maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" transferMode="Streamed">
        <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
        <security mode="TransportWithMessageCredential">
            <transport clientCredentialType="Windows" />
        </security>
    </binding>
</basicHttpBinding>

You need to set in code proxy.ClientCredentials.UserName.UserName and proxy.ClientCredentials.UserName.Password.

If this is going to be an application that lives on the intranet it might be easiest to just create a new group in your Active Directory and only give members of that group the ability to use the service.

You can add Authentication (using windows credentials) with something like this:

<basicHttpBinding> 
 <security mode="TransportCredentialOnly"> 
  <transport clientCredentialType="Windows" /> 
 </security> 
</basicHttpBinding> 

Could then Authorise by decorating the Interface to your services methods:

<PrincipalPermission(SecurityAction.Demand, Role:="MyAppsUsers")> _ 
Public Function MyMethod() As String Implements IService.MyMethod 

Heres a good link to Security in WCF. It has lots of How To's at the end (the one titled 'How To - Use basicHttpBinding with Windows Authentication and TransportCreditals' might be of use to you).
Wcf Secruity

[Disclaimer: I'm also new to WCF and haven’t done this exact case before so apologises if this is slightly off!]

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top