Session Resumption
Trên trang này
Session Resumption là một giao thức hiệu năng cao trong Nalix, cho phép client kết nối lại và khôi phục trạng thái trước đó mà không cần thực hiện lại X25519 Handshake đầy đủ. Điều này rất quan trọng với ứng dụng di động, nơi việc chuyển mạng (ví dụ từ Wi-Fi sang 5G) hoặc mất kết nối ngắn là chuyện thường gặp.
Ánh xạ mã nguồn
src/Nalix.Codec/ProtocolFrames/Session/SessionResume.cssrc/Nalix.Runtime/Handlers/SessionHandlers.cssrc/Nalix.SDK/Transport/Extensions/ResumeExtensions.cssrc/Nalix.Runtime/Sessions/SessionService.cs
Tính năng chính
- Kết nối lại nhanh: Việc resume hoàn tất trong một chu kỳ yêu cầu-phản hồi.
- Lưu trữ trạng thái: Khôi phục mức xác thực, quyền và các attribute tùy chỉnh của kết nối.
- Xoay vòng token: Mỗi lần resume thành công trả về một session token mới cho lần kết nối lại tiếp theo.
- Xác thực zero-trust: Dùng bằng chứng sở hữu dựa trên HMAC để xác minh client thực sự sở hữu session secret.
Quy trình Resume
Sơ đồ sau minh họa cách Nalix SDK dùng token đã lưu để tiếp tục một phiên trên Nalix Server.
sequenceDiagram
participant SDK as Nalix SDK (Client)
participant Srv as Nalix Server
participant SSv as Session Service
participant Store as Session Store
Note over SDK: Load Stored Session Token & Secret<br/>Compute MAC Proof: HMAC(Secret, Token)
SDK->>Srv: SESSION_SIGNAL (REQUEST)<br/>[SessionToken, MAC Proof]
Note over Srv: Resolve SessionHandlers<br/>Atomically Consume Token via Service
Srv->>SSv: ConsumeAsync(Token)
SSv->>Store: ConsumeAsync(Token)
Store-->>SSv: SessionEntry (Snapshot)
SSv-->>Srv: SessionEntry (Snapshot)
Note over Srv: Verify MAC Proof using Snapshot Secret<br/>Apply Snapshot to Live Connection<br/>Store Current Connection
Srv->>SSv: SaveSessionAsync(CurrentConnection)
SSv->>Store: StoreAsync(SessionEntry)
Srv->>SDK: SESSION_SIGNAL (RESPONSE)<br/>[NewSessionToken, SUCCESS]
Note over SDK: Update Stored Session with New Token<br/>Restore Encrypted ChannelTiêu thụ token nguyên tử
Để ngăn Race Condition và các tấn công Double-Resume, Nalix dùng cơ chế “Atomic Consumption”. Khi một yêu cầu resume đến:
- Server cố gắng xóa token khỏi
ISessionServicengay lập tức quaConsumeAsync(...). - Nếu token đã được dùng hoặc không tồn tại, yêu cầu bị từ chối ngay.
- Điều này bảo đảm một token bị đánh cắp không thể dùng hai lần, ngay cả khi hai yêu cầu đến cùng một mili giây.
Xoay vòng và bảo mật
SessionToken là một “mục tiêu di động”. Sau khi resume thành công:
- Token cũ bị vô hiệu hóa nhờ việc tiêu thụ nguyên tử.
- Một token mới được cấp cho client.
- Secret (được dẫn xuất trong handshake ban đầu) vẫn giữ nguyên, duy trì entropy bảo mật cho tầng mã hóa.
Hướng dẫn triển khai
Mặc định, mô hình Nalix Hosting tự xử lý session resumption. Tuy nhiên, bạn có thể kiểm soát hành vi bằng cách triển khai ISessionStore tùy chỉnh (ví dụ dùng Redis cho cụm phân tán).
Để resume hoạt động đầu cuối:
- Đăng ký hỗ trợ session trên server bằng
UseSessions(). - Đăng ký một store bằng
UseSessionStore(...)khi service bộ nhớ trong mặc định không đủ. - Đặt
SessionStoreOptions.MinAttributesForPersistenceđủ thấp so với metadata mà các phiên đã xác thực thực sự mang theo. - Đặt
SessionStoreOptions.SessionTtlbằng cửa sổ resume mong muốn cho phiên đã ngắt kết nối. - Giữ
TransportOptions.ResumeEnabledđược bật trên client, và giữ tokenSessionStatecùng secret của client giữa các lần thử kết nối lại.
Chính sách cửa sổ phát lại
Bằng chứng resume là HMAC-Keccak256(Secret, SessionToken || (UnixSecondsNow() / 30)) — một bucket thời gian 30 giây, được kiểm tra với t-1, t, t+1 để chịu được lệch đồng hồ. Trong cửa sổ khoảng 90 giây đó, bằng chứng tự nó mang tính xác định và có thể tái tạo, nhưng phát lại nó không cho phép resume lần thứ hai: SessionToken bị tiêu thụ nguyên tử (ISessionService.ConsumeAsync → ConcurrentDictionary.TryRemove) ở lần thành công đầu tiên, nên lần resume thứ hai với cùng token — kể cả khi bằng chứng giống hệt từng byte và vẫn còn hợp lệ — bị từ chối với SESSION_EXPIRED. Token, không phải bucket thời gian, là nonce dùng một lần.
Xem tests/Nalix.Network.Tests/InMemorySessionStoreTests.cs::ConsumeAsync_ReplayedTokenWithinSameTimeBucket_RejectedOnSecondAttempt và tests/Nalix.Framework.Tests/Cryptography/SessionResumeProofTests.cs để thấy hai nửa của đảm bảo này (tiêu thụ nonce so với tính xác định của bằng chứng).
Chính sách bọc bộ đếm sequence
Mỗi hướng transport được bảo vệ bởi một SequenceCounter đơn điệu, dùng như một phần của nonce AEAD. SequenceCounter.Next() ném CipherException nếu việc tăng sẽ vượt qua uint.MaxValue, từ chối tái sử dụng nonce. Để tránh chạm vào guard này như một lỗi trực tiếp, mọi đường gửi (TcpFrameSender, UdpFrameSender, WsFrameSender ở client; PacketPipeline.ProcessAndSendAsync ở server) giờ kiểm tra ISequenceCounter.IsApproachingOverflow(margin: 1_000_000) trước khi giữ số sequence tiếp theo:
- Phía client: ném
CipherException, và cơ chế xử lý ngoại lệ không nghiêm trọng hiện có sẽ báo lỗi quaOnErrorvà ngắt kết nối — client cần kết nối lại và handshake lại, hoặc gọiRekeyExtensions.RekeyAsyncchủ động trước thời điểm này để xoay khóa và đặt lại bộ đếm. - Phía server: gọi trực tiếp
IConnection.Disconnect(...)để đóng kết nối sạch sẽ thay vì ném ngoại lệ giữa chừng khi gửi.
ResumeFrom(lastKnownSeq, safetyGap) (dùng khi khôi phục phiên) bão hòa tại uint.MaxValue thay vì quay vòng, nên bộ đếm đã resume không bao giờ có thể âm thầm rơi xuống dưới giá trị cuối đã biết và cấp lại nonce — lần gọi Next() kế tiếp sẽ thất bại rõ ràng qua cùng guard tràn.