내가 할 수있는 요구 사항이 A가 WIF를 사용하여 WCF net.tcp 서비스 엔드 포인트를 스트리밍 보안을 . 토큰 서버에 대한 수신 전화를 인증해야합니다. 서비스는 많은 양의 데이터를 전송하도록 설계되었으므로 스트리밍됩니다.
불가능한 것 같습니다. 그리고 내가 잡을 수 없다면 크리스마스가 망가질 것이고 메리 쇼핑객들이 천천히 차가워지는 몸을 넘어가는 동안 홈통에서 죽을 것입니다. 진지한 토트.
왜 이것이 불가능합니까? 여기 캐치 -22가 있습니다.
클라이언트에서는 토큰 서버에서 얻은 GenericXmlSecurityToken 으로 채널을 만들어야 합니다. 문제 없습니다.
// people around here hate the Framework Design Guidelines.
var token = Authentication.Current._Token;
var service = base.ChannelFactory.CreateChannelWithIssuedToken(token);
return service.Derp();
“문제 없음”이라고 했습니까? 문제. 사실, NullReferenceException
스타일 문제.
“브로,”나는 프레임 워크에 물었다. “널 체크도하지?” 프레임 워크는 침묵했기 때문에 분해하고
((IChannel)(object)tChannel).
GetProperty<ChannelParameterCollection>().
Add(federatedClientCredentialsParameter);
예외의 원인이었으며 GetProperty
호출이를 반환했습니다 null
. 그래서 WTF? 메시지 보안을 설정하고 클라이언트 자격 증명 유형을 IssuedToken
로 설정하면 이 속성이 이제 존재합니다 ClientFactory
.
<binding name="OMGWTFLOL22" transferMode="Streamed" >
<security mode="Message">
<message clientCredentialType="IssuedToken"/>
</security>
</binding>
단. 더 이상 NRE가 없습니다. 그러나 이제 내 의뢰인은 태어날 때 잘못이되었다 (아직도 그를 사랑하라). WCF 진단을 통해 발굴 (팁 : 최악의 적들이 그들을 분쇄하고 당신 앞에서 운전하지만 여성과 아이들의 애가를 즐기기 직전 에이 작업을 수행하도록하십시오), 나는 그것이 서버와 클라이언트 사이의 보안 불일치 때문이라고 생각합니다.
요청한 업그레이드는 ‘net.tcp : // localhost : 49627 / MyService’에서 지원되지 않습니다. 바인딩이 일치하지 않기 때문일 수 있습니다 (예 : 서버가 아닌 클라이언트에서 사용 가능한 보안).
호스트의 진드기 점검 (다시 : 호감, 운전, 로그 읽기, 애도를 즐기십시오), 이것이 사실임을 알았습니다.
프로토콜 유형 application / ssl-tls가 해당 유형의 업그레이드를 지원하지 않는 서비스로 전송되었습니다.
“자기야, 나는 호스트에서 메시지 보안을 켜겠다!” 그리고 나도 그래 어떻게 보이는지 알고 싶다면 클라이언트 구성의 정확한 사본입니다. 찾다.
결과 : Kaboom.
바인딩 ( ‘NetTcpBinding’, ‘ http://tempuri.org/ ‘)은 메시지 레벨 보안과 함께 구성 할 수없는 스트리밍을 지원합니다. 다른 전송 모드를 선택하거나 전송 수준 보안을 선택하십시오.
따라서 내 호스트는 tokens를 통해 스트리밍 및 보안 될 수 없습니다 . 캐치 -22.
tl; dr : WIF를 사용하여 스트리밍 된 net.tcp WCF 엔드 포인트를 어떻게 보호 할 수 있습니까 ???
답변
WCF는 대부분의 사람들이 작동한다고 생각하는 방식으로 사전 인증을 수행하지 못하는 방식의 근본적인 문제로 인해 스트리밍 (MTOM 1 ) 을 통해 일부 영역에서 문제를 겪었습니다 (해당 채널에 대한 후속 요청에만 영향을 미침) , 첫 번째 요청이 아님) 좋아요, 이것은 정확히 당신의 문제는 아니지만 마지막에 당신에게 갈 것입니다. 일반적으로 HTTP 챌린지는 다음과 같이 작동합니다.
- 클라이언트가 서버를 익명으로 공격 함
- 서버에 죄송합니다. 401, 인증이 필요합니다
- 클라이언트가 인증 토큰으로 서버에 충돌
- 서버가 동의합니다.
이제 서버의 WCF 엔드 포인트에서 MTOM 스트리밍을 사용하려고 시도하면 불평하지 않습니다. 그러나 클라이언트 프록시에서 구성하면 바인딩과 일치해야하며 불의의 죽음으로 폭발합니다. 그 이유는 WCF가 방지하려고하는 위의 이벤트 순서는 다음과 같습니다.
- 클라이언트가 단일 POST에서 익명으로 100MB 파일을 서버로 스트리밍
- 서버에서 죄송합니다. 401, 인증이 필요합니다
- 클라이언트는 다시 인증 헤더를 사용하여 100MB 파일을 서버로 스트리밍합니다
- 서버가 동의합니다.
100MB 만 보내야 할 때 서버에 200MB를 보냈습니다. 음, 이것이 문제입니다. 답은 첫 번째 시도에서 인증을 보내는 것이지만 사용자 지정 동작을 작성하지 않으면 WCF에서 불가능합니다. 어쨌든 나는 떠난다.
너의 문제
먼저, 당신이 시도하는 것이 불가능하다는 것을 말씀 드리겠습니다 2 . 이제 바퀴 회전을 멈추기 위해 이유를 알려 드리겠습니다.
당신이 지금 비슷한 종류의 문제에서 방황하고 있다는 것이 저를 놀라게합니다. 메시지 레벨 보안을 사용하는 경우 클라이언트는 ws-security에 필요한 일반 해시 함수 및 xml 서명으로 메시지를 실제로 닫을 수 있기 전에 전체 데이터 스트림을 메모리에로드해야합니다. 단일 메시지 (실제로 메시지는 아니지만 단일 연속 스트림)에 서명하기 위해 전체 스트림을 읽어야하는 경우 여기에서 문제를 볼 수 있습니다. WCF는 메시지 보안을 계산하기 위해 “로컬”로 한 번 스트리밍 한 다음 다시 스트리밍하여 서버로 보냅니다. 이것은 명백히 어리석은 일이므로 WCF는 스트리밍 데이터에 대한 메시지 수준 보안을 허용하지 않습니다.
따라서 간단한 대답은 토큰을 초기 웹 서비스의 매개 변수 또는 SOAP 헤더로 보내고 사용자 지정 동작을 사용하여 토큰을 확인해야한다는 것입니다. 이를 위해 WS-Security를 사용할 수 없습니다. 솔직히 이것은 WCF 문제가 아닙니다. 다른 스택에서 실제로 어떻게 작동하는지 알 수 없습니다.
MTOM 문제 해결
이것은 기본 인증을 위해 MTOM 스트리밍 문제를 해결 한 방법에 대한 예일 뿐이므로이 문제를 해결하고 비슷한 문제를 구현할 수 있습니다. 핵심은 사용자 정의 메시지 검사기를 사용하려면 전송 레벨 (SSL)을 제외하고 클라이언트 프록시 (서버에서 사용 가능한 상태로 유지)에서 모든 보안 개념을 사용하지 않아야한다는 것입니다.
this._contentService.Endpoint.Behaviors.Add(
new BasicAuthenticationBehavior(
username: this.Settings.HttpUser,
password: this.Settings.HttpPass));
var binding = (BasicHttpBinding)this._contentService.Endpoint.Binding;
binding.Security.Mode = BasicHttpSecurityMode.Transport; // SSL only
binding.Security.Transport.ClientCredentialType =
HttpClientCredentialType.None; // Do not provide
메시지 관리자와 사용자 지정 동작을 사용하여 직접 제공 할 것이기 때문에 여기에서 전송 보안을 해제했습니다.
internal class BasicAuthenticationBehavior : IEndpointBehavior
{
private readonly string _username;
private readonly string _password;
public BasicAuthenticationBehavior(string username, string password)
{
this._username = username;
this._password = password;
}
public void AddBindingParameters(ServiceEndpoint endpoint,
BindingParameterCollection bindingParameters) { }
public void ApplyClientBehavior(ServiceEndpoint endpoint,
ClientRuntime clientRuntime)
{
var inspector = new BasicAuthenticationInspector(
this._username, this._password);
clientRuntime.MessageInspectors.Add(inspector);
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint,
EndpointDispatcher endpointDispatcher) { }
public void Validate(ServiceEndpoint endpoint) { }
}
internal class BasicAuthenticationInspector : IClientMessageInspector
{
private readonly string _username;
private readonly string _password;
public BasicAuthenticationInspector(string username, string password)
{
this._username = username;
this._password = password;
}
public void AfterReceiveReply(ref Message reply,
object correlationState) { }
public object BeforeSendRequest(ref Message request,
IClientChannel channel)
{
// we add the headers manually rather than using credentials
// due to proxying issues, and with the 101-continue http verb
var authInfo = Convert.ToBase64String(
Encoding.Default.GetBytes(this._username + ":" + this._password));
var messageProperty = new HttpRequestMessageProperty();
messageProperty.Headers.Add("Authorization", "Basic " + authInfo);
request.Properties[HttpRequestMessageProperty.Name] = messageProperty;
return null;
}
}
따라서이 예는 MTOM 문제로 어려움을 겪고있는 사람을위한 것이지만 기본 WIF 보안 토큰 서비스에서 생성 한 토큰을 인증하기 위해 비슷한 것을 구현하기위한 뼈대입니다.
도움이 되었기를 바랍니다.
(1) 대용량 데이터 및 스트리밍
(2) WCF의 메시지 보안 ( “단점”참조)