Разграничение доступа из кода в 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 и оставляет частично доверенного клиента открытым для атаки с приманкой или позволяет ему делать больше, чем положено.