Catch-22 ngăn chặn dịch vụ TCP WCF được truyền phát an toàn bởi WIF; hủy hoại Giáng sinh của tôi, sức khỏe tâm thần


181

Tôi có một yêu cầu để bảo mật điểm cuối dịch vụ WCF net.tcp được truyền phát bằng WIF . Nó sẽ xác thực các cuộc gọi đến đối với máy chủ mã thông báo của chúng tôi. Dịch vụ này được truyền phát vì nó được thiết kế để truyền một lượng lớn dữ liệu thứ n.

Điều này dường như là không thể. Và nếu tôi không thể đi lại được, Giáng sinh của tôi sẽ bị hủy hoại và tôi sẽ tự uống đến chết trong máng xối trong khi những người mua sắm vui vẻ bước qua cơ thể đang lạnh dần của tôi. Totes nghiêm trọng, các bạn.

Tại sao điều này là không thể? Đây là Catch-22.

Trên máy khách, tôi cần tạo một kênh với GenericXmlSecurityToken tôi nhận được từ máy chủ mã thông báo của chúng tôi. Không có vấn đề.

// people around here hate the Framework Design Guidelines.
var token = Authentication.Current._Token;
var service = base.ChannelFactory.CreateChannelWithIssuedToken(token);
return service.Derp();

Tôi đã nói "không có vấn đề"? Vấn đề. Trong thực tế, NullReferenceExceptionphong cách vấn đề.

"Bro", tôi hỏi Framework, "bạn có kiểm tra null không?" Khung im lặng, vì vậy tôi đã tháo rời và thấy rằng

((IChannel)(object)tChannel).
    GetProperty<ChannelParameterCollection>().
    Add(federatedClientCredentialsParameter);

là nguồn gốc của ngoại lệ và GetPropertycuộc gọi đã trở lại null. Vậy, WTF? Hóa ra nếu tôi bật Bảo mật tin nhắn và đặt loại thông tin xác thực của khách hàng IssuedTokenthì thuộc tính này hiện tồn tại trong ClientFactory(protip: Không có "SetProperty" tương đương trong IChannel, tên khốn).

<binding name="OMGWTFLOL22" transferMode="Streamed" >
    <security mode="Message">
        <message clientCredentialType="IssuedToken"/>
    </security>
</binding>

Ngọt. Không còn NRE. Tuy nhiên, bây giờ khách hàng của tôi bị lỗi khi sinh (vẫn yêu anh, tho). Đi sâu vào chẩn đoán WCF (protip: làm cho kẻ thù tồi tệ nhất của bạn làm điều này sau khi nghiền nát chúng và lái chúng trước bạn nhưng ngay trước khi thưởng thức những lời than vãn của phụ nữ và trẻ em của chúng), tôi thấy đó là do sự không phù hợp về bảo mật giữa máy chủ và máy khách.

Nâng cấp được yêu cầu không được hỗ trợ bởi 'net.tcp: // localhost: 49627 / MyService'. Điều này có thể là do các ràng buộc không khớp (ví dụ: bảo mật được kích hoạt trên máy khách chứ không phải trên máy chủ).

Kiểm tra các dấu vết của máy chủ (một lần nữa: đè bẹp, lái xe, đọc nhật ký, thưởng thức những lời than thở), tôi thấy điều này là đúng

Ứng dụng / ssl-tls Loại giao thức được gửi đến một dịch vụ không hỗ trợ loại nâng cấp đó.

"Chà, tự," tôi nói, "Tôi sẽ chỉ bật Bảo mật tin nhắn trên máy chủ!" Và tôi làm. Nếu bạn muốn biết nó trông như thế nào, thì đó là bản sao chính xác của cấu hình máy khách. Tra cứu.

Kết quả: Kaboom.

Liên kết ('NetTcpBinding', ' http://tempuri.org/ ') hỗ trợ truyền phát mà không thể được cấu hình cùng với bảo mật cấp thông báo. Xem xét chọn một chế độ chuyển khác nhau hoặc chọn bảo mật cấp vận chuyển.

Vì vậy, máy chủ của tôi không thể được truyền phát và bảo mật thông qua mã thông báo . Bắt-22.

tl; dr: Làm cách nào tôi có thể bảo mật điểm cuối WCF được truyền phát trực tuyến bằng WIF ???


3
Ok, có lẽ là câu hỏi không biết gì ở đây, nhưng WIF có thực sự yêu cầu chế độ Tin nhắn không? Chế độ vận chuyển nghe có vẻ như sẽ hoạt động tốt hơn với phát trực tuyến, một thứ giống như chưa được kiểm chứng<security mode="Transport" /> <transport clientCredentialType="IssuedToken" /> </security>
Joachim Isaksson

3
TransportWithMessageCredentialchế độ có thể là một lựa chọn khác.
Joachim Isaksson

3
TMLK, MessageSecurance có thể ký và mã hóa tải trọng được đệm, nhưng dò dẫm khi xử lý các luồng. Bạn đã cân nhắc sử dụng xác thựcMode = IssuedTokenOverTransport chưa?
OnoSendai

7
Hãy để tôi xem nếu tôi có thể triệu tập một số hồn ma từ quá khứ để giúp tiết kiệm kỳ nghỉ của bạn sau đó. Một số gợi ý ở đây: social.msdn.microsoft.com/Forums/vstudio/en-US/NH
OnoSendai

2
Bất kỳ cơ hội nào bạn có thể đăng một dự án trường hợp thử nghiệm mà người khác có thể thử nghiệm?
antiduh

Câu trả lời:


41

WCF đã gặp rắc rối ở một số khu vực có phát trực tuyến (tôi đang xem xét bạn, MTOM 1 ) do vấn đề cơ bản là làm thế nào để nó không thực hiện việc xác nhận trước theo cách mà hầu hết mọi người sẽ nghĩ rằng nên hoạt động (nó chỉ ảnh hưởng đến các yêu cầu tiếp theo cho kênh đó , không phải là yêu cầu đầu tiên) Ok, vì vậy đây không chính xác là vấn đề của bạn nhưng vui lòng làm theo vì tôi sẽ nhận được yêu cầu của bạn vào cuối. Thông thường, thách thức HTTP hoạt động như thế này:

  1. máy khách truy cập nặc danh
  2. máy chủ nói, xin lỗi, 401, tôi cần xác thực
  3. máy khách truy cập máy chủ với mã thông báo xác thực
  4. máy chủ chấp nhận.

Bây giờ, nếu bạn từng cố gắng kích hoạt phát trực tuyến MTOM trên điểm cuối WCF trên máy chủ, nó sẽ không phàn nàn. Nhưng, khi bạn định cấu hình nó trên proxy máy khách (như bạn muốn, chúng phải khớp với các ràng buộc), nó sẽ phát nổ trong một cái chết rực lửa. Lý do cho điều này là chuỗi các sự kiện trên mà WCF đang cố gắng ngăn chặn là:

  1. máy khách truyền tệp 100MB đến máy chủ ẩn danh trong một POST
  2. máy chủ nói xin lỗi, 401, tôi cần xác thực
  3. máy khách lại truyền tệp 100MB đến máy chủ với tiêu đề xác thực
  4. máy chủ chấp nhận.

Lưu ý rằng bạn vừa gửi 200MB đến máy chủ khi bạn chỉ cần gửi 100MB. Vâng, đây là vấn đề. Câu trả lời là gửi xác thực trong lần thử đầu tiên nhưng điều này là không thể trong WCF mà không viết một hành vi tùy chỉnh. Dù sao, tôi lạc đề.

Vấn đề của bạn

Trước tiên, hãy để tôi nói với bạn rằng những gì bạn đang cố gắng là không thể 2 . Bây giờ, để bạn ngừng quay bánh xe, hãy để tôi cho bạn biết lý do:

Tôi nhận ra rằng bạn đang đi lang thang trong một lớp vấn đề tương tự. Nếu bạn kích hoạt bảo mật mức thông báo, máy khách phải tải toàn bộ luồng dữ liệu vào bộ nhớ trước khi nó thực sự có thể đóng tin nhắn với hàm băm thông thường và chữ ký xml theo yêu cầu của ws-security. Nếu nó phải đọc toàn bộ luồng để ký một tin nhắn (không thực sự là một tin nhắn, nhưng đó là một luồng liên tục duy nhất) thì bạn có thể thấy vấn đề ở đây. WCF sẽ phải truyền phát nó một lần "cục bộ" để tính toán bảo mật tin nhắn, sau đó truyền phát lại để gửi đến máy chủ. Đây rõ ràng là một điều ngớ ngẩn, vì vậy WCF không cho phép bảo mật mức tin nhắn để truyền dữ liệu.

Vì vậy, câu trả lời đơn giản ở đây là bạn nên gửi mã thông báo dưới dạng tham số cho dịch vụ web ban đầu hoặc dưới dạng tiêu đề SOAP và sử dụng hành vi tùy chỉnh để xác thực nó. Bạn không thể sử dụng WS-Security để làm điều này. Thành thật mà nói, đây không chỉ là vấn đề WCF - tôi không thể thấy nó thực sự có thể hoạt động như thế nào đối với bất kỳ ngăn xếp nào khác.

Giải bài toán MTOM

Đây chỉ là một ví dụ về cách tôi giải quyết vấn đề phát trực tuyến MTOM của mình để xác thực cơ bản, vì vậy có lẽ bạn có thể lấy can đảm của việc này và thực hiện một cái gì đó tương tự cho vấn đề của bạn. Điểm mấu chốt của nó là để kích hoạt trình kiểm tra tin nhắn tùy chỉnh của bạn, bạn phải vô hiệu hóa tất cả các khái niệm về bảo mật trên proxy máy khách (nó vẫn được bật trên máy chủ,) ngoài mức vận chuyển (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

Lưu ý rằng tôi đã tắt bảo mật vận chuyển ở đây vì tôi sẽ tự cung cấp cho mình bằng cách sử dụng trình kiểm tra thư và hành vi tùy chỉnh:

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

Vì vậy, ví dụ này dành cho bất kỳ ai đang gặp phải vấn đề MTOM, nhưng cũng là bộ xương để bạn triển khai một cái gì đó tương tự để xác thực mã thông báo của bạn được tạo bởi dịch vụ mã thông báo được bảo mật WIF chính.

Hi vọng điêu nay co ich.

(1) Dữ liệu lớn và truyền phát

(2) Bảo mật tin nhắn trong WCF (xem "nhược điểm.")


MTOM and Basic AuthorizationMTOM và OAuth2 ?
Kiquenet
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.