הפעלות ואבטחה

הפעלות מסמכים ובקרת גישה

אסימון Doconut מזהה מסמך פתוח. אם כל בקשה שנושאת אותו תשרת, מי שהשיג אותו יוכל לקרוא כל דף. דף זה מסביר מה מכילה הפעלת מסמך, כמה זמן היא נמשכת, וכיצד DocImage.axd מחליט מי רשאי לראות את הדפים שלה — בשרת יחיד ובחוות רשת.

מה שמכילה הפעלת מסמך

כל OpenDocumentAsync מוצלח יוצר הפעלה אחת, הנשמרת בזיכרון:

  • הצופה בפורמט הטעון — מופע המנוע המחזיק את המסמך המפוענח,
  • מצב לכל דף — סיבוב, הפיכות, ונתוני ההערות שהמשתמש מוסיף בווידג'ט,
  • האינדקס חיפוש האופציונלי, נבנה בחיפוש הראשון (או נטען מקובץ .srh שנבנה מראש),
  • הסימן מים של ההפעלה מ-DocOptions.Watermark.

משך החיים

הפעלות פוגעות בחלון זמן מתגלגל: DocOptions.TimeOut דקות (ברירת מחדל 60), מתאפסות בכל בקשה שמציגה את האסימון. כאשר הפעלה מסתיימת — עקב פקיעה או על ידי CloseDocument(token) — מנוע המסמך משוחרר והזיכרון שלו משוחרר מיידית.

csharp
// מושב קצר טווח לתצוגה מקדימה חד-פעמית
var token = await viewer.OpenDocumentAsync(path, new DocOptions { TimeOut = 10 });

בקשה עם אסימון שפג מקבלת תמונת שגיאה עם הטקסט Document session not found. Please re-open document.. על הדף לפתוח את המסמך מחדש כדי לקבל אסימון חדש. בשרת יחיד, מחזור של בריכת היישומים מסיים גם כל הפעלה.

דפים ניתנים רק להפעלה שפתחה אותם

עם UnsafeMode = false — ברירת המחדל — פתיחת מסמך מעניקה גישה להפעלה של ASP.NET של הבקשה שפתחה אותו, על ידי כתיבת רשומת secure-{token} באותה הפעלה. DocImage.axd דורש את מצב ההפעלה עצמו, ומציג דף רק כאשר הפעלת הבקשה מחזיקה ברשומה זו. כל דפדפן אחר שמציג את אותו אסימון מקבל תמונת שגיאה עם הטקסט You Are Not Authorized To View This Page..

csharp
Doconut.DoconutHost.Initialize(options =>
{
    // false (ברירת המחדל): DocImage.axd מגיש דף רק למושב ASP.NET שפתח אותו
    // המסמך. המטפל מבקש את מצב המושב בעצמו; הוא צריך רק שהאתר לא
    // כבה את מצב המושב ב‑Web.config.
    options.UnsafeMode = false;
});

שלושה השלכות מעשיות:

  • נקודת הקצה הפתוחה דורשת מצב הפעלה. בקרים של MVC ודפי Web Forms כוללים זאת כברירת מחדל. IHttpHandler מותאם אישית אינו עושה זאת אלא אם הוא מממש System.Web.SessionState.IRequiresSessionState. פתיחה שמופעלת ללא הפעלה אין לה מה להעניק, ולכן הצופה מציג את ההודעה "אינך מורשה לצפות בדף זה." בכל דף.
  • מצב ההפעלה חייב להיות פעיל. <sessionState mode="Off" /> בWeb.config משביתים הן את ההענקה והן את הבדיקה, וכל דף נדחה.
  • הדפדפן חייב לשלוח את עוגיית ההפעלה. הבקשות של הווידג'ט הן מאותו מקור, ולכן הן נושאות את ASP.NET_SessionId אוטומטית. לקוח ללא מכולת עוגיות — סקריפט, קריאה משרת-לשרת, או הגדרה חוצת‑מקור שמסירה עוגיות — נדחה. זהו הפונקציונליות הפועלת.

UnsafeMode = true מכבה את הבדיקה: כל בקשה שנושאת את האסימון משרתת. זהו מתג גלובלי אחד לכל מסמך, ללא אפשרות דריסת הגדרה לכל מסמך. השאירו אותו false.

ביטול

CloseDocument(token) עושה יותר משחרור זיכרון: הוא מסיר את רשומת secure-{token} מההפעלה של הבקשה הנוכחית ומבטל את האסימון, כך שאסימון סגור נדחה מייד.

חוות רשת: כרטיסים חתומים

בחווה, הבקשה הבאה יכולה להגיע לשרת שמעולם לא ראה את המסמך, בתהליך עובד שונה, עם הפעלת ASP.NET משלו. ההענקה של ההפעלה אינה יכולה לעקוב אחריה. מצב מבוזר מחליף זאת בכרטיס חתום הקשור לדפדפן: כל צומת חולק מאגר אחד להפעלות מסמכים ומפתח חתימה אחד, וDocImage.axd מקבל בקשה כאשר הכרטיס שלו תקף לאותו אסימון, לדפדפן ההוא, ו—כאשר המשתמש מחובר—לאותו משתמש.

ההגדרה, זהה בכל צומת:

csharp
// Global.asax.cs - Application_Start
Doconut.DoconutHost.Initialize(
    options => options.UnsafeMode = false,     // בדיקת הכרטיס פועלת רק כאשר זה false
    services => services.AddDoconutDistributed(d =>
    {
        d.Store             = CloudLocation.FileShare;
        d.FileShareRootPath = @"\\fileserver\doconut-shared";  // תיקייה שכל צומת יכול להגיע אליה
        d.SigningKey        = farmKey;                          // לפחות 32 בתים, זהה על כל צומת
    }));

נקודת הקצה הפתוחה אז קושרת את הכרטיס לדפדפן לפני הפתיחה, ומחזירה את הכרטיס יחד עם האסימון:

  • הגדר DocOptions.BrowserId = DoconutFarmBinding.EnsureBrowserId(System.Web.HttpContext.Current, securityOptions) — הוא מנפיק את עוגיית doconut-client שהכרטיס קשור אליה — וDocOptions.UserId = DoconutFarmBinding.ResolveUserId(System.Web.HttpContext.Current);
  • לאחר OpenDocumentAsync, החזר viewer.AccessToken לצד האסימון;
  • בעמוד, העבר את שניהם לווידג'ט: objViewer.View(token, access).

Doconut.MvcSample.WebFarm בחבילת הדוגמאות הוא צומת חווה שלם, בר ביצוע, וההדריך למעבר שלצידו מסביר כל שלב.

שמרו את מפתח החתימה מחוץ לבקרת המקור: הוא חותם את הכרטיסים ומצפין את המסמכים במאגר המשותף. צומת עם מפתח שונה דוחה כל כרטיס שהאחרים הנפיקו.

בדקו חווה עם דפדפן אמיתי, או סקריפט ששומר על עוגיות. לקוח ללא עוגיית doconut-client אינו מקבל תשובה עם 401: הוא מקבל את תמונת השגיאה "לא מורשה" עם סטטוס 200, כ‑2 ק״ב, בעוד דף אמיתי הוא בעשרות עד מאות קילובייטים.

רשימת בדיקות לייצור

  • שמרו על UnsafeMode = false (ברירת המחדל).
  • פתחו מסמכים מבקשות שיש להן מצב הפעלה, ולעולם אל תכבו את מצב ההפעלה.
  • ודאו שעוגיית ההפעלה מגיעה אל DocImage.axd (אותו מקור, HTTPS, מדיניות SameSite שמאפשרת זאת).
  • בחווה, השתמשו במצב מבוזר עם מפתח חתימה אחד משותף לכל הצמתים.
  • קראו לCloseDocument כאשר המשתמש עוזב מסמך — זיכרון ואבטחה משפרים.
  • לעולם אל תתעדו או תשתפו אסימונים; התייחסו אליהם כלאימותים קצרים.

האם דף זה היה מועיל?