Защита службы WCF с использованием basicHttpBinding, которая поддерживает потоковую передачу - PullRequest
12 голосов
/ 10 мая 2009

Мой вопрос касается лучшего (иначе называемого «наименее болезненного») способа обеспечения доступа к службе WCF, доступной только внутренним пользователям нашей компании. Цель состоит в том, чтобы обеспечить доступ к службе только через одно приложение форм Windows, которое установил каждый из наших пользователей. Когда служба вызывается, я хочу, чтобы служба могла проверить, вызвана ли она из разрешенного приложения.

Защищаемый сервис использует basicHttpBinding, который поддерживает потоковую передачу, поэтому я считаю, что я ограничен безопасностью транспортного уровня.

Ниже приведены упрощенные версии разделов <bindings> и <services> из файла конфигурации моей службы.

<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>

Может ли кто-нибудь предложить некоторые подробности относительно того, какие действия мне необходимо предпринять для обеспечения безопасности в этой службе?

Примечание: я новичок в WCF и совсем не знаком с безопасностью, поэтому дайте мне знать, если я не предоставил достаточно подробностей.


UPDATE:

Как и , предложенный marc_s , я бы хотел защитить службу WCF, используя какой-то механизм имени пользователя / пароля. Это дает немного больше направления к ответу, но я все еще немного размыт на , как фактически сделать это.

Поскольку мой сервис требует, чтобы потоковая передача была включена, я должен использовать basicHttpBinding и безопасность транспортного уровня (верно?); Кроме того, метод, содержащийся в моем сервисе, может принимать только объект Stream.

С учетом этих ограничений и моего предпочтения использовать проверку имени пользователя / пароля ...

  • Как мне изменить конфигурационный файл моей службы так, чтобы вводить учетные данные для имени пользователя / пароля?
  • Как мой сервис проверит предоставленные учетные данные?
  • Как мое клиентское приложение будет передавать учетные данные службе при совершении вызова?
  • Требуется ли для этого использование SSL, и если да, то все ли клиентские машины также требуют сертификат?

UPDATE:

После объяснения проблемы, с которой я столкнулся при обеспечении этой службы своему боссу, мне дали разрешение попробовать маршрут аутентификации Windows. К сожалению, мне не повезло в реализации этого типа аутентификации с моей службой Streamed (argh) После внесения соответствующих изменений (как указано здесь - единственное исключение, что мой transferMode="Streamed") и доступа к моему сервису, я получил следующую ошибку:

Потоковая передача HTTP-запроса не может использоваться в сочетании с аутентификацией HTTP. Отключите потоковую передачу запросов или укажите анонимную HTTP-аутентификацию.

Затем я наткнулся на следующую цитату здесь , которая предлагает некоторые пояснения:

Вы не можете выполнять авторизацию транспорта. с потоковой передачей. Если вам нужно использовать потоковую передачу HTTP-запросов, вам придется работать без защиты.

Как работает система безопасности:

Клиент WCF отправляет http-запрос на сервер.

Сервер отвечает что-то вроде: «Вы не авторизованы, пришлите мне базовые / digest / etc учетные данные».

Клиент получает этот ответ и повторно отправляет свое сообщение с прикрепленными учетными данными.

Теперь Сервер получает сообщение, проверяет учетные данные и продолжает работу. Поток запросов не предназначен для работы с этим шаблоном безопасности. Если это произойдет, это будет очень медленно, так как Клиент отправит весь поток, получит сообщение с Сервера, что он не авторизован, тогда ему придется повторно отправить весь поток с учетными данными.

Так что теперь я ищу мнения, как бы вы защитили службу WCF с поддержкой потоковой передачи? Как упоминалось ранее, предпочтительнее использовать какой-либо механизм имени пользователя / пароля. Не стесняйтесь мыслить нестандартно на этом ...

Любая помощь очень приветствуется!

Ответы [ 6 ]

6 голосов
/ 12 мая 2009

Ну, я обнаружил много проблем, связанных с безопасностью / потоковой передачей, работая над этой проблемой. Хак (эээ ... гм ... обходной путь), который я в итоге закончил, заключался в создании нового DataContract, который наследует MemoryStream, и украшении его свойством BaseStream (для хранения данных, которые я хочу передавать) вместе с соответствующими свойствами, используемыми простая аутентификация.

Вот результирующий DataContract:

[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; }
}

Приведенный выше DataContract в конечном итоге является входным параметром метода моей службы. Первым действием, которое выполняет моя служба, является проверка подлинности предоставленных учетных данных по известным действительным значениям и продолжение в случае необходимости.

Теперь я знаю , что это , а не самый безопасный вариант, но моя директива состояла в том, чтобы избегать использования SSL (, который я даже не уверен, что это возможно в любом случае как указано здесь ) для этого внутреннего процесса.

При этом, это было лучшее решение вышеупомянутой проблемы, которую я мог придумать, надеюсь, это поможет кому-то еще пораженному этой проблемой.

Спасибо всем, кто откликнулся.

1 голос
/ 04 октября 2011

Можно использовать проверку подлинности Windows с потоковой передачей и SSL, но вы должны использовать 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>

Вам необходимо установить код proxy.ClientCredentials.UserName.UserName и proxy.ClientCredentials.UserName.Password.

1 голос
/ 30 января 2011

Пожалуйста, поправьте меня, если я ошибаюсь, но:

если вы используете проверку подлинности с помощью форм для своей службы WCf (на asp.net), просто добавьте метод входа в свою службу, в котором вы создадите требуемый файл cookie (formsAuthentication.Authenticate ()). который автоматически отправляется с ответом, клиент может затем вызвать потоковый API, не требуя дополнительных параметров (требование должно быть STREAM), и вы можете проверить идентичность в потоковом API, прежде чем запустить обратный поток.

Что касается защиты доступа ко всему WCF, у меня возникает ощущение, что встраивание сертификата в приложение .net - это один из способов. им придется использовать ваше приложение, чтобы получить к нему доступ.

вы можете указать asp.net/wcf не предоставлять wsdl или, точнее, не генерировать wsdl автоматически. Без доступа wsdl им становится намного сложнее создать прокси ....

1 голос
/ 06 июля 2010

Если вы хотите использовать basicHttpBinding (для взаимодействия), вы можете передать свои учетные данные только на уровне сообщения. Вы должны установить конфигурацию безопасности на TransportWithMessageCredential.

Для этого вам нужно создать канал SSL, поэтому вам нужен сертификат на стороне сервера, и клиенту не обязательно иметь его.

1 голос
/ 10 мая 2009

Есть несколько вещей, которые вы можете сделать:

  • добавьте сертификат на каждую машину, которой разрешено использовать вашу службу, и проверьте этот сертификат. Это позволяет вам исключать «неавторизованные» машины - вы не можете ограничить это определенным приложением
  • тоже самое, что и выше, но включите сертификат, встроенный в ваше приложение winforms, и отправьте его оттуда (не храните его в хранилище сертификатов машины)
  • требуется имя пользователя / пароль, о которых знает только ваше конкретное приложение и которое может передать их вашему сервису; например кто-то другой не сможет предоставить соответствующие полномочия

РЕДАКТИРОВАТЬ 2: ОК, поэтому подход с использованием имени пользователя и пароля выходит из-под контроля .... что если у вас есть базовая безопасность транспорта (SSL) для базовой защиты, а затем используйте MessageContract для определения заголовка и тело вашего сообщения SOAP, включить определенное значение в заголовок, а затем просто проверить наличие этого элемента в заголовке в вашем сервисе?

Что-то в этом роде:

[DataContract]
class YourRequestData
{
 ...
}

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

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

А затем на вашем сервере в вашем коде просто проверьте наличие и действительность этого AppThumbprint кода:

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

Это может оказаться намного проще, чем сценарий безопасности имени пользователя / пароля.

Марк

0 голосов
/ 10 мая 2009

Если это будет приложение, которое живет в интрасети, возможно, будет проще всего создать новую группу в Active Directory и дать членам этой группы возможность пользоваться службой.

Вы можете добавить Аутентификацию (используя учетные данные Windows) примерно так:

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

Затем можно авторизоваться, украшая интерфейс для ваших методов обслуживания:

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

Вот хорошая ссылка на безопасность в WCF. В конце у него много практических рекомендаций (вам может пригодиться один из них под названием «Как использовать basicHttpBinding с аутентификацией Windows и TransportCreditals»).
Wcf Secruity

[Отказ от ответственности: я также новичок в WCF и не делал этого точного случая прежде, поэтому извиняюсь, если это не так!]

...