Let's Go بهبودهای سرور و امنیت › اجرای سرور HTTPS
قبلی · فهرست · بعدی
فصل ۹.۴.

اجرای سرور HTTPS

حالا که یک گواهی TLS خودامضا و کلید خصوصی مربوطه داریم، راه‌اندازی یک سرور وب HTTPS ساده است — فقط باید فایل main.go را باز کنیم و متد srv.ListenAndServe() را با srv.ListenAndServeTLS() جایگزین کنیم.

فایل main.go خود را مطابق کد زیر تغییر دهید:

File: cmd/web/main.go
package main

...

func main() {
    addr := flag.String("addr", ":4000", "HTTP network address")
    dsn := flag.String("dsn", "web:pass@/snippetbox?parseTime=true", "MySQL data source name")
    flag.Parse()

    logger := slog.New(slog.NewTextHandler(os.Stdout, nil))

    db, err := openDB(*dsn)
    if err != nil {
        logger.Error(err.Error())
        os.Exit(1)
    }
    defer db.Close()

    templateCache, err := newTemplateCache()
    if err != nil {
        logger.Error(err.Error())
        os.Exit(1)
    }

    formDecoder := form.NewDecoder()

    sessionManager := scs.New()
    sessionManager.Store = mysqlstore.New(db)
    sessionManager.Lifetime = 12 * time.Hour
    // Make sure that the Secure attribute is set on our session cookies.
    // Setting this means that the cookie will only be sent by a user's web
    // browser when a HTTPS connection is being used (and won't be sent over an
    // unsecure HTTP connection).
    sessionManager.Cookie.Secure = true

    app := &application{
        logger:         logger,
        snippets:       &models.SnippetModel{DB: db},
        templateCache:  templateCache,
        formDecoder:    formDecoder,
        sessionManager: sessionManager,
    }

    srv := &http.Server{
        Addr:     *addr,
        Handler:  app.routes(),
        ErrorLog: slog.NewLogLogger(logger.Handler(), slog.LevelError),
    }

    logger.Info("starting server", "addr", srv.Addr)
    
    // Use the ListenAndServeTLS() method to start the HTTPS server. We
    // pass in the paths to the TLS certificate and corresponding private key as
    // the two parameters.
    err = srv.ListenAndServeTLS("./tls/cert.pem", "./tls/key.pem")
    logger.Error(err.Error())
    os.Exit(1)
}

...

وقتی این را اجرا می‌کنیم، سرور ما همچنان روی پورت ۴۰۰۰ گوش می‌دهد — تنها تفاوت این است که اکنون به جای HTTP از HTTPS استفاده می‌کند.

بروید و آن را به صورت عادی اجرا کنید:

$ cd $HOME/code/snippetbox
$ go run ./cmd/web
time=2024-03-18T11:29:23.000+00:00 level=INFO msg="starting server" addr=:4000

اگر مرورگر وب خود را باز کنید و به https://localhost:4000/ مراجعه کنید، احتمالاً یک هشدار مرورگر دریافت خواهید کرد زیرا گواهی TLS خودامضا است، مشابه اسکرین‌شات زیر.

09.02-01.png

پس از آن صفحه اصلی برنامه باید ظاهر شود (اگرچه هنوز یک هشدار در نوار URL خواهد داشت).

در Firefox، باید چیزی شبیه به این باشد:

09.02-02.png

اگر از Firefox استفاده می‌کنید، توصیه می‌کنم Ctrl+i را فشار دهید تا اطلاعات صفحه را برای صفحه اصلی خود بررسی کنید:

09.02-03.png

بخش ‘Security > Technical Details’ در اینجا تأیید می‌کند که اتصال ما رمزگذاری شده و همان‌طور که انتظار می‌رود کار می‌کند.

در مورد من، می‌توانم ببینم که از نسخه TLS 1.3 استفاده می‌شود و cipher suite برای اتصال HTTPS من TLS_AES_128_GCM_SHA256 است. در فصل بعدی بیشتر در مورد cipher suite صحبت خواهیم کرد.


اطلاعات تکمیلی

درخواست‌های HTTP

مهم است که توجه داشته باشید سرور HTTPS ما فقط از HTTPS پشتیبانی می‌کند. اگر سعی کنید یک درخواست HTTP معمولی به آن ارسال کنید، سرور به کاربر یک وضعیت 400 Bad Request و پیام "Client sent an HTTP request to an HTTPS server" ارسال می‌کند. هیچ چیزی لاگ نخواهد شد.

$ curl -i http://localhost:4000/
HTTP/1.0 400 Bad Request

Client sent an HTTP request to an HTTPS server.

اتصال‌های HTTP/2

یک مزیت بزرگ استفاده از HTTPS این است که Go به طور خودکار اتصال را به HTTP/2 ارتقا می‌دهد اگر کلاینت از آن پشتیبانی کند.

این خوب است چون به این معنی است که در نهایت، صفحات ما برای کاربران سریع‌تر بارگذاری می‌شوند. اگر با HTTP/2 آشنا نیستید، می‌توانید یک مرور کلی از اصول اولیه و طعمی از نحوه پیاده‌سازی آن در پشت صحنه در Go را در این سخنرانی GoSF توسط Brad Fitzpatrick دریافت کنید.

اگر از نسخه به‌روز Firefox استفاده می‌کنید، باید بتوانید این را در عمل ببینید. Ctrl+Shift+E را فشار دهید تا Developer Tools باز شود، و اگر به هدرهای صفحه اصلی نگاه کنید، باید ببینید که پروتکل استفاده شده HTTP/2 است.

09.02-04.png

مجوزهای گواهی

مهم است که توجه داشته باشید کاربری که برای اجرای برنامه Go خود استفاده می‌کنید باید مجوز خواندن برای هر دو فایل cert.pem و key.pem داشته باشد، در غیر این صورت ListenAndServeTLS() یک خطای permission denied برمی‌گرداند.

به طور پیش‌فرض، ابزار generate_cert.go مجوز خواندن را برای همه کاربران برای فایل cert.pem اعطا می‌کند اما مجوز خواندن را فقط برای مالک فایل key.pem اعطا می‌کند. در مورد من مجوزها به این صورت هستند:

$ cd $HOME/code/snippetbox/tls
$ ls -l
total 8
-rw-rw-r-- 1 alex alex 1090 Mar 18 16:24 cert.pem
-rw------- 1 alex alex 1704 Mar 18 16:24 key.pem

به طور کلی، ایده خوبی است که مجوزهای کلیدهای خصوصی خود را تا حد امکان محدود نگه دارید و اجازه دهید فقط توسط مالک یا یک گروه خاص خوانده شوند.

کنترل نسخه

اگر از یک سیستم کنترل نسخه (مانند Git یا Mercurial) استفاده می‌کنید، ممکن است بخواهید یک قانون ignore اضافه کنید تا محتوای دایرکتوری tls به طور تصادفی commit نشود. با Git، به عنوان مثال:

$ cd $HOME/code/snippetbox
$ echo 'tls/' >> .gitignore