عنوان:

‫چالش‌های متداول توسعه‌دهندگان ASP.NET Core هنگام استفاده از Nginx - قسمت چهارم - امنیت و SSL/TLS


نویسنده: وحید نصیری
تاریخ: ۱۴۰۴/۰۴/۱۰ ۰۸:۱۰
آدرس: www.dntips.ir
تا اینجا، ما یک برنامه پایدار داریم که پشت یک Reverse Proxy بهینه کار می‌کند. اما یک مشکل بزرگ و غیرقابل چشم‌پوشی وجود دارد: تمام ترافیک بین کاربران و سرور ما به صورت متن ساده (Plain Text) و روی پروتکل HTTP رد و بدل می‌شود. این به معنای آن است که هر کسی در میانه راه می‌تواند اطلاعات را شنود کند، آن‌ها را تغییر دهد و هویت سرور ما را جعل کند. در این قسمت، این حفره امنیتی بزرگ را با پیاده‌سازی HTTPS می‌بندیم. ما با استفاده از Let's Encrypt یک گواهی SSL/TLS رایگان و معتبر دریافت می‌کنیم و با ابزار Certbot، فرآیند نصب و تمدید آن را کاملاً خودکار می‌کنیم. در پایان این فصل، سایت شما دارای قفل سبز رنگ اعتماد در مرورگرها خواهد بود.

بخش ۱: پیاده‌سازی HTTPS با Let's Encrypt و Certbot
Let's Encrypt یک مرجع صدور گواهی (CA) رایگان، خودکار و باز است. Certbot ابزاری است که فرآیند دریافت، نصب و تمدید گواهی از Let's Encrypt را بسیار ساده می‌کند.
پیش‌نیازهای ضروری:
  • یک دامنه ثبت شده: شما باید مالک یک دامنه باشید (مثلاً your-domain.com).
  • تنظیمات DNS: رکورد A دامنه شما (و ساب‌دامین www) باید به آدرس IP عمومی سرور شما اشاره کند. Certbot برای تایید مالکیت شما، از طریق این دامنه به سرور شما متصل می‌شود.
  • پیکربندی Nginx: کانفیگ Nginx که در فصل قبل ساختیم، باید برای دامنه شما روی پورت 80 به درستی کار کند.

قدم ۱: نصب Certbot
Certbot و پلاگین مخصوص Nginx آن را روی سرور اوبونتو نصب می‌کنیم.
sudo apt update
sudo apt install certbot python3-certbot-nginx

قدم ۲: دریافت و نصب گواهی SSL
اکنون، با یک دستور ویژه، Certbot تمام کارها را برای ما انجام می‌دهد. دامنه خود را جایگزین your-domain.com کنید.
# -d برای مشخص کردن دامنه‌هاست. می‌توانید چند دامنه را مشخص کنید.
sudo certbot --nginx -d your-domain.com -d www.your-domain.com

مراحل تعاملی Certbot:
  • ایمیل: از شما یک آدرس ایمیل برای اطلاع‌رسانی‌های ضروری (مانند نزدیک شدن به تاریخ انقضای گواهی) می‌خواهد.
  • شرایط سرویس: باید با شرایط سرویس Let's Encrypt موافقت کنید.
  • خبرنامه: از شما می‌پرسد که آیا مایل به اشتراک در خبرنامه هستید یا خیر (اختیاری).

مهم‌ترین سوال Certbot:
سپس Certbot از شما می‌پرسد که آیا می‌خواهید تمام ترافیک HTTP به صورت خودکار به HTTPS ریدایرکت شود.
Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: No redirect - Make no further changes to the webserver configuration.
2: Redirect - Make all requests redirect to secure HTTPS access.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel):
گزینه ۲ (Redirect) را انتخاب کنید. این بهترین روش امنیتی است و تضمین می‌کند که هیچ کاربری به نسخه ناامن سایت شما دسترسی نخواهد داشت.
پس از این مرحله، Certbot به صورت خودکار فایل کانفیگ Nginx شما را ویرایش کرده، گواهی‌ها را نصب و Nginx را Reload می‌کند. سایت شما اکنون از طریق https://your-domain.com در دسترس است!

بخش ۲: تحلیل تغییرات و عیب‌یابی مشکلات رایج
کانفیگ جدید Nginx شما چه شکلی شده است؟
اگر فایل /etc/nginx/sites-available/kestrel-mywebapp را باز کنید، می‌بینید که Certbot آن را به شکل زیر تغییر داده است:
server {
    server_name your-domain.com www.your-domain.com;

    location / {
        # ... تنظیمات پراکسی شما
    }

    # این خطوط توسط Certbot اضافه شده‌اند
    listen [::]:443 ssl ipv6only=on; # مدیریت شده توسط Certbot
    listen 443 ssl; # مدیریت شده توسط Certbot
    ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem; # مدیریت شده توسط Certbot
    ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem; # مدیریت شده توسط Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # مدیریت شده توسط Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # مدیریت شده توسط Certbot
}

server {
    if ($host = www.your-domain.com) {
        return 301 https://$host$request_uri;
    } # مدیریت شده توسط Certbot

    if ($host = your-domain.com) {
        return 301 https://$host$request_uri;
    } # مدیریت شده توسط Certbot

    listen 80;
    listen [::]:80;
    server_name your-domain.com www.your-domain.com;
    return 404; # مدیریت شده توسط Certbot
}
همانطور که می‌بینید، یک بلاک server برای پورت 443 (HTTPS) با مسیر گواهی‌ها ایجاد شده و بلاک قبلی پورت 80 (HTTP) اکنون تمام درخواست‌ها را به نسخه HTTPS ریدایرکت می‌کند.

مشکل شماره ۱: گواهی من ۳ ماه دیگر منقضی می‌شود، چه کار کنم؟
  • علت: گواهی‌های Let's Encrypt فقط ۹۰ روز اعتبار دارند تا فرآیند خودکارسازی تشویق شود.
  • راه‌حل: هیچ کاری لازم نیست انجام دهید! پکیج Certbot به صورت خودکار یک systemd timer یا cron job روی سیستم شما تنظیم می‌کند که دو بار در روز اجرا شده و گواهی‌هایی که نزدیک به تاریخ انقضا هستند را به صورت خودکار تمدید می‌کند.
  • برای اطمینان خاطر: می‌توانید فرآیند تمدید را شبیه‌سازی کنید (بدون اینکه واقعاً گواهی را تمدید کند).
sudo certbot renew --dry-run
  • اگر این دستور بدون خطا اجرا شد، تمدید خودکار نیز به درستی کار خواهد کرد.

مشکل شماره ۲: مرورگرم خطای "Mixed Content" نمایش می‌دهد.
  • علت: صفحه اصلی سایت شما از طریق HTTPS بارگذاری شده، اما برخی از منابع آن (یک تصویر، یک فایل CSS یا JS) با آدرس http:// فراخوانی شده‌اند.
  • راه‌حل: مطمئن شوید هدر X-Forwarded-Proto که در فصل قبل تنظیم کردیم، وجود دارد. این کار اکثر لینک‌های سمت سرور را اصلاح می‌کند.
  • در کدهای سمت کلاینت (HTML, JS)، آدرس‌های http:// را به https:// تغییر دهید یا از آدرس‌های نسبی (/images/logo.png) یا پروتکل-نسبی (//example.com/logo.png) استفاده کنید.

مشکل شماره ۳: چگونه امنیت Nginx را فراتر از SSL ببرم؟
  • راه‌حل: چند هدر امنیتی ساده اما مؤثر را به بلاک server پورت 443 خود اضافه کنید:
server {
    listen 443 ssl;
    server_name your-domain.com;

    # ... مسیر گواهی‌ها

    # جلوگیری از نمایش سایت در یک iframe در سایت‌های دیگر (Clickjacking)
    add_header X-Frame-Options "SAMEORIGIN";
    # جلوگیری از حملات MIME-type sniffing
    add_header X-Content-Type-Options "nosniff";
    # فعال کردن حفاظت XSS در مرورگرهای سازگار
    add_header X-XSS-Protection "1; mode=block";

    location / {
        # ...
    }
}
  • همچنین برای مخفی کردن نسخه Nginx، فایل /etc/nginx/nginx.conf را باز کرده و در بلاک http خط زیر را اضافه (یا uncomment) کنید: server_tokens off;

مشکل شماره ۴: پورت Kestrel هنوز از بیرون قابل دسترس است!
  • علت: این یک اشتباه امنیتی بزرگ است. ترافیک باید مجبور شود که از طریق Nginx عبور کند تا تمام قوانین امنیتی ما اعمال شوند.
  • راه‌حل: فایروال سرور را طوری تنظیم کنید که فقط به Nginx اجازه عبور دهد.
# اجازه به ترافیک رمزنگاری شده و استاندارد وب
sudo ufw allow 'Nginx Full'

# بستن دسترسی مستقیم به پورت برنامه (مثلا 5000)
sudo ufw deny 5000

# اگر فایروال غیرفعال است، آن را فعال کنید
sudo ufw enable

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