پیکربندی تنظیمات HTTPS
Go تنظیمات پیشفرض خوبی برای سرور HTTPS خود دارد، اما امکان بهینهسازی و سفارشیسازی نحوه رفتار سرور وجود دارد.
یک تغییر که تقریباً همیشه ایده خوبی است، محدود کردن منحنیهای بیضوی است که ممکن است در طول handshake TLS استفاده شوند. Go از چند منحنی بیضوی پشتیبانی میکند، اما از Go 1.23 فقط tls.CurveP256 و tls.X25519 پیادهسازی assembly دارند. سایرین بسیار CPU-intensive هستند، بنابراین حذف آنها کمک میکند تا سرور ما تحت بارهای سنگین عملکردی باقی بماند.
برای انجام این تنظیم، میتوانیم یک ساختار tls.Config حاوی تنظیمات TLS غیرپیشفرض خود ایجاد کنیم و آن را به ساختار http.Server خود قبل از راهاندازی سرور اضافه کنیم.
نشان میدهم:
package main import ( "crypto/tls" // New import "database/sql" "flag" "html/template" "log/slog" "net/http" "os" "time" "snippetbox.alexedwards.net/internal/models" "github.com/alexedwards/scs/mysqlstore" "github.com/alexedwards/scs/v2" "github.com/go-playground/form/v4" _ "github.com/go-sql-driver/mysql" ) ... func main() { ... app := &application{ logger: logger, snippets: &models.SnippetModel{DB: db}, templateCache: templateCache, formDecoder: formDecoder, sessionManager: sessionManager, } // Initialize a tls.Config struct to hold the non-default TLS settings we // want the server to use. In this case the only thing that we're changing // is the curve preferences value, so that only elliptic curves with // assembly implementations are used. tlsConfig := &tls.Config{ CurvePreferences: []tls.CurveID{tls.X25519, tls.CurveP256}, } // Set the server's TLSConfig field to use the tlsConfig variable we just // created. srv := &http.Server{ Addr: *addr, Handler: app.routes(), ErrorLog: slog.NewLogLogger(logger.Handler(), slog.LevelError), TLSConfig: tlsConfig, } logger.Info("starting server", "addr", srv.Addr) err = srv.ListenAndServeTLS("./tls/cert.pem", "./tls/key.pem") logger.Error(err.Error()) os.Exit(1) } ...
اطلاعات تکمیلی
نسخههای TLS
به طور پیشفرض، سرور HTTPS در Go برای پشتیبانی از TLS 1.2 و 1.3 پیکربندی شده است. میتوانید این را سفارشی کنید و نسخههای حداقل و حداکثر TLS را با استفاده از فیلدهای tls.Config.MinVersion و MaxVersion و ثابتهای نسخههای TLS در بسته crypto/tls تغییر دهید.
به عنوان مثال، اگر میخواهید سرور فقط از نسخههای TLS 1.0 تا 1.2 پشتیبانی کند، میتوانید از یک پیکربندی مانند این استفاده کنید:
tlsConfig := &tls.Config{ MinVersion: tls.VersionTLS10, MaxVersion: tls.VersionTLS12, }
Cipher suiteها
cipher suiteهایی که Go پشتیبانی میکند نیز در ثابتهای بسته crypto/tls تعریف شدهاند.
با این حال، برخی از این cipher suiteها (به طور خاص، cipher suiteهایی که از Perfect Forward Secrecy پشتیبانی نمیکنند، یا از RC4، 3DES یا CBC_SHA256 استفاده میکنند) ضعیف در نظر گرفته میشوند و به طور پیشفرض توسط سرور HTTPS در Go استفاده نمیشوند. از Go 1.23، cipher suiteهایی که سرور HTTPS در Go به طور پیشفرض استفاده میکند عبارتند از:
TLS_AES_128_GCM_SHA256 // TLS 1.3 connections only TLS_AES_256_GCM_SHA384 // TLS 1.3 connections only TLS_CHACHA20_POLY1305_SHA256 // TLS 1.3 connections only TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 // TLS 1.2 connections only TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 // TLS 1.2 connections only TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 // TLS 1.2 connections only TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 // TLS 1.2 connections only TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 // TLS 1.2 connections only TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 // TLS 1.2 connections only TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA // TLS 1.0, 1.1 and 1.2 connections TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA // TLS 1.0, 1.1 and 1.2 connections TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA // TLS 1.0, 1.1 and 1.2 connections TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA // TLS 1.0, 1.1 and 1.2 connections
اگر میخواهید cipher suiteهای استفاده شده توسط سرور HTTPS در Go را تغییر دهید — یا با شامل کردن cipher suiteهای ضعیفی که به طور پیشفرض استفاده نمیشوند، یا حذف cipherهای خاصی که به طور پیشفرض استفاده میشوند — میتوانید این کار را از طریق فیلد tls.Config.CipherSuites انجام دهید.
به عنوان مثال، اگر میخواهید از لیست cipher پیشفرض استفاده کنید اما با حذف cipherهای CBC، میتوانید tls.Config خود را به این صورت پیکربندی کنید:
tlsConfig := &tls.Config{ CipherSuites: []uint16{ tls.TLS_AES_128_GCM_SHA256, tls.TLS_AES_256_GCM_SHA384, tls.TLS_CHACHA20_POLY1305_SHA256, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, }, }
Go به طور خودکار انتخاب میکند که کدام از این cipher suiteها در واقع در زمان اجرا بر اساس امنیت cipher، عملکرد و پشتیبانی سختافزار کلاینت/سرور استفاده شود.
همچنین مهم (و جالب) است که توجه داشته باشید اگر یک اتصال TLS 1.3 مذاکره شود، tls.Config.CipherSuites نادیده گرفته خواهد شد. دلیل این است که همه cipher suiteهایی که Go برای اتصالهای TLS 1.3 پشتیبانی میکند ایمن در نظر گرفته میشوند، بنابراین ارائه مکانیزمی برای پیکربندی آنها چندان منطقی نیست.
اساساً، استفاده از tls.Config.CipherSuites برای تنظیم یک لیست سفارشی از cipher suiteهای پشتیبانی شده فقط اتصالهای TLS 1.0-1.2 را تحت تأثیر قرار میدهد. بنابراین، در مثال بالا، در واقع لازم نیست cipherهای خاص TLS 1.3 را شامل کنیم و میتوان آن را به این صورت ساده کرد:
tlsConfig := &tls.Config{ CipherSuites: []uint16{ tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, }, }