SSD Nodes Learn Hosting plans →
מדריכים Matt Connorמאת Matt Connor

האם Vaultwarden מאובטח? מדריך אבטחה והקשחה

Vaultwarden מצפין את כל תוכן הכספת בצד הלקוח כך שהשרת לא מחזיק מידע גלוי. גלו מהם הסיכונים האמיתיים בניהול עצמי, כולל אבטחת ה-admin token וניהול קבצי הגיבוי.

האם Vaultwarden מאובטח? התשובה הקצרה

Vaultwarden מאובטח בנקודה החשובה ביותר, כיוון שכל פריט בכספת מוצפן במכשיר שלכם לפני שהוא מגיע לשרת. השרת מאחסן גושי מידע (blobs) שאין לו יכולת לקרוא. מי שיעתיק את מסד הנתונים כולו עדיין יזדקק לסיסמת האב כדי להפיק ממנו מידע שימושי כלשהו.

התשובה הזו מסתמכת על הנחות רבות, והחלקים שעלולים להיכשל הם אלו שאתם מגדירים. פאנל ניהול מאחורי אסימון (token) שניתן לניחוש. פורט של מכולה (container) החשוף לכל האינטרנט. קובץ config.json בטקסט גלוי. קובץ גיבוי בפורמט tarball שנמצא בתיקיית הבית על אותו השרת. אף אחד מאלו אינו בעיה קריפטוגרפית. כולם מהווים את הסיבה לכך שכספות בניהול עצמי נפרצות.

כל המפורט להלן מניח קיום של התקנה תקינה. אם טרם התקנתם, בצעו זאת תחילה באמצעות מדריך ההתקנה של Vaultwarden ל-VPS, ולאחר מכן חזרו ועבדו לפי רשימה זו לפי הסדר.

מה השרת מאחסן בפועל

Vaultwarden מיישם את מודל הנתונים של Bitwarden. השם, שם המשתמש, הסיסמה, ההערות והכתובות (URIs) של פריט בכספת מוצפנים בצד הלקוח באמצעות מפתח שנגזר מסיסמת האב, וזאת לפני שליחת כל בקשה. תוכן הקבצים המצורפים מוצפן באותו אופן. השרת מקבל נתונים אטומים המשויכים ל-UUID (מזהה ייחודי אוניברסלי).

חלק מהנתונים אינם מוצפנים, ועליך לדעת בדיוק אילו מהם:

  • כתובת האימייל של החשבון, בטקסט גלוי.
  • הגדרות ה-KDF (פונקציית גזירת מפתח) וה-salt, כיוון שהלקוח זקוק להם כדי לשחזר את המפתח בכניסה הבאה.
  • Hash בצד השרת של ה-hash של סיסמת האב שנשלח מהלקוח, המשמש לאימות הכניסה עצמה.
  • מטא-דאטה: חברות בארגון, שמות מכשירים, זמני כניסה אחרונים.
  • הסוד של שיטת האימות הדו-שלבי (2FA) המגן על הכניסה ל-Vaultwarden. הוא נשמר בטבלה twofactor ללא הצפנה, כיוון שהשרת חייב לחשב את הקוד הצפוי כדי להשוות אותו לקוד שלך. אין מדובר בסוד של TOTP (סיסמה חד-פעמית מבוססת זמן) שאתה מאחסן בתוך פריט בכספת, שכן זה מוצפן כמו כל שדה אחר.

תיקיית הנתונים קטנה. בהתקנת Docker, מדובר בנתיב שמיפית ל-/data.

sudo ls -l /vw-data/

db.sqlite3 מכיל כמעט את כל מצב המערכת. attachments/ מכיל קבצים שהועלו, קובץ אחד לכל UUID, וזוהי הקטגוריה החשובה היחידה של נתונים שאינה נמצאת בטבלאות מסד הנתונים. sends/ מכיל קבצים מצורפים של Send והוא מיועד להיות זמני. icon_cache/ הוא קובץ זמני שניתן למחוק. rsa_key.pem וקובצי העזר שלו חותמים על ה-JWTs (אסימוני אינטרנט מסוג JSON) של משתמשים מחוברים, לכן עותק של מפתח פרטי זה יכול לשמש לזיוף סשן כניסה לכספת. config.json קיים רק לאחר הפעלת דף הניהול, והפרויקט מבהיר זאת ללא כחל וסרק: הוא מכיל את אסימון הניהול ואת פרטי ה-SMTP שלך בטקסט גלוי.

לפיכך, מודל האיום המעשי הוא גישה למערכת הקבצים, לא הצפנה ברשת. גישת קריאה לאותה תיקייה מעניקה גישה לכתובת האימייל של כל משתמש, לסודות ה-2FA שלהם, למפתח המאפשר זיוף סשנים, ולעותק לא מקוון של כל כספת לצורך תקיפה ללא הגבלת זמן. כל צעד להלן נועד למנוע מאנשים לא מורשים גישה לתיקייה זו.

תקנו תחילה את ה-admin token

/admin הוא לוח בקרה מלא: רשימת משתמשים, הזמנות, מחיקה וכל הגדרת זמן ריצה. הוא מוגן על ידי סוד משותף אחד בלבד. אין שם משתמש. אין אימות דו-שלבי לכל משתמש.

מדריכים ישנים מנחים ליצור ADMIN_TOKEN באמצעות openssl rand -base64 48. זה עובד, והוא כותב את הסוד בטקסט גלוי לתוך config.json ולתוך קובץ ה-compose שלכם. Vaultwarden מקבל גם מחרוזת Argon2 PHC (תחרות גיבוב סיסמאות), כך שהערך המאוחסן הוא גיבוב במקום זאת. צרו אחד מול מכולה רצה:

docker exec -it vaultwarden /vaultwarden hash

או מבלי לגעת במכולה הרצה כלל:

docker run --rm -it vaultwarden/server /vaultwarden hash

הוא יבקש סיסמה פעמיים, ואז ידפיס שורה שמתחילה ב-$argon2id$. בהתקנה על גבי שרת חשוף (bare-metal), הריצו את ./vaultwarden hash. אם אתם מעדיפים להשתמש ישירות ב-CLI של argon2, הפרויקט מתעד את הפרמטרים המינימליים של OWASP:

echo -n 'MySecretPassword' | argon2 "$(openssl rand -base64 32)" -e -id -k 19456 -t 2 -p 1

כעת, המלכודת שגוזלת לאנשים שעה של עבודה. מחרוזת PHC מלאה בתווי $, ו-Docker Compose מתייחס ל-$ כאל אינטרפולציה של משתנים. אם תדביקו אותה ללא מילוט (unescaped) לתוך בלוק environment:, הערך שיגיע למכולה יהיה משובש, ו-/admin ידחה טוקן שאתם יודעים שהוא נכון. ישנן שתי צורות בטוחות. ב-docker-compose.yml, הכפילו כל $:

environment:
  ADMIN_TOKEN: $$argon2id$$v=19$$m=19456,t=2,p=1$$UUZxK1FZMkZoRHFQRlVrTXZvS0E3bHpNQW55c2dBN2NORzdsa0Nxd1JhND0$$cUoId+JBUsJutlG4rfDZayExfjq4TCt48aBc9qsc3UI

בתוך קובץ .env, אין צורך במילוט, אך השתמשו במירכאות בודדות:

ADMIN_TOKEN='$argon2id$v=19$m=65540,t=3,p=4$MmeKRnGK5RW5mJS7h3TOL89GrpLPXJPAtTK8FTqj9HM$DqsstvoSAETl9YhnsXbf43WeaUwJC6JhViIvuPoig78'

לאחר מכן הגבילו את קצב הפניות ללוח וקצרו את משך הסשן שלו:

ADMIN_RATELIMIT_SECONDS=300
ADMIN_RATELIMIT_MAX_BURST=3
ADMIN_SESSION_LIFETIME=20

שלושה ניסיונות כושלים בתוך חמש דקות יגרמו ללוח להפסיק להשיב לאותו לקוח. סשן ה-admin יפוג לאחר 20 דקות של חוסר פעילות.

טוב יותר מכל זה: כבו את הדף. רוב המופעים זקוקים לו פעם אחת בלבד, כדי להגדיר SMTP ולהזמין את המשתמשים הראשונים, ולאחר מכן לעולם לא. כדי להשבית אותו, אל תגדירו לא את ADMIN_TOKEN ולא את DISABLE_ADMIN_TOKEN, הסירו כל מפתח "admin_token" מ-config.json, ולאחר מכן צרו מחדש את המכולה. מחיקת המפתח מהקובץ חשובה כיוון שדף ה-admin כותב הגדרות לשם, ומה שנמצא ב-config.json גובר על משתני הסביבה. הסרת המשתנה בלבד תשאיר את הדף פתוח.

סגירת ההרשמה לפני שמישהו ימצא את הדומיין

SIGNUPS_ALLOWED=false
SIGNUPS_VERIFY=true
SHOW_PASSWORD_HINT=false

SIGNUPS_ALLOWED מוגדר כברירת מחדל ל-true. אם תשאיר זאת כך, כל מי שיגיע לדומיין שלך יוכל ליצור חשבון, והנתונים שלו יישמרו באותו db.sqlite3 כמו שלך. הגדר זאת ל-false והוסף משתמשים באמצעות הזמנות מדף הניהול, מה שמחייב הגדרת SMTP תקינה. INVITATIONS_ALLOWED מוגדר גם הוא כ-true כברירת מחדל, ומאפשר לבעלי ארגונים להזמין אחרים. זה תקין כאשר אתה סומך על המשתמשים שלך, אך במופע (instance) של משתמש יחיד, עליו להיות false. אם רק דומיינים מסוימים אמורים להירשם, SIGNUPS_DOMAINS_WHITELIST=example.com הוא מגביל יותר מהרשמה פתוחה, אך חלש משמעותית משימוש בהזמנות.

SHOW_PASSWORD_HINT מוגדר כ-false כברירת מחדל, וכך עליו להישאר. כאשר הגדרה זו פעילה, הקלדת כתובת דוא"ל תקפה בטופס ההתחברות תחזיר את רמז הסיסמה הראשית של אותו חשבון; פעולה זו גם חושפת את הרמז וגם מאשרת שהכתובת קיימת במערכת.

אם המופע שלך פעל עם הרשמה פתוחה לזמן כלשהו, פתח את דף הניהול ועיין ברשימת המשתמשים לפני שתניח שאתה המשתמש היחיד במערכת.

הפורט שפורסם בטעות

ה־image של Docker מאזין לפורט 80 בתוך המכולה. התקנה על גבי שרת פיזי (bare-metal) משתמשת כברירת מחדל ב-ROCKET_PORT=8000. פקודת ה-run המתועדת מפרסמת אותו כך:

--publish 127.0.0.1:8000:80

הקידומת 127.0.0.1: היא לב העניין. אם תכתבו -p 8000:80 במקום זאת, Docker יבצע bind ל-0.0.0.0, והוא עושה זאת על ידי כתיבת חוקי DNAT (תרגום כתובות רשת ליעד) לתוך טבלת nat. חוקים אלו מוערכים לפני שרשראות ה-filter ש-ufw מנהל, ולכן ufw status מדווח על הפורט כחסום בעוד שהפורט משיב בגלוי לבקשות מהאינטרנט. כדאי לקרוא על המנגנון המלא ב-מדריך לעקיפת ufw על ידי פורטים של Docker.

בדקו מה באמת מאזין:

sudo ss -tlnp | grep 8000

תוצאה תקינה היא שורה אחת שקשורה ל-127.0.0.1:8000. שורה שקשורה ל-0.0.0.0:8000 משמעותה שה-vault חשוף ישירות. תקנו את המיפוי ולאחר מכן צרו מחדש את המכולה, כיוון שקישור פורט נקבע בעת יצירת המכולה ו-docker compose restart לא ישנה זאת:

docker compose up -d --force-recreate

פורט נוסף שנותר במדריכים ישנים הוא 3012, פורט ה-WebSocket הנפרד. התמיכה בו הוסרה ב-Vaultwarden 1.31.0, כיוון שתעבורת ההתראות עברה לפורט ה-HTTP הראשי. WEBSOCKET_ENABLED ו-WEBSOCKET_PORT מתעלמים ממנו מאז גרסה 1.29.0. המתג הנוכחי הוא ENABLE_WEBSOCKET, שערכו כברירת מחדל הוא true. אם ה-firewall או קובץ ה-compose שלכם עדיין פותחים את 3012, סגרו אותו.

סיום TLS ב-reverse proxy, לא ב-Rocket

Vaultwarden יכול להגיש TLS (אבטחת שכבת תעבורה) בעצמו דרך Rocket, תשתית ה-web שלו, אך הפרויקט מנחה לא לעשות זאת בסביבת production. ה-TLS המובנה של Rocket חסר תמיכה קפדנית ב-SNI (חיווי שם שרת), וזו גם הסיבה שההמלצה להקשחת האבטחה היא לגשת למופע שלכם לפי שם מתחם (hostname) ולעולם לא לפי כתובת IP חשופה. טווחי IP ציבוריים נסרקים ללא הרף, וכספת שמגיבה לכתובת IP היא כספת שתימצא.

החלקים החשובים בבלוק השרת של nginx:

client_max_body_size 525M;

location / {
  proxy_pass http://127.0.0.1:8000;
  proxy_set_header Host $host;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header X-Forwarded-Proto $scheme;
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection $connection_upgrade;
}

ברירת המחדל של nginx עבור client_max_body_size היא 1 MB, לכן ללא שורה זו העלאת קבצים מצורפים תיכשל עם 413 Request Entity Too Large בלוג השגיאות של nginx, בעוד ש-Vaultwarden לא ירשום דבר. ה-headers של Upgrade ו-Connection מעבירים את ה-handshake של ה-WebSocket ל-/notifications/hub. אם תסירו אותם, הכספת עדיין תעבוד, אך שינויים יפסיקו להופיע במכשירים האחרים שלכם עד שתטענו את הדף מחדש באופן ידני.

Caddy קצר יותר ומנפיק את התעודה בעצמו:

vw.example.com {
  reverse_proxy 127.0.0.1:8000 {
    header_up X-Real-IP {remote_host}
  }
}

לאחר מכן עדכנו את Vaultwarden בנושא:

DOMAIN=https://vw.example.com
IP_HEADER=X-Real-IP

IP_HEADER מוגדר כברירת מחדל ל-X-Real-IP, לכן המשימה היא לוודא שה-proxy אכן מגדיר את ה-header הזה. אם לא, כל שורת לוג וכל הגבלת קצב (rate limit) של התחברות יראו את 127.0.0.1, ה-proxy עצמו; המשמעות היא שכישלונות של תוקף אחד ייספרו כנגד כל משתמש במופע. הגדירו גם את DOMAIN לכתובת ה-https האמיתית, כיוון ש-Vaultwarden בונה ממנה קישורים להזמנות ולאיפוס סיסמה, ומפתחות אבטחה מסוג WebAuthn קשורים למקור (origin) זה.

פרט אחד שאנשים מפספסים: חיבור ה-WebSocket מעביר את ה-session token במחרוזת השאילתה (query string), בתור /notifications/hub?access_token=[JWT]. זה מגיע ללוג הגישה של ה-proxy שלכם בטקסט גלוי. בצעו הסתרה (redact) לפרמטר access_token בפורמט הלוג, או ודאו שהלוגים הללו לא נשלחים לשום מקום שאינו בשליטתכם.

חסימת התקפות Brute force בנקודת הקצה של ההתחברות

מגבלות קצב (Rate limits) מופעלות כברירת מחדל (LOGIN_RATELIMIT_SECONDS=60, LOGIN_RATELIMIT_MAX_BURST=10). הן מאטות תוקף, אך אינן עוצרות אותו. fail2ban עושה זאת, אך Vaultwarden חייב לכתוב קובץ לוג תחילה, והוא אינו עושה זאת בהגדרות ברירת המחדל:

LOG_FILE=/data/vaultwarden.log
LOG_LEVEL=info
EXTENDED_LOGGING=true

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

[2026-08-07 09:14:22][vaultwarden::api::identity][ERROR] Username or password is incorrect. Try again. IP: 203.0.113.10. Username: user@example.com.

כתבו את הפילטר אל /etc/fail2ban/filter.d/vaultwarden.local:

[INCLUDES]
before = common.conf

[Definition]
failregex = ^.*?Username or password is incorrect\. Try again\. IP: <ADDR>\. Username:.*$
ignoreregex =

ואת ה-jail אל /etc/fail2ban/jail.d/vaultwarden.local:

[vaultwarden]
enabled = true
port = 80,443
filter = vaultwarden
banaction = %(banaction_allports)s
logpath = /vw-data/vaultwarden.log
maxretry = 3
bantime = 14400
findtime = 14400

אם השארתם את דף הניהול פעיל, הוסיפו jail שני שה-failregex שלו הוא ^.*Invalid admin token\. IP: <ADDR>.*$, כיוון שכישלונות בגישה לניהול נרשמים עם הודעה שונה ופילטר ההתחברות לא יזהה אותם. לאחר מכן בדקו את עבודתכם:

sudo systemctl restart fail2ban
sudo fail2ban-client status vaultwarden

jail תקין יציג את קובץ הלוג שלכם תחת File list וידווח על Currently failed: 0. הזינו סיסמה שגויה שלוש פעמים מרשת אחרת; המונה יעלה, והכתובת תופיע תחת Banned IP list. אם המונה אינו עולה, הסיבה הנפוצה היא logpath: עליו להיות הנתיב לקובץ במערכת המארחת (host), ולא הנתיב /data/... בתוך המכולה. הסיבה הנפוצה השנייה היא חוסר ב-X-Real-IP, מה שגורם לכל חסימה להתבצע מול ה-proxy שלכם. שאר ההגדרות, כולל ה-jail עבור SSH שמומלץ להריץ בכל מקרה, נמצאות ב-מדריך fail2ban עבור Ubuntu 24.04.

סיסמת האב היא עדיין המפתח לכל המערכת

הצפנה בצד הלקוח משמעותה שסיסמת האב היא המפתח. סיסמת אב קצרה במופע (instance) שבו תוקף העתיק את מסד הנתונים אינה מוגנת על ידי אף הגדרה בפוסט זה, כיוון שהתוקף תוקף את העותק במצב לא מקוון (offline) ובקצב שחומרת המחשב שלו מאפשרת. שום הגדרת שרת אינה מגיעה למכונה של התוקף.

קל לפרש לא נכון את PASSWORD_ITERATIONS=600000. הגדרה זו קובעת את מספר האיטרציות עבור ה-hash בצד השרת של ה-hash של פרטי ההתחברות שהלקוח שולח, ותבנית התצורה של הפרויקט מציינת שערך שונה יחול על משתמשים קיימים בהתחברות הבאה שלהם. היא אינה נוגעת ב-KDF בצד הלקוח, שהיא ההגדרה הקובעת עד כמה תהיה יקרה מתקפת offline על הכספת (vault). הגדרה זו שייכת לכל חשבון בנפרד: מי שנרשם לפני שנים עשוי עדיין להשתמש בהגדרת KDF ישנה ונמוכה יותר, עד שיעלה אותה בהגדרות האבטחה של הכספת ב-web vault, פעולה שמצפינה מחדש את המפתח שלהם. עליכם ליידע אותם, כיוון שהשרת אינו יכול לעשות זאת עבורם.

לאחר מכן, הפעילו אימות דו-שלבי (2FA) לכל חשבון. הוא אינו מגן על הטקסט המוצפן (ciphertext), כיוון שמפתח הכספת נגזר מסיסמת האב בלבד. הוא כן מונע ממצב שבו סיסמה גנובה מספיקה כדי להתחבר ולסנכרן עותק. REQUIRE_DEVICE_EMAIL=true הופך את שליחת האימייל בעת התחברות ממכשיר חדש לחובה: אם Vaultwarden אינו יכול לשלוח אותו, ההתחברות נכשלת, כך שהתחברות ממכשיר לא מוכר לעולם לא תעבור ללא התראה. הגדרה זו דורשת SMTP תקין, אחרת כל התחברות ממכשיר חדש תידחה.

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

tar czf של תיקיית הנתונים, שנשמר בספריית הבית על אותו שרת VPS, מבטל את כל הצעדים שפורטו לעיל. ארכיון זה מכיל db.sqlite3 עם הטקסט המוצפן של כל משתמש, rsa_key.pem שמאפשר זיוף של סשנים להתחברות, ו־config.json עם אסימון הניהול וסיסמת ה־SMTP בטקסט גלוי. גישת קריאה לקובץ בודד זה שקולה לגישה מלאה לכספת.

שני כללים מכסים זאת. הוציאו את הארכיון מהשרת. הצפינו אותו לפני שהוא עוזב את המכונה.

קיימת גם בעיה של תקינות נתונים. העתקת db.sqlite3 באמצעות cp בזמן שהשירות פעיל עלולה להפיק קובץ שנמצא באמצע כתיבה ולא ייפתח, ולא תדעו זאת עד לשלב השחזור. השתמשו במקום זאת ב־snapshot המובנה של SQLite:

sqlite3 /vw-data/db.sqlite3 ".backup '/tmp/vw-db-backup.sqlite3'"

צד השחזור, שהוא החצי שאף אחד לא בודק, מכוסה בתוך מדריך הגיבוי והשחזור של Vaultwarden.

מה אתם מקריבים לעומת שירות Bitwarden מנוהל

חשבון נפש כנה. השירות המנוהל של Bitwarden מופעל על ידי אנשים שתפקידם המלא הוא לתפעל אותו, עם ביקורות צד-שלישי מפורסמות וצוות כוננות שזמין גם ב-3 לפנות בוקר. אירוח עצמי מחליף זאת בקצב עדכוני האבטחה שלכם.

Vaultwarden מפיצה תיקוני אבטחה כגרסאות רגילות, והן מגיעות לעיתים קרובות. בבדיקה שנערכה ב-7 באוקטובר 2026 מול ערוץ העדכונים של הפרויקט, הגרסה הנוכחית היא 1.37.4, שפורסמה ב-5 באוקטובר 2026. הערות השחרור שלה כוללות שבע התראות אבטחה, החמורה שבהן מדורגת כגבוהה, וממליצות בחום על עדכון בהקדם האפשרי. זוהי הגרסה הרביעית מאז 1.37.0 שיצאה ב-24 ביולי 2026: גרסה 1.37.1 הגיעה ב-29 ביולי, 1.37.2 ב-22 באוגוסט (נדרשת עבור לקוחות בגרסה 2026.8.0 ומעלה), ו-1.37.3 ב-13 בספטמבר, אשר מבטלת אסימוני "זכור אותי" של 2FA בעת שינוי אישורים או 2FA, ומגבילה את קצב הבקשות בנקודות הקצה של ה-prelogin וה-auth. אם אתם מנהלים ארגונים עם מנהלים שאינכם סומכים עליהם במלואם, הערות הגרסה 1.37.4 מציעות גם לרענן את מפתח ה-API של כל ארגון לאחר העדכון. מופע שהקמתם לפני שנה ושכחתם ממנו מריץ קוד בן שנה. התג latest לא עוזר בפני עצמו: מכולה (container) רצה שומרת על האימג' איתו היא התחילה עד שתריצו docker compose pull ותיצרו אותה מחדש. הגדירו עדכונים אוטומטיים ב-Ubuntu עבור חבילות המערכת המארחת, ושימו תזכורת ביומן לעדכון המכולה שבאמת תקראו.

המסקנה שקורא כנה צריך להסיק: הקריפטוגרפיה כאן היא התכנון של Bitwarden והיא עומדת במבחן, בעוד שהסיכון התפעולי עובר כולו אליכם. אם תעדכנו את המערכת ותגבו אותה במקום אחר, מופע Vaultwarden על שרת VPS שבשליטתכם הוא מקום סביר לשמור בו את הסיסמאות שלכם. אם שני הרגלים אלו לא יתקיימו, שלמו עבור השירות המנוהל והשקיעו את תשומת הלב שלכם במקום אחר. השוואה תכונה-אחר-תכונה נמצאת ב-Vaultwarden בהשוואה ל-Bitwarden באירוח עצמי.

הקשחת המארח שמתחת למכולה

Vaultwarden הוא תהליך אחד על גבי שרת Linux, ומשתמש root בשרת זה יכול לקרוא את /vw-data ללא קשר להגדרות היישום. הריצו את המכולה כמשתמש ללא הרשאות מיוחדות באמצעות user: "1000:1000" בקובץ ה-compose שלכם, ודאגו שהבעלות על תיקיית הנתונים תואמת לכך, ובצעו mount לכל מה שהמכולה אינה כותבת אליו כקריאה בלבד באמצעות :ro. לאחר מכן, נעלו את הדלת הראשית: הקשחת SSH בשרת VPS מכסה התחברות באמצעות מפתחות בלבד וביטול אימות באמצעות סיסמה, מה שמונע את מתקפות ה-brute force הפשוטות שעוקפות את כל האמצעים שצוינו לעיל.

FAQ

האם מישהו יכול לקרוא את הסיסמאות שלי אם הוא גונב את מסד הנתונים של Vaultwarden?

לא באופן ישיר. כל פריט בכספת מוצפן בצד הלקוח באמצעות מפתח שנגזר מסיסמת האב, לכן db.sqlite3 מכיל טקסט מוצפן בלבד. מה שהתוקף מקבל באופן מיידי הוא כתובת הדוא"ל של כל חשבון, הגדרות ה-KDF, מטא-נתונים של התחברויות ומכשירים, וכן סודות האימות הדו-שלבי בטבלה twofactor, המאוחסנים ללא הצפנה כיוון שהשרת נדרש לחשב את הקוד הצפוי. התוקף יכול גם לנסות לפצח את הטקסט המוצפן של הכספת במצב לא מקוון ללא הגבלת זמן, וזו הסיבה שאורך סיסמת האב הוא הגורם המכריע בתוצאה.

האם עליי להשתמש ב-ADMIN_TOKEN או להשבית את דף הניהול לחלוטין?

השביתו אותו אם ניתן, שכן רוב המופעים זקוקים לו פעם אחת בלבד כדי להגדיר SMTP ולהזמין משתמשים, ולאחר מכן אין בו צורך. כדי להשבית אותו, אל תגדירו את ADMIN_TOKEN או את DISABLE_ADMIN_TOKEN, הסירו כל מפתח "admin_token" מתוך config.json, ולאחר מכן צרו מחדש את ה-container. הסרת משתנה הסביבה בלבד אינה מספיקה, כיוון שהגדרות שנכתבו על ידי דף הניהול נשמרות ב-config.json וגוברות על הגדרות הסביבה. אם אתם בוחרים להשאיר את הדף, אחסנו את ה-token כ-Argon2 hash שנוצר על ידי vaultwarden hash במקום כמחרוזת טקסט פשוט, והגדירו את ADMIN_RATELIMIT_MAX_BURST=3.

ה-ADMIN_TOKEN שלי נכון אך הגישה ל-/admin נדחית. מה הבעיה?

כמעט תמיד מדובר ב-$ interpolation. מחרוזת Argon2 PHC מכילה כמה תווים מסוג $, ו-Docker Compose מפרש אותם כמשתנים בתוך בלוק docker-compose.yml environment:, לכן ה-container מקבל ערך משובש בעוד הקובץ שלכם נראה תקין. הכפילו כל $ ל-$$ בקובץ ה-compose, או העבירו את הערך לקובץ .env עטוף במירכאות בודדות, שם אין צורך ב-escaping. צרו מחדש את ה-container לאחר מכן, כיוון ששינויים במשתני סביבה אינם נקלטים בביצוע restart בלבד.

האם אני עדיין צריך לפתוח את פורט 3012 עבור התראות?

לא. התמיכה בתעבורת WebSocket בפורט 3012 הוסרה ב-Vaultwarden 1.31.0 כיוון שההתראות עברו לפורט ה-HTTP הראשי, והערכים WEBSOCKET_ENABLED ו-WEBSOCKET_PORT מתעלמים מהם מאז גרסה 1.29.0. ההגדרה הנוכחית היא ENABLE_WEBSOCKET, שהיא true כברירת מחדל. סגרו את פורט 3012 ב-firewall ומחקו אותו מקובץ ה-compose שלכם, ולאחר מכן ודאו שה-reverse proxy מעביר את ה-headers מסוג Upgrade ו-Connection, כיוון שזה מה שסנכרון בזמן אמת תלוי בו כעת.