SSD Nodes Learn Hosting plans →
راهنماها Matt Connorتوسط Matt Connor

آیا Vaultwarden امن است؟ راهنمای کامل ایمن‌سازی

امنیت Vaultwarden به دلیل رمزنگاری سمت کلاینت بالاست اما خطراتی مانند توکن ادمین و فایل‌های پشتیبان وجود دارد. با رعایت نکات امنیتی از نشت اطلاعات در سرور خود جلوگیری کنید.

آیا Vaultwarden امن است؟ پاسخ کوتاه

امنیت Vaultwarden در مهم‌ترین بخش تأمین شده است، زیرا هر آیتم موجود در vault پیش از رسیدن به سرور، روی دستگاه شما رمزنگاری می‌شود. سرور تنها داده‌های رمزنگاری‌شده‌ای (blobs) را ذخیره می‌کند که قادر به خواندن آن‌ها نیست. حتی اگر کسی کل پایگاه داده را کپی کند، برای استخراج هرگونه اطلاعات مفید، همچنان به master password نیاز خواهد داشت.

این پاسخ کوتاه، بخش بزرگی از مسئولیت امنیت را پوشش نمی‌دهد، زیرا نقاط ضعف معمولاً در بخش‌هایی است که شما پیکربندی می‌کنید. پنل مدیریتی که پشت یک توکن قابل حدس قرار دارد، پورت کانتینری که برای کل اینترنت باز شده است، یک config.json به صورت متن ساده (plaintext)، یا یک فایل پشتیبان tarball که در دایرکتوری home روی همان سرور رها شده است. هیچ‌کدام از این‌ها مشکلات رمزنگاری نیستند. تمام این موارد دلایلی هستند که باعث می‌شوند vaultهای خودمیزبان (self-hosted) تخلیه شوند.

تمام موارد زیر فرض را بر این می‌گذارند که یک نصب فعال دارید. اگر هنوز نصبی ندارید، ابتدا آن را با استفاده از راهنمای نصب Vaultwarden برای VPS انجام دهید، سپس بازگردید و این لیست را به ترتیب دنبال کنید.

سرور دقیقاً چه چیزی را ذخیره می‌کند

Vaultwarden مدل داده‌ای Bitwarden را پیاده‌سازی می‌کند. نام، نام کاربری، رمز عبور، یادداشت‌ها و URIهای یک آیتم در vault، پیش از ارسال هرگونه درخواست و در سمت کلاینت، با کلیدی که از رمز عبور اصلی شما مشتق شده، رمزنگاری می‌شوند. محتوای فایل‌های پیوست نیز به همین شیوه رمزنگاری می‌گردند. سرور داده‌های مبهمی را دریافت می‌کند که یک UUID (شناسه منحصربه‌فرد جهانی) به آن‌ها متصل است.

برخی موارد به صورت متن ساده (plaintext) هستند و باید دقیقاً بدانید کدام‌ها هستند:

  • آدرس ایمیل حساب کاربری شما، به صورت متن ساده.
  • تنظیمات KDF (تابع مشتق‌سازی کلید) و salt شما، زیرا کلاینت برای بازسازی کلید در ورود بعدی به آن‌ها نیاز دارد.
  • یک هش سمت سرور از هش رمز عبور اصلی که کلاینت ارسال می‌کند؛ این مورد برای احراز هویت خودِ ورود استفاده می‌شود.
  • متادیتا: عضویت در سازمان، نام دستگاه‌ها، زمان‌های آخرین ورود.
  • رمز (secret) روش احراز هویت دو مرحله‌ای که از ورود به Vaultwarden محافظت می‌کند. این مورد در جدول twofactor به صورت رمزنگاری‌نشده قرار دارد، زیرا سرور باید کد مورد انتظار را محاسبه کند تا با کد شما مقایسه نماید. این با رمز TOTP (رمز یک‌بارمصرف زمانی) که داخل یک آیتم vault ذخیره می‌کنید متفاوت است؛ آن رمز مانند هر فیلد دیگری رمزنگاری می‌شود.

پوشه داده‌ها کوچک است. در نصب Docker، این همان مسیری است که در /data mount کرده‌اید.

sudo ls -l /vw-data/

db.sqlite3 تقریباً تمام وضعیت (state) را در خود نگه می‌دارد. attachments/ فایل‌های آپلود شده را به ازای هر UUID ذخیره می‌کند و تنها دسته مهمی از داده‌هاست که در جداول دیتابیس قرار ندارد. sends/ پیوست‌های Send را نگه می‌دارد و ماهیت آن موقتی است. icon_cache/ قابل حذف است. rsa_key.pem و فایل‌های همراه آن، JWTهای (توکن‌های وب JSON) کاربران واردشده را امضا می‌کنند؛ بنابراین یک کپی از آن کلید خصوصی می‌تواند برای جعل نشست ورود به vault استفاده شود. config.json تنها زمانی ایجاد می‌شود که صفحه مدیریت (admin page) را فعال کنید و پروژه در مورد آن صریح است: این فایل توکن مدیریت و اعتبارنامه‌های SMTP شما را به صورت متن ساده نگه می‌دارد.

بنابراین مدل تهدید عملی، دسترسی به سیستم فایل است، نه رمزنگاری شبکه. دسترسی خواندن به آن دایرکتوری، آدرس ایمیل تمام کاربران، رمزهای 2FA ورود آن‌ها، کلیدی برای جعل نشست‌ها و یک کپی آفلاین از تمام vaultها برای حمله در فرصت مناسب را در اختیار مهاجم قرار می‌دهد. تمام مراحلی که در ادامه می‌آید برای دور نگه داشتن افراد از آن دایرکتوری است.

ابتدا توکن مدیریت را اصلاح کنید

/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 کاراکتر $ را به عنوان جای‌گذاری متغیر (variable interpolation) در نظر می‌گیرد. اگر آن را بدون escape کردن در یک بلوک environment: قرار دهید، مقداری که به کانتینر می‌رسد تغییر می‌کند و /admin توکنی که می‌دانید صحیح است را رد می‌کند. دو روش امن وجود دارد. در docker-compose.yml، هر $ را دو برابر کنید:

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

در یک فایل .env، نیازی به escape کردن نیست، اما از تک‌کوتیشن استفاده کنید:

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

سپس برای پنل محدودیت نرخ (rate limit) تعیین کنید و نشست آن را کوتاه‌تر کنید:

ADMIN_RATELIMIT_SECONDS=300
ADMIN_RATELIMIT_MAX_BURST=3
ADMIN_SESSION_LIFETIME=20

با سه تلاش ناموفق در عرض پنج دقیقه، پنل دیگر به آن کلاینت پاسخ نمی‌دهد. نشست مدیریت پس از 20 دقیقه عدم فعالیت منقضی می‌شود.

بهتر از همه این‌ها: صفحه را خاموش کنید. اکثر نمونه‌ها فقط یک بار به آن نیاز دارند تا SMTP را پیکربندی کنند و اولین کاربران را دعوت کنند، و دیگر هرگز به آن نیاز نخواهند داشت. برای غیرفعال کردن آن، نه ADMIN_TOKEN و نه DISABLE_ADMIN_TOKEN را تنظیم نکنید، هر کلید "admin_token" را از config.json حذف کنید و سپس کانتینر را دوباره ایجاد کنید. حذف کلید از فایل اهمیت دارد، زیرا صفحه مدیریت تنظیمات را در آنجا می‌نویسد و آنچه در config.json است بر متغیرهای محیطی (environment) اولویت دارد. حذف کردن متغیر به تنهایی باعث باز ماندن صفحه می‌شود.

بستن ثبت‌نام پیش از آنکه کسی دامنه را پیدا کند

SIGNUPS_ALLOWED=false
SIGNUPS_VERIFY=true
SHOW_PASSWORD_HINT=false

SIGNUPS_ALLOWED به‌صورت پیش‌فرض روی true تنظیم شده است. اگر آن را به همین حالت رها کنید، هر کسی که به دامنه شما دسترسی پیدا کند می‌تواند یک حساب کاربری بسازد و داده‌هایش در همان db.sqlite3 شما ذخیره خواهد شد. آن را روی false قرار دهید و کاربران را از طریق دعوت‌نامه در صفحه مدیریت اضافه کنید؛ این کار نیازمند تنظیم صحیح SMTP است. INVITATIONS_ALLOWED نیز به‌صورت پیش‌فرض true است و به مالکان سازمان اجازه می‌دهد دیگران را دعوت کنند. این حالت زمانی که به کاربران خود اعتماد دارید مناسب است و در یک نمونه تک‌کاربره باید false باشد. اگر فقط دامنه‌های خاصی مجاز به ثبت‌نام هستند، SIGNUPS_DOMAINS_WHITELIST=example.com محدودتر از ثبت‌نام آزاد است اما امنیت آن بسیار کمتر از دعوت‌نامه‌هاست.

SHOW_PASSWORD_HINT به‌صورت پیش‌فرض false است و باید همین‌طور باقی بماند. با فعال بودن آن، وارد کردن یک آدرس ایمیل معتبر در فرم ورود، راهنمای رمز عبور اصلی (master password hint) آن حساب را نمایش می‌دهد که هم باعث افشای راهنما می‌شود و هم وجود آن آدرس ایمیل را تأیید می‌کند.

اگر نمونه شما برای مدتی با ثبت‌نام باز اجرا شده است، پیش از آنکه فرض کنید تنها کاربر آن هستید، صفحه مدیریت را باز کرده و لیست کاربران را بررسی کنید.

پورتی که قصد انتشار آن را نداشتید

ایمیج Docker داخل کانتینر روی پورت 80 گوش می‌دهد. نصب روی سیستم عامل (bare-metal) به‌صورت پیش‌فرض از ROCKET_PORT=8000 استفاده می‌کند. دستور اجرای مستندسازی‌شده، آن را به این شکل منتشر می‌کند:

--publish 127.0.0.1:8000:80

پیشوند 127.0.0.1: تمام هدف این بخش است. اگر به‌جای آن -p 8000:80 بنویسید، Docker آن را به 0.0.0.0 متصل (bind) می‌کند و این کار را با نوشتن قوانین DNAT (ترجمه آدرس شبکه مقصد) در جدول nat انجام می‌دهد. این قوانین پیش از زنجیره‌های filter که توسط ufw مدیریت می‌شوند ارزیابی می‌گردند؛ بنابراین ufw status وضعیت پورت را مسدود (denied) گزارش می‌دهد، در حالی که پورت همچنان به درخواست‌های اینترنت پاسخ می‌دهد. مطالعه مکانیزم کامل این موضوع در راهنمای دور زدن ufw توسط پورت‌های Docker ارزشمند است.

بررسی کنید چه چیزی واقعاً در حال گوش دادن است:

sudo ss -tlnp | grep 8000

نتیجه سالم، یک خط واحد است که به 127.0.0.1:8000 متصل شده باشد. خطی که به 0.0.0.0:8000 متصل باشد به این معنی است که vault مستقیماً در معرض اینترنت قرار دارد. نگاشت (mapping) را اصلاح کنید و سپس کانتینر را دوباره بسازید، زیرا اتصال پورت در زمان ایجاد کانتینر تعیین می‌شود و docker compose restart آن را تغییر نخواهد داد:

docker compose up -d --force-recreate

یک پورت دیگر در راهنماهای قدیمی باقی مانده است: 3012، که پورت جداگانه WebSocket است. پشتیبانی از آن در نسخه 1.31.0 از Vaultwarden حذف شد، زیرا ترافیک اعلان‌ها (notification) به پورت اصلی HTTP منتقل شده است. WEBSOCKET_ENABLED و WEBSOCKET_PORT از نسخه 1.29.0 نادیده گرفته می‌شوند. سوئیچ فعلی ENABLE_WEBSOCKET است که به‌صورت پیش‌فرض روی true تنظیم شده است. اگر فایروال یا فایل compose شما هنوز پورت 3012 را باز نگه داشته است، آن را ببندید.

پایان‌دهی TLS در reverse proxy، نه در Rocket

Vaultwarden می‌تواند TLS (امنیت لایه انتقال) را مستقیماً از طریق Rocket، که فریم‌ورک وب آن است، ارائه دهد؛ اما مستندات پروژه توصیه می‌کنند در محیط production این کار را انجام ندهید. قابلیت TLS داخلی Rocket فاقد پشتیبانی دقیق از SNI (نشان‌گر نام سرور) است. به همین دلیل است که توصیه امنیتی بر این است که همیشه از طریق نام دامنه (hostname) به نمونه خود دسترسی پیدا کنید و هرگز از آدرس IP خام استفاده نکنید. محدوده‌های IP عمومی دائماً اسکن می‌شوند و vaultای که به آدرس IP پاسخ می‌دهد، vaultای است که کشف خواهد شد.

بخش‌های مهم یک server block در 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 هیچ چیزی ثبت نمی‌کند. هدرهای Upgrade و Connection وظیفه انتقال handshake مربوط به WebSocket به /notifications/hub را بر عهده دارند. اگر آن‌ها را حذف کنید، vault همچنان کار می‌کند، اما تغییرات تا زمانی که صفحه را به‌صورت دستی رفرش نکنید، در سایر دستگاه‌های شما ظاهر نمی‌شوند.

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 حتماً این هدر را تنظیم کند. اگر این کار انجام نشود، تمام خطوط لاگ و محدودیت‌های نرخ ورود (login rate limit) آدرس 127.0.0.1، یعنی همان proxy، را مشاهده می‌کنند. این بدان معناست که شکست‌های یک مهاجم به پای تمام کاربران نمونه شما نوشته می‌شود. مقدار DOMAIN را نیز روی URL واقعی https تنظیم کنید، زیرا Vaultwarden لینک‌های دعوت و بازنشانی رمز عبور را بر اساس آن می‌سازد و کلیدهای امنیتی WebAuthn نیز به همان origin متصل هستند.

یک جزئیات که اغلب نادیده گرفته می‌شود: اتصال WebSocket توکن نشست (session token) را در query string و به عنوان /notifications/hub?access_token=[JWT] ارسال می‌کند. این مقدار به‌صورت متن آشکار در لاگ دسترسی proxy شما ثبت می‌شود. پارامتر access_token را در فرمت لاگ حذف (redact) کنید یا اطمینان حاصل کنید که این لاگ‌ها به جایی که تحت کنترل شما نیست، ارسال نمی‌شوند.

مسدودسازی حملات brute force در endpoint ورود

محدودیت‌های نرخ (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/... داخل container. دومین علت رایج، نبود X-Real-IP است که باعث می‌شود هر مسدودسازی، proxy خودتان را هدف قرار دهد. باقی تنظیمات، از جمله jail مربوط به SSH که باید از قبل فعال کرده باشید، در راهنمای fail2ban برای Ubuntu 24.04 موجود است.

رمز عبور اصلی همچنان کل سیستم است

رمزنگاری سمت کلاینت به این معناست که رمز عبور اصلی، همان کلید است. یک رمز عبور اصلی کوتاه روی نمونه‌ای که مهاجم پایگاه‌داده آن را کپی کرده است، با هیچ‌کدام از موارد این نوشته محافظت نمی‌شود؛ زیرا آن‌ها به آن کپی به‌صورت آفلاین و با هر سرعتی که سخت‌افزارشان اجازه دهد، حمله می‌کنند. هیچ تنظیماتی در سرور به ماشین شخصی مهاجم دسترسی ندارد.

PASSWORD_ITERATIONS=600000 به‌راحتی ممکن است اشتباه برداشت شود. این گزینه تعداد تکرارها (iterations) را برای هش سمت سرور از هش ورود که کلاینت ارسال می‌کند، تعیین می‌کند و قالب پیکربندی پروژه می‌گوید که مقدار تغییریافته در ورود بعدی کاربران اعمال می‌شود. این گزینه به KDF سمت کلاینت دست نمی‌زند؛ همان تنظیمی که تعیین می‌کند حمله آفلاین به vault چقدر هزینه‌بر باشد. آن تنظیم متعلق به هر حساب کاربری است: کسی که سال‌ها پیش ثبت‌نام کرده است، ممکن است همچنان از تنظیمات KDF قدیمی و پایین‌تر استفاده کند، مگر اینکه آن را در تنظیمات امنیتی web vault افزایش دهد که باعث رمزنگاری مجدد کلید او می‌شود. به آن‌ها اطلاع دهید، زیرا سرور نمی‌تواند این کار را برایشان انجام دهد.

سپس احراز هویت دو مرحله‌ای را برای هر حساب فعال کنید. این کار از متن رمزنگاری‌شده (ciphertext) محافظت نمی‌کند، زیرا کلید vault فقط از رمز عبور اصلی به دست می‌آید. اما این کار باعث می‌شود که یک رمز عبور سرقت‌شده برای ورود و همگام‌سازی یک کپی کافی نباشد. REQUIRE_DEVICE_EMAIL=true ارسال ایمیل ورود دستگاه جدید را اجباری می‌کند: اگر Vaultwarden نتواند آن را ارسال کند، ورود با شکست مواجه می‌شود؛ بنابراین ورود از یک دستگاه ناشناس هرگز بدون اطلاع باقی نمی‌ماند. این قابلیت به SMTP فعال نیاز دارد، در غیر این صورت ورود هر دستگاه جدید رد خواهد شد.

پشتیبان‌گیری؛ جایی که مخازن self-hosted دچار مشکل می‌شوند

یک tar czf از پوشهٔ داده‌ها که در دایرکتوری home روی همان VPS باقی بماند، تمام اقدامات امنیتی پیشین را بی‌اثر می‌کند. آن آرشیو حاوی db.sqlite3 با متن رمزنگاری‌شدهٔ تمام کاربران، rsa_key.pem که نشست‌های ورود را جعل می‌کند، و config.json با توکن مدیر و رمز عبور SMTP به صورت متن ساده (plaintext) است. دسترسی خواندن به آن یک فایل، به معنای دسترسی خواندن به کل مخزن است.

دو قانون برای این موضوع وجود دارد: آرشیو را از سرور خارج کنید و پیش از خروج، آن را رمزنگاری کنید.

یک مشکل صحت‌سنجی نیز وجود دارد. کپی کردن db.sqlite3 با cp در حالی که سرویس در حال اجراست، ممکن است فایلی ایجاد کند که در میانهٔ نوشتن بوده و باز نشود؛ و شما تا زمان بازیابی (restore) متوجه این موضوع نخواهید شد. به‌جای آن از قابلیت snapshot خودِ SQLite استفاده کنید:

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

بخش بازیابی، که نیمه‌ای است که هیچ‌کس آن را تست نمی‌کند، در راهنمای پشتیبان‌گیری و بازیابی Vaultwarden پوشش داده شده است.

آنچه در مقایسه با سرویس میزبانی‌شده Bitwarden از دست می‌دهید

حساب‌وکتاب صادقانه. سرویس میزبانی‌شده Bitwarden توسط افرادی اداره می‌شود که شغل تمام‌وقتشان مدیریت آن است؛ این سرویس دارای ممیزی‌های شخص ثالث منتشرشده است و در ساعت 3 بامداد نیز کسی برای پاسخگویی در دسترس است. در حالت self-hosting، شما این مزایا را با برنامهٔ به‌روزرسانی خودتان جایگزین می‌کنید.

Vaultwarden اصلاحات امنیتی را در قالب releaseهای معمولی ارائه می‌دهد و این به‌روزرسانی‌ها مکرر هستند. طبق بررسی انجام‌شده در تاریخ 7 اکتبر 2026 در فید انتشار پروژه، نسخه فعلی 1.37.4 است که در 5 اکتبر 2026 منتشر شده است. یادداشت‌های این نسخه شامل هفت توصیه امنیتی است که شدیدترین آن‌ها دارای رتبه High بوده و قویاً توصیه می‌کند در اسرع وقت به‌روزرسانی انجام شود. این چهارمین نسخه از زمان انتشار 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 هر سازمان را تغییر دهید (rotate کنید). نمونه‌ای که یک سال پیش راه‌اندازی کرده و فراموش کرده‌اید، کدی یک‌ساله را اجرا می‌کند. تگ latest به‌تنهایی کمکی نمی‌کند: کانتینر در حال اجرا، ایمیجی را که با آن شروع شده حفظ می‌کند تا زمانی که دستور docker compose pull را اجرا کرده و آن را دوباره بسازید. برای بسته‌های میزبان، ارتقاهای خودکار در Ubuntu را فعال کنید و به‌روزرسانی کانتینر را در یادآور تقویمی قرار دهید که واقعاً آن را می‌خوانید.

نتیجه‌گیری که یک خواننده صادق باید بگیرد: رمزنگاری در اینجا طراحی Bitwarden است و کاملاً قابل‌اتکا است، اما ریسک عملیاتی کاملاً به عهده شما منتقل می‌شود. اگر آن را به‌روز نگه دارید و در جای دیگری از آن نسخه پشتیبان تهیه کنید، یک نمونه Vaultwarden روی VPS تحت کنترل شما، مکانی معقول برای نگهداری رمزهای عبور است. اگر قرار نیست این دو عادت را رعایت کنید، هزینه سرویس میزبانی‌شده را بپردازید و توجه خود را صرف کارهای دیگر کنید. مقایسه ویژگی‌به‌ویژگی در مقایسه Vaultwarden با Bitwarden خودمیزبان موجود است.

ایمن‌سازی میزبان زیرین کانتینر

Vaultwarden تنها یک پردازش روی سیستم‌عامل Linux است و کاربر root روی آن سیستم می‌تواند /vw-data را فارغ از تنظیمات داخلی برنامه بخواند. کانتینر را با استفاده از یک کاربر بدون امتیاز (unprivileged) و با تنظیم user: "1000:1000" در فایل compose اجرا کنید؛ مالکیت پوشه داده‌ها را نیز مطابق با آن تنظیم نمایید. هر فایلی که کانتینر نیازی به نوشتن در آن ندارد را با استفاده از :ro به صورت فقط‌خواندنی (read-only) mount کنید. سپس درب ورودی را ببندید: ایمن‌سازی SSH روی VPS به موضوع ورود فقط با کلید و غیرفعال‌سازی احراز هویت با رمز عبور می‌پردازد؛ این همان اقدامی است که حملات رایج و ساده‌ای را که از سد موارد فوق عبور می‌کنند، متوقف می‌سازد.

FAQ

آیا اگر کسی دیتابیس Vaultwarden را سرقت کند، می‌تواند رمزهای عبور مرا بخواند؟

نه مستقیماً. هر آیتم موجود در vault در سمت کلاینت با کلیدی که از رمز عبور اصلی (master password) مشتق شده، رمزنگاری می‌شود؛ بنابراین db.sqlite3 فقط شامل متن رمزنگاری‌شده (ciphertext) است. آنچه مهاجم بلافاصله به دست می‌آورد، آدرس ایمیل هر حساب، تنظیمات KDF، متادیتای ورود و دستگاه، و همچنین کدهای احراز هویت دو مرحله‌ای در جدول twofactor است. این موارد به‌صورت رمزنگاری‌نشده ذخیره می‌شوند، زیرا سرور باید کد مورد انتظار را محاسبه کند. مهاجم می‌تواند متن رمزنگاری‌شدهٔ vault را به‌صورت آفلاین و برای هر مدتی که بخواهد مورد حمله قرار دهد؛ به همین دلیل است که طول رمز عبور اصلی، تعیین‌کنندهٔ امنیت نهایی است.

آیا باید از ADMIN_TOKEN استفاده کنم یا صفحهٔ مدیریت را کاملاً غیرفعال کنم؟

اگر می‌توانید، آن را غیرفعال کنید؛ زیرا اکثر نمونه‌ها (instances) فقط یک‌بار برای پیکربندی SMTP و دعوت از کاربران به آن نیاز دارند و پس از آن دیگر نیازی به آن نیست. برای غیرفعال کردن، نه ADMIN_TOKEN و نه DISABLE_ADMIN_TOKEN را تنظیم نکنید، هرگونه کلید "admin_token" را از config.json حذف کنید و سپس کانتینر را دوباره ایجاد (recreate) کنید. حذف کردن متغیر محیطی (environment variable) به‌تنهایی کافی نیست، زیرا تنظیماتی که توسط صفحهٔ مدیریت نوشته شده‌اند در config.json قرار دارند و اولویت بالاتری دارند. اگر صفحه را نگه می‌دارید، توکن را به‌جای یک رشتهٔ متنی ساده، به‌عنوان یک هش Argon2 تولیدشده توسط vaultwarden hash ذخیره کنید و ADMIN_RATELIMIT_MAX_BURST=3 را تنظیم نمایید.

توکن ADMIN_TOKEN من درست است اما مسیر /admin آن را رد می‌کند. مشکل چیست؟

تقریباً همیشه مشکل از جای‌گذاری (interpolation) در $ است. یک رشتهٔ Argon2 PHC حاوی چندین کاراکتر $ است و Docker Compose آن‌ها را به‌عنوان متغیر در داخل بلوک docker-compose.yml environment: بسط می‌دهد؛ در نتیجه کانتینر یک مقدار ناقص دریافت می‌کند، در حالی که فایل شما درست به نظر می‌رسد. در فایل compose، هر $ را به $$ تبدیل کنید (دوبرابر کنید)، یا مقدار را به یک فایل .env منتقل کرده و آن را داخل کوتیشن تکی قرار دهید که در آن نیازی به escape کردن نیست. پس از آن کانتینر را دوباره ایجاد کنید، زیرا تغییرات محیطی با یک restart ساده اعمال نمی‌شوند.

آیا هنوز نیاز است پورت 3012 را برای اعلان‌ها (notifications) باز بگذارم؟

خیر. پشتیبانی از ترافیک WebSocket روی پورت 3012 در نسخهٔ 1.31.0 از Vaultwarden حذف شد، زیرا اعلان‌ها به پورت اصلی HTTP منتقل شدند و WEBSOCKET_ENABLED و WEBSOCKET_PORT از نسخهٔ 1.29.0 نادیده گرفته می‌شوند. تنظیم فعلی ENABLE_WEBSOCKET است که به‌صورت پیش‌فرض true می‌باشد. پورت 3012 را در فایروال ببندید و آن را از فایل compose خود حذف کنید؛ سپس مطمئن شوید که reverse proxy شما هدرهای Upgrade و Connection را فوروارد می‌کند، زیرا همگام‌سازی بلادرنگ (real-time sync) اکنون واقعاً به این موارد وابسته است.