Protegendo serviço WCF usando basicHttpBinding que suporta streaming de
-
21-08-2019 - |
Pergunta
A minha pergunta é em relação ao melhor (aka "menos dolorosa") caminho para o acesso seguro para um serviço WCF que só é exposto a usuários internos da nossa empresa. O objetivo é garantir que o serviço só é acessado através de uma única aplicação Windows Forms que cada um de nossos usuários tem instalado. Quando o serviço é chamado, eu quero o serviço a ser capaz de validar que foi chamado a partir da aplicação permitida.
O serviço a ser protegido usos BasicHttpBinding, que suporta streaming, então eu acredito que estou limitado a segurança em nível de transporte.
versões Abaixo estão simplificadas das seções <bindings>
e <services>
de arquivo de configuração do meu serviço.
<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>
Alguém pode oferecer alguns detalhes quanto ao que ações que eu precisaria para tomar a fim de implementar a segurança neste serviço?
Nota:. Eu sou novo para o WCF e não estou familiarizado com a segurança em tudo, então deixe-me saber se eu não forneceram detalhes suficientes
UPDATE:
Como sugerido por marc_s , Eu gostaria de proteger o serviço WCF usando algum tipo de mecanismo de nome de usuário / senha. Isto dá um pouco de direção mais para uma resposta, mas eu ainda estou um pouco desfocadas no como para realmente fazer isso.
Porque o meu serviço requer streaming para ser habilitado, eu tenho que usar a segurança em nível basicHttpBinding e Transportes (certo?); Para além disso, o método referido no meu serviço só pode aceitar um objeto Stream.
Tomar essas restrições em consideração juntamente com a minha preferência para usar nome de usuário / senha de validação ...
- Como devo modificar o arquivo de configuração do meu serviço para forçar as credenciais de usuário / senha a ser fornecida?
- Como o meu serviço de validar as credenciais fornecidas?
- Como os meus aplicativo cliente credenciais passa o serviço ao fazer uma chamada?
- Será que este exigir o uso de SSL e, se assim for, vai todas as máquinas clientes exigem um certificado bem?
UPDATE:
Depois de explicar o problema que eu tenho tido com a segurança este serviço para meu chefe, me foi dado o sinal verde para tentar a rota de autenticação do Windows. Infelizmente, eu não teve sorte na implementação deste tipo de autenticação com o meu serviço Streamed (argh). Depois de fazer as alterações apropriadas (conforme descrito aqui - o único ser excepção que o meu transferMode="Streamed"
) e acessar o meu serviço, eu foi apresentado com o seguinte erro:
solicitação HTTP streaming não pode ser usado em conjunto com a autenticação HTTP. Desabilite pedido de streaming ou especificar a autenticação HTTP anônima.
Então eu tropecei em cima da seguinte citação aqui que oferece alguns esclarecimentos:
Você não pode fazê-auth transporte. com fluência. Se você tem que usar HTTP pedido de streaming, você vai ter que correr sem segurança.
O modo de segurança funciona é:
WCF cliente faz uma solicitação HTTP para o servidor.
Os responde Server com algo dizendo: "Você não está autorizado, envia-me um básico / digest / etc credencial."
O cliente recebe essa resposta e reenvia a mensagem com as credenciais embutido.
Agora, o servidor recebe a mensagem, verifica as credenciais, e continua. Pedido ao vivo não está concebido para trabalhar com esse padrão de segurança. Se o fizesse, seria muito lento, uma vez que o cliente iria enviar todo o fluxo, obter a mensagem do servidor que não foi autorizado, em seguida, ele teria que reenviar todo o fluxo com credenciais.
Então agora eu estou procurando opiniões, como você garantir o seu serviço WCF streaming de habilitado? Como mencionado anteriormente, uma espécie de nome de usuário / senha mecanismo seria preferível. Sinta-se livre para pensar fora da caixa em um presente ...
Qualquer ajuda é muito apreciada!
Solução
Bem, eu encontrei um monte de questões que envolvem a segurança / streaming ao trabalhar sobre este problema. O hack (er ... hum ... solução temporária) eu finalmente acabei indo com foi a de criar um novo DataContract que herda MemoryStream e decorado com uma propriedade BaseStream (para prender os dados que eu quero streaming), juntamente com propriedades adequadas utilizadas para autenticação simples.
Aqui está o DataContract resultante:
[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; }
}
O acima DataContract acaba sendo o parâmetro de entrada do método de meu serviço. A primeira ação meu serviço toma é para autenticar as credenciais fornecidas contra valores válidos conhecidos e continuar conforme o caso.
Agora eu faço sabe que este é não a opção mais segura, mas o meu directiva era evitar o uso de SSL ( que eu não estou mesmo certo é possível de qualquer maneira - como afirmou aqui ) para este processo interno.
Dito isto, esta foi a melhor solução para o problema indicado acima eu poderia vir acima com, espero que isso ajude alguém aflito com esta questão.
Obrigado a todos que responderam.
Outras dicas
Há uma série de coisas que você poderia fazer:
- adicionar um certificado para cada máquina que está autorizado a usar o seu serviço, e verificar se há esse certificado. Que só permite a exclusão de máquinas "não autorizadas" - você não pode limitá-lo a uma aplicação específica
- mesmo que acima, mas incluem o certificado incorporado em seu winforms aplicativo e enviá-lo de lá (não armazená-lo no armazenamento de certificados da máquina)
- exigir um nome de usuário / senha que somente esse aplicativo específico de vocês conhece e pode transmitir ao seu serviço; por exemplo. outra pessoa não seria capaz de apresentar as credenciais adequadas
EDIT 2: OK, então a abordagem nome de usuário / senha parece sair da mão .... E se você só tem a segurança de transporte básico (SSL) para a proteção básica, e depois usar o MessageContract
para definir cabeçalho e corpo de sua mensagem SOAP, incluem um valor específico no cabeçalho, e em seguida, basta verificar que a presença do elemento no cabeçalho no seu serviço?
Algo assim:
[DataContract]
class YourRequestData
{
...
}
[MessageContract]
public class YourRequest
{
[MessageBodyMember]
public YourRequestData bodyData { get; set; }
[MessageHeader]
public string AppThumbprint { get; set; }
}
E, em seguida, em seu servidor em seu código apenas verificar a presença e a validade desse código AppThumbprint
:
public Stream RequestStream(YourRequest request)
{
if(AppThumbprintIsValid(request.AppThumbprint))
{
.... begin your streaming
}
}
Isso pode acabar sendo muito mais fácil do que o cenário de segurança nome de usuário / senha.
Marc
Por favor me corrija se eu estiver errado, mas:
Se você estiver usando autenticação de formulários para o seu serviço WCF (em asp.net), basta adicionar um método de login para o seu serviço, em que você cria o cookie necessário (formsAuthentication.Authenticate ()). que é automaticamente enviada com a resposta, o cliente pode então chamar o API fluxo sem precisar parâmetros extras (um requisito para que seja STREAM) e você pode verificar a identidade na API de streaming antes de disparar o fluxo de retorno.
Como para garantir o acesso a todo o WCF, fico com a sensação de que a incorporação de um certificado no aplicativo .net é um caminho a percorrer. eles teriam que ildump seu aplicativo para chegar a ele.
você pode dizer asp.net/wcf não fornecer o WSDL, ou mais precisamente, para não gerar automaticamente o WSDL. Sem acesso wsdl ele fica muito mais difícil para eles para gerar um proxy ....
Se você quiser usar basicHttpBinding
(para interoperabilidade), você só pode passar a sua credencial no nível de mensagem. Você tem que definir sua configuração de segurança para TransportWithMessageCredential
.
Para fazer isso você tem que criar um canal SSL, então você precisa de um certificado no lado do servidor, e não é necesary para a cliente para ter um.
É possível utilizar a autenticação do Windows com Streaming e SSL, mas você deve usar 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>
Você precisa definir em proxy.ClientCredentials.UserName.UserName
código e proxy.ClientCredentials.UserName.Password
.
Se isso vai ser um aplicativo que vidas na intranet, pode ser mais fácil simplesmente criar um novo grupo no Active Directory e só dar membros desse grupo a capacidade de usar o serviço.
Você pode adicionar autenticação (usando credenciais do Windows) com algo como isto:
<basicHttpBinding>
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
</basicHttpBinding>
poderia, então, autorizar, através de decorar a interface para seus métodos de serviços:
<PrincipalPermission(SecurityAction.Demand, Role:="MyAppsUsers")> _
Public Function MyMethod() As String Implements IService.MyMethod
Aqui está um bom link para Segurança no WCF. Tem muita Como de no final (aquele intitulado 'How To - Use basicHttpBinding com Autenticação e TransportCreditals do Windows' pode ser de utilidade para você).
Wcf Secruity
[Disclaimer: Eu também sou novo para o WCF e não ter feito neste caso exato antes, então desculpas se isso é um pouco fora]