Sesje i bezpieczeństwo

Sesje dokumentu i kontrola dostępu

Token Doconut jest potężny: każdy, kto go przedstawi, mógłby żądać każdej strony dokumentu, gdyby nie był powiązany z sesją otwierającą. Ta strona wyjaśnia, co przechowuje sesja, jak długo żyje oraz jakie kontrole domyślnie włącza UseDoconut().

Co przechowuje sesja dokumentu

  • załadowany podgląd formatu (instancja silnika dokumentu przechowująca przetworzony dokument),
  • stan per-strona — rotacja, odbicia i dane adnotacji, które użytkownik stosuje w widżecie,
  • opcjonalny indeks wyszukiwania, tworzony leniwie przy pierwszym wyszukiwaniu (lub ładowany z wstępnie zbudowanego pliku .srh, gdy strony są serwowane z współdzielonego magazynu),
  • znak wodny sesji pochodzący z DocOptions.Watermark.

Okres życia

Sesje wygasają po przesuwanym oknie: DocOptions.TimeOut minut (domyślnie 60), resetowane przy każdym żądaniu prezentującym token. Gdy sesja zostaje usunięta — z powodu wygaśnięcia lub przez CloseDocument(token) — jej callback usuwający zwalnia silnik dokumentu i natychmiast zwalnia powiązaną pamięć.

csharp
// Krótkożyjąca sesja do jednorazowego podglądu
var token = await viewer.OpenDocumentAsync(path, new DocOptions { TimeOut = 10 });

Żądanie z wygasłym tokenem otrzymuje obraz błędu z napisem Document session not found. Please re-open document. — klient musi ponownie otworzyć dokument, aby uzyskać nowy token.

Wbudowane powiązanie tokenu

Przy UnsafeMode = false (domyślnie), OpenDocumentAsync wiąże nowy token z sesją ASP.NET żądania HTTP, które go otworzyło, zapisując znacznik secure-{token} w tej sesji. Pośrednik Doconut odmawia wtedy serwowania stron innym sesjom przeglądarki:

  • Inna przeglądarka/sesja prezentująca skradziony token → obraz błędu You Are Not Authorized To View This Page.
  • Pośrednik sesji nie zarejestrowany → HTTP 500 Session middleware not configured. Call UseSession() before UseDoconut().

Dlatego Quick Start wymaga AddSession() + app.UseSession() przed gałęzią Doconut. Dwie praktyczne konsekwencje:

  • Klient musi wysyłać ciasteczko sesji ASP.NET wraz z żądaniami stron. Konfiguracje cross-origin usuwające ciasteczka (lub klient API bez pojemnika na ciasteczka) spowodują niepowodzenie kontroli — to działająca funkcja, a nie błąd.
  • options.UnsafeMode = true wyłącza całkowicie powiązanie. Istnieje dla kontrolowanych scenariuszy; pozostaw false w produkcji na pojedynczym węźle.

Zwróć uwagę na pisownię. Poprzednia biblioteka .NET Standard nazywała tę właściwość UnSafeMode i przekazywała ją do pośrednika; tutaj jest to UnsafeMode i jest ustawiane raz wewnątrz AddDoconut().

Powiązanie tokenu jest kontrolowane wyłącznie przez ten globalny przełącznik UnsafeMode — jest włączony domyślnie (UnsafeMode = false) i ma zastosowanie do każdej sesji. Nie ma możliwości wyłączenia go per dokument; ustawienie UnsafeMode = true wyłącza powiązanie globalnie.

Przyznania dostępu i uwierzytelnieni użytkownicy

Gdy UnsafeMode jest false, UseDoconut() wstawia pośrednika dostępu do dokumentu automatycznie przed pośrednikiem stron. Nie rejestruj go ponownie. Gdy żądanie zawiera token, wyszukuje przyznanie dostępu zapisane przy otwieraniu dokumentu i autoryzuje tylko wtedy, gdy spełnione są wszystkie poniższe warunki:

  1. przyznanie istnieje dla tokenu,
  2. nie wygasło (czas życia przyznania = TimeOut dokumentu),
  3. identyfikator sesji ASP.NET żądającego pasuje do tego, który otworzył dokument,
  4. jeśli otwierający był uwierzytelniony, roszczenie NameIdentifier żądającego użytkownika również się zgadza.

Niepowodzenia zwracają 403 — jako obraz PNG błędu dla żądań stron/miniatur, w przeciwnym razie jako zwykły tekst. Wiadomość i klucz zapytania tokenu pochodzą z DocumentSecurityOptions (TokenQueryKey, domyślnie "token"; UnauthorizedMessage, domyślnie "You Are Not Authorized To View This Page."). Skonfiguruj te opcje przez ASP.NET Core DI przed budowaniem aplikacji. Jeśli stan sesji jest niedostępny, pośrednik zamyka się z HTTP 500: ASP.NET Session is required for Doconut document security.

csharp
builder.Services.Configure<Doconut.Security.DocumentSecurityOptions>(options =>
{
    options.TokenQueryKey = "token";
    options.UnauthorizedMessage = "You Are Not Authorized To View This Page.";
});

Podstawowy pośrednik stron weryfikuje znacznik sesji secure-{token} przed serwowaniem dokumentu. Przy UnsafeMode = true, UseDoconut() pomija pośrednika dostępu, a sprawdzenie znacznika jest również wyłączone.

Bezpieczeństwo w kilku węzłach

Tokeny powiązane z sesją zakładają, że węzeł serwujący stronę również widział żądanie otwarcia dokumentu. To założenie nie obowiązuje, gdy kilka węzłów serwuje te same dokumenty z współdzielonego magazynu: żądanie strony może trafić na węzeł, który nigdy nie widział otwarcia, a kontrola per-sesja je odrzuca.

Rozwiązaniem nie jest pozostawianie dokumentów niechronionych. Użyj podpisanych biletów dostępu poprzez AddDoconutDistributedDocumentSecurity(...), które zastępują kontrolę sesji poświadczeniem, które każdy węzeł może zweryfikować niezależnie. Pełny opis znajduje się w Rozproszone wdrożenia.

Odwołanie

CloseDocument(token) nie tylko zwalnia pamięć — usuwa również znacznik secure-{token} i odwołuje przyznanie dostępu, więc zamknięty token jest natychmiast nieaktywny na obu warstwach bezpieczeństwa.

Lista kontrolna dla produkcji

  • Utrzymuj UnsafeMode = false (domyślnie) na pojedynczym węźle — ten globalny przełącznik wiąże tokeny z sesjami.
  • Zarejestruj AddDistributedMemoryCache() (aplikacje MVC i Razor Pages już go mają) oraz AddSession(), i wywołaj app.UseSession() przed gałęzią pośrednika Doconut.
  • Upewnij się, że polityka ciasteczek sesji pozwala żądaniom widżetu przenosić ciasteczko (SameSite, HTTPS).
  • Używaj CloseDocument, gdy użytkownik opuszcza dokument — korzyść zarówno dla pamięci, jak i bezpieczeństwa.
  • Nigdy nie loguj ani nie udostępniaj tokenów; traktuj je jako krótkotrwałe poświadczenia.
  • Czy serwujesz z współdzielonego magazynu? Przejdź na podpisane bilety dostępu zamiast akceptować niechronione dokumenty.

Czy ta strona była pomocna?