Nguon: Microsoft Learn · .NET 8.0

Các lưu ý bảo mật trong ASP.NET Core SignalR

Nguồn: Security considerations in ASP.NET Core SignalR

Bởi Andrew Stanton-Nurse

Bài viết này cung cấp thông tin về bảo mật SignalR.

Cross-Origin Resource Sharing (CORS - Chia sẻ tài nguyên khác nguồn gốc)

Cross-Origin Resource Sharing (CORS) có thể được dùng để cho phép các kết nối SignalR khác nguồn gốc trong trình duyệt. Nếu mã JavaScript được host trên một domain khác với ứng dụng SignalR, CORS middleware phải được bật để cho phép JavaScript kết nối với ứng dụng SignalR. Chỉ cho phép các request từ các domain bạn tin tưởng hoặc kiểm soát. Ví dụ:

CORS phải được cấu hình trong ứng dụng SignalR để chỉ cho phép origin www.example.com.

SignalR yêu cầu các CORS policy sau:

Ví dụ, CORS policy sau cho phép một SignalR browser client được host trên https://example.com truy cập ứng dụng SignalR được host trên https://signalr.example.com:

csharp
using SignalRChat.Hubs;

var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: MyAllowSpecificOrigins,
                      policy =>
                      {
                          policy.WithOrigins("http://example.com");
                          policy.WithMethods("GET", "POST");
                          policy.AllowCredentials();
                      });
});

// Thêm services vào container.
builder.Services.AddRazorPages();
builder.Services.AddSignalR();

var app = builder.Build();

app.MapHub<ChatHub>("/chatHub");

Áp dụng CORS policy cho SignalR hub endpoints

Thay vì áp dụng CORS policy toàn cục bằng middleware UseCors, bạn có thể áp dụng CORS cụ thể cho các SignalR hub endpoints. Cách tiếp cận này cho phép các CORS policy khác nhau cho các phần khác nhau của ứng dụng.

Có hai cách áp dụng CORS policy cho SignalR hubs: nối chuỗi RequireCors trên endpoint mapping, hoặc thêm thuộc tính [EnableCors] vào lớp Hub. Cả hai cách đều yêu cầu một named CORS policy được đăng ký trong cấu hình service. Ví dụ sau định nghĩa một policy tên "SignalRPolicy":

csharp
builder.Services.AddCors(options =>
{
    options.AddPolicy("SignalRPolicy", policy =>
    {
        policy.WithOrigins("https://example.com")
            .AllowAnyHeader()
            .WithMethods("GET", "POST")
            .AllowCredentials();
    });
});

Áp dụng CORS policy trên hub endpoint mapping bằng cách nối chuỗi RequireCors trên lệnh gọi MapHub:

csharp
app.MapHub<ChatHub>("/chatHub")
    .RequireCors("SignalRPolicy");

Áp dụng CORS policy trên lớp Hub bằng cách thêm thuộc tính [EnableCors]:

csharp
[EnableCors("SignalRPolicy")]
public class ChatHub : Hub
{
    // ...
}

Hạn chế Origin WebSocket

Các biện pháp bảo vệ của CORS không áp dụng cho WebSockets. Để hạn chế origin cho WebSockets, đọc WebSockets origin restriction.

ConnectionId

Việc lộ ConnectionId có thể dẫn đến giả mạo độc hại nếu phiên bản SignalR server hoặc client là ASP.NET Core 2.2 trở về trước. Nếu phiên bản SignalR server và client là ASP.NET Core 3.0 trở lên, ConnectionToken thay vì ConnectionId phải được giữ bí mật. ConnectionToken cố ý không được lộ trong bất kỳ API nào. Có thể khó đảm bảo rằng các SignalR client cũ hơn không kết nối đến server, vì vậy ngay cả khi phiên bản SignalR server của bạn là ASP.NET Core 3.0 trở lên, ConnectionId cũng không nên bị lộ.

Ghi log Access token

Khi sử dụng WebSockets hoặc Server-Sent Events, browser client gửi access token trong query string. Nhận access token qua query string nhìn chung cũng an toàn như dùng header Authorization tiêu chuẩn. Luôn sử dụng HTTPS để đảm bảo kết nối end-to-end an toàn giữa client và server. Nhiều web server ghi log URL cho mỗi request, bao gồm cả query string. Việc ghi log URL có thể ghi log access token. ASP.NET Core ghi log URL cho mỗi request theo mặc định, bao gồm cả query string. Ví dụ:

output
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
      Request starting HTTP/1.1 GET http://localhost:5000/chathub?access_token=1234

Nếu bạn lo ngại về việc ghi log dữ liệu này trong server logs, bạn có thể tắt hoàn toàn việc ghi log này bằng cách cấu hình logger Microsoft.AspNetCore.Hosting ở mức Warning hoặc cao hơn (các message này được ghi ở mức Info). Xem Apply log filter rules in code để biết thêm thông tin. Nếu bạn vẫn muốn ghi log một số thông tin request, bạn có thể viết middleware để ghi log dữ liệu cần thiết và lọc bỏ giá trị query string access_token (nếu có).

Exceptions (Ngoại lệ)

Thông báo exception thường được coi là dữ liệu nhạy cảm không nên tiết lộ cho client. Theo mặc định, SignalR không gửi chi tiết của exception được ném ra bởi một hub method đến client. Thay vào đó, client nhận được một thông báo chung báo hiệu đã xảy ra lỗi. Việc gửi thông báo exception đến client có thể được ghi đè (ví dụ trong môi trường development hoặc test) bằng EnableDetailedErrors. Thông báo exception không nên được lộ cho client trong các ứng dụng production.

Buffer management (Quản lý bộ đệm)

SignalR sử dụng buffer (bộ đệm) per-connection (mỗi kết nối) để quản lý các tin nhắn đến và đi. Theo mặc định, SignalR giới hạn các buffer này ở 32 KB. Tin nhắn lớn nhất mà client hoặc server có thể gửi là 32 KB. Bộ nhớ tối đa được tiêu thụ bởi một kết nối cho các tin nhắn là 32 KB.

Nếu tin nhắn của bạn luôn nhỏ hơn 32 KB, bạn có thể giảm giới hạn này:

Nếu tin nhắn của bạn lớn hơn 32 KB, bạn có thể tăng giới hạn này. Tuy nhiên việc tăng giới hạn có nghĩa là:

Có giới hạn cho cả tin nhắn đến và đi, cả hai đều có thể được cấu hình trên đối tượng HttpConnectionDispatcherOptions được cấu hình trong MapHub:

Đặt giới hạn thành 0 sẽ vô hiệu hóa giới hạn. Xóa giới hạn cho phép client gửi tin nhắn có kích thước bất kỳ. Các client độc hại gửi tin nhắn lớn có thể gây ra cấp phát bộ nhớ quá mức. Việc sử dụng bộ nhớ quá mức có thể làm giảm đáng kể số lượng kết nối đồng thời.