Разграничение доступа из кода в WCF - Требования клиента

ОГЛАВЛЕНИЕ

Требования клиента

Увы, прием, показанный на рис. 1, представляет собой потенциальную брешь в защите. Любой частично доверенный клиент теперь может вызвать службу WCF, подавляя требования безопасности WCF. Представьте себе клиента, которому не было дано полномочий на подключение к сокету TCP или веб-узлу. Хотя этот клиент и не может использовать сеть напрямую, он может обойти это ограничение, делая вызов из ограниченной клиентской среды через WCF.

Решение для этой проблемы – использование специального подкласса ClientBase<T>, который, с одной стороны, установит чистое требование полного доверия от WCF и, с другой стороны, потребует определенных полномочий безопасности в соответствии с тем, что пытается сделать клиент. Таким классом прокси является мой класс PartialTrustClientBase<T>, показанный на рис. 2.

Рис. 2 Класс PartialTrustClientBase<T>

public abstract class PartialTrustClientBase<T> : 
  ClientBase<T>,IDisposable 
  where T : class
{
  [PermissionSet(SecurityAction.Assert,Name = "FullTrust")]
  public PartialTrustClientBase() {}

 

  [PermissionSet(SecurityAction.Assert,Name = "FullTrust")]
  public PartialTrustClientBase(string endpointName) : 
   base(endpointName) {}

  [PermissionSet(SecurityAction.Assert,Name = "FullTrust")]
  public PartialTrustClientBase(Binding binding,
   EndpointAddress remoteAddress) : 
   base(binding,remoteAddress) {}

  //Useful only for clients that want full-brunt raw demands from WCF
  protected new T Channel
  {
   [PermissionSet(SecurityAction.Assert,Name = "FullTrust")]
   get {
    return base.Channel;
   }
  }
  
  [PermissionSet(SecurityAction.Assert,Name = "FullTrust")]
  new public void Close() {
   base.Close();
  }
  void IDisposable.Dispose() {
   Close();
  }

  protected object Invoke(string operation,params object[] args) {
   if(IsAsyncCall(operation)) {
    DemandAsyncPermissions();
   }
   DemandSyncPermissions(operation);
   CodeAccessSecurityHelper.PermissionSetFromStandardSet(
    StandardPermissionSet.FullTrust).Assert();

   Type contract = typeof(T);
   MethodInfo methodInfo = contract.GetMethod(operation);
   return methodInfo.Invoke(Channel,args);
  }

  protected virtual void DemandAsyncPermissions() {
   CodeAccessSecurityHelper.DemandAsyncPermissions();
  }

  protected virtual void DemandSyncPermissions(string operationName) {
   this.DemandClientPermissions(operation);
  }

  bool IsAsyncCall(string operation) {
   if(operation.StartsWith("Begin")) {
    MethodInfo info = typeof(T).GetMethod(operation);
    object[] attributes = info.GetCustomAttributes(
     typeof(OperationContractAttribute),false);
    Debug.Assert(attributes.Length == 1);
    return (attributes[0] as 
     OperationContractAttribute).AsyncPattern;
   }
   return false;
  }
}

PartialTrustClientBase<T> используется подобно обычному базовому классу прокси. Его производному классу прокси тоже необходимо дать полное доверие и разрешить источники вызова с частичным доверием. Однако, в отличие от показанного на рис. 1, PartialTrustClientBase<T> не утверждает полное доверие на уровне класса. Вместо этого он утверждает полное доверие локально, лишь когда это требуется. Вдобавок, PartialTrustClientBase<T> также может быть использован, чтобы требовать другие полномочия CAS.

Если произвести класс прокси PartialTrustClientBase<T> и заставить прокси установить полное доверие, как показано здесь, вызывающему клиенту не будет предъявляться требований:

[PermissionSet(SecurityAction.Assert,Name = "FullTrust")]
public class MyContractClient : 
  PartialTrustClientBase<IMyContract>,IMyContract
{
  public MyContractClient() {}

 

  public MyContractClient(string endpointName) : 
   base(endpointName) {}

  public void MyMethod() {
   Channel.MyMethod();
  }
}

Единственная разница между этим кодом и рис. 1 заключается в том, что новая версия чище, поскольку сокрытие Close и Dispose теперь выполняется PartialTrustClientBase<T>. Этот новый прокси по-прежнему подавляет все требования безопасности от WCF и оставляет частично доверенного клиента открытым для атаки с приманкой или позволяет ему делать больше, чем положено.