Các lưu ý bảo mật trong ASP.NET Core SignalR
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ụ:
- Site của bạn được host trên
http://www.example.com - Ứng dụng SignalR được host trên
http://signalr.example.com
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:
- Cho phép các origin cụ thể được mong đợi. Cho phép bất kỳ origin nào là có thể nhưng không an toàn hoặc không được khuyến nghị.
- Các HTTP method
GETvàPOSTphải được cho phép. - Credentials (thông tin xác thực) phải được cho phép để cookie-based sticky sessions hoạt động đúng. Chúng phải được bật ngay cả khi không sử dụng xác thực.
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:
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":
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:
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]:
[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ụ:
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://localhost:5000/chathub?access_token=1234Nế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:
- Ngăn client gửi tin nhắn lớn hơn.
- Server sẽ không bao giờ cần cấp phát buffer lớn để nhận tin nhắn.
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à:
- Client có thể khiến server cấp phát buffer bộ nhớ lớn.
- Server cấp phát buffer lớn có thể làm giảm số lượng kết nối đồng thời.
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:
ApplicationMaxBufferSizeđại diện cho số byte tối đa từ client mà server lưu vào buffer. Nếu client cố gắng gửi tin nhắn lớn hơn giới hạn này, kết nối có thể bị đóng.TransportMaxBufferSizeđại diện cho số byte tối đa mà server có thể gửi. Nếu server cố gắng gửi tin nhắn (bao gồm cả giá trị trả về từ hub methods) lớn hơn giới hạn này, một exception sẽ được ném ra.
Đặ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.