Tarkibga o'tish

Self-signed sertifikat

HTTPS server ishga tushirish uchun sertifikat va yopiq kalit kerak. Production’da sertifikat ishonchli sertifikat markazidan (CA) olinadi. Lokal kompyuterda esa localhost uchun hech bir CA sertifikat bermaydi, chunki localhost hech kimga tegishli domen emas.

Bunday holatda self-signed (o‘zi imzolagan) sertifikat ishlatiladi. U CA tomonidan emas, egasining o‘zi tomonidan imzolanadi. Shifrlash xuddi haqiqiy sertifikatdagidek ishlaydi. Faqat brauzer va boshqa klientlar unga avtomatik ishonmaydi, chunki imzo ishonchli ildiz sertifikatlar ro‘yxatida yo‘q.

Self-signed sertifikat qachon kerak bo‘ladi:

  • lokal ishlab chiqishda HTTPS’ni sinash uchun: Secure cookie’lar, HSTS, HTTP/2;
  • ichki tarmoqdagi servislar orasidagi aloqada, agar o‘z CA’ingiz bo‘lsa;
  • testlarda.

Ommaviy saytda esa self-signed sertifikat ishlatilmaydi. U uchun Let's Encrypt kabi bepul CA’lar bor.

1. Sertifikat yaratish

Sertifikat yaratishning uch usulini ko‘rib chiqamiz.

Go bilan: generate_cert.go

Go o‘rnatilgan bo‘lsa, sertifikat yaratish uchun qo‘shimcha dastur kerak emas. Go manba kodida tayyor skript bor:

go run $(go env GOROOT)/src/crypto/tls/generate_cert.go --host localhost,127.0.0.1
2026/09/30 10:00:00 wrote cert.pem
2026/09/30 10:00:00 wrote key.pem

Joriy katalogda ikkita fayl paydo bo‘ladi:

  • cert.pem — sertifikat. Unda ochiq kalit va domenlar bor. Uni tarqatish mumkin;
  • key.pem — yopiq kalit. U maxfiy.

OpenSSL bilan

openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 \
  -days 365 -nodes \
  -keyout key.pem -out cert.pem \
  -subj "/CN=localhost" \
  -addext "subjectAltName=DNS:localhost,IP:127.0.0.1"

Parametrlar:

  • -x509 — so‘rov emas, tayyor self-signed sertifikat yaratadi;
  • -newkey ec ... prime256v1 — yangi ECDSA P-256 kaliti. RSA’ga qaraganda qisqa va tez;
  • -days 365 — amal qilish muddati;
  • -nodes — yopiq kalit parol bilan shifrlanmaydi;
  • -subj "/CN=localhost" — sertifikat nomi;
  • -addext "subjectAltName=..." — sertifikat qaysi domen va IP manzillar uchun ekanini bildiradi.

Sertifikat ichini tekshirish:

openssl x509 -in cert.pem -noout -subject -ext subjectAltName -dates
subject=CN=localhost
X509v3 Subject Alternative Name:
    DNS:localhost, IP Address:127.0.0.1
notBefore=Sep 30 05:00:00 2026 GMT
notAfter=Sep 30 05:00:00 2027 GMT

Info

Zamonaviy klientlar domenni CN maydonidan emas, faqat Subject Alternative Name (SAN) kengaytmasidan tekshiradi. Go ham shunday ishlaydi. SAN bo‘lmagan sertifikat bilan x509: certificate relies on legacy Common Name field xatosi chiqadi. Shu sababli -addext qatorini tushirib qoldirmang.

mkcert bilan

mkcert — lokal ishlab chiqish uchun maxsus yaratilgan vosita. U kompyuteringizda shaxsiy CA yaratadi va uni tizimning hamda brauzerlarning ishonchli ro‘yxatiga qo‘shadi. Shundan keyin u bergan sertifikatlarga brauzer ogohlantirishsiz ishonadi.

mkcert -install
mkcert localhost 127.0.0.1 ::1

Birinchi buyruq lokal CA yaratib, uni ishonchli ro‘yxatga qo‘shadi. Ikkinchisi ko‘rsatilgan nomlar uchun sertifikat yaratadi va fayllar nomini chiqaradi. Masalan, localhost+2.pem sertifikat va localhost+2-key.pem kalit.

Warning

mkcert -install tizimning ishonchli sertifikatlar ro‘yxatini o‘zgartiradi. Yaratilgan CA’ning yopiq kaliti (mkcert -CAROOT buyrug‘i ko‘rsatadigan katalogda) kimning qo‘liga tushsa, u sizning kompyuteringiz ishonadigan istalgan sayt uchun sertifikat yarata oladi. Bu kalitni hech kimga bermang va boshqa kompyuterga ko‘chirmang. mkcertni o‘rnatish bo‘yicha joriy ko‘rsatmalarni loyihaning rasmiy sahifasidan oling.

Lokal ishlab chiqish uchun mkcert eng qulay variant: brauzer ham, curl ham ogohlantirish bermaydi.

2. Yopiq kalitni himoyalash

chmod 600 key.pem
echo "*.pem" >> .gitignore

Yopiq kalitni faqat dastur egasi o‘qiy olishi kerak va u Git’ga tushmasligi lozim. Lokal self-signed kalit uchun ham shu qoidaga amal qilish yaxshi odat.

3. Go serverini HTTPS’da ishga tushirish

main.go
package main

import (
    "fmt"
    "log"
    "net/http"
    "time"
)

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("GET /", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Salom! Protokol: %s, TLS: %v\n", r.Proto, r.TLS != nil)
    })

    srv := &http.Server{
        Addr:              ":8443",
        Handler:           mux,
        ReadHeaderTimeout: 5 * time.Second,
    }

    log.Println("Server: https://localhost:8443")
    log.Fatal(srv.ListenAndServeTLS("cert.pem", "key.pem"))
}

ListenAndServe o‘rniga ListenAndServeTLS chaqirildi va unga sertifikat hamda kalit fayllari berildi. Boshqa hech narsa o‘zgarmadi.

r.TLS — so‘rov TLS orqali kelgan bo‘lsa, ulanish haqidagi ma’lumot. Oddiy HTTP so‘rovda u nil bo‘ladi.

Go HTTPS ulanishlar uchun HTTP/2ni avtomatik yoqadi. Buning uchun hech narsa qilish shart emas.

4. Klientdan ulanish

curl bilan

curl https://localhost:8443
curl: (60) SSL certificate problem: self-signed certificate

curl sertifikatga ishonmadi. Bu to‘g‘ri xatti-harakat. Ikkita yechim bor:

# ✅ Aynan shu sertifikatga ishonish
curl --cacert cert.pem https://localhost:8443

# ⚠️ Tekshiruvni butunlay o‘chirish: faqat tez sinov uchun
curl -k https://localhost:8443
Salom! Protokol: HTTP/2.0, TLS: true

--cacert curlga faqat shu sertifikatni ishonchli deb qabul qilishni aytadi. Tekshiruv saqlanib qoladi: sertifikatdagi domen ham tekshiriladi. -k esa hamma narsaga ko‘z yumadi.

Go klienti bilan

Go klienti ham self-signed sertifikatni rad etadi. Unga sertifikatni ishonchli ro‘yxatga qo‘shib beramiz:

client.go
package main

import (
    "crypto/tls"
    "crypto/x509"
    "fmt"
    "io"
    "log"
    "net/http"
    "os"
    "time"
)

func main() {
    pem, err := os.ReadFile("cert.pem")
    if err != nil {
        log.Fatal(err)
    }

    pool := x509.NewCertPool()
    if !pool.AppendCertsFromPEM(pem) {
        log.Fatal("sertifikatni o‘qib bo‘lmadi")
    }

    client := &http.Client{
        Timeout: 5 * time.Second,
        Transport: &http.Transport{
            TLSClientConfig: &tls.Config{RootCAs: pool},
        },
    }

    resp, err := client.Get("https://localhost:8443")
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    body, _ := io.ReadAll(resp.Body)
    fmt.Print(string(body))
}
go run client.go
Salom! Protokol: HTTP/1.1, TLS: true

RootCAs maydoni klient ishonadigan ildiz sertifikatlar ro‘yxatini almashtiradi. Endi klient faqat cert.pemga ishonadi, lekin sertifikat tekshiruvi to‘liq saqlanadi: domen, muddat va imzo tekshiriladi. Bu InsecureSkipVerify: truedan tubdan farq qiladi.

Protokol bu safar HTTP/1.1 chiqdi. Maxsus TLSClientConfig berilgan http.Transport HTTP/2’ni avtomatik yoqmaydi. Kerak bo‘lsa, uni ForceAttemptHTTP2: true maydoni bilan yoqish mumkin.

5. Testlarda: httptest.NewTLSServer

Testlarda sertifikat fayllari bilan ishlash shart emas. httptest paketi TLS serverni vaqtinchalik sertifikat bilan o‘zi yaratadi:

main_test.go
package main

import (
    "io"
    "net/http"
    "net/http/httptest"
    "testing"
)

func TestHTTPS(t *testing.T) {
    srv := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        io.WriteString(w, "xavfsiz")
    }))
    defer srv.Close()

    resp, err := srv.Client().Get(srv.URL) // srv.Client() sertifikatga ishonadi
    if err != nil {
        t.Fatal(err)
    }
    defer resp.Body.Close()

    body, _ := io.ReadAll(resp.Body)
    if string(body) != "xavfsiz" {
        t.Errorf("kutilgan %q, olindi %q", "xavfsiz", body)
    }
}

srv.Client() shu server sertifikatiga ishonadigan tayyor klientni qaytaradi.

Xulosa

  • Self-signed sertifikat lokal ishlab chiqish va testlar uchun mo‘ljallangan. Ommaviy saytda u ishlatilmaydi.
  • Sertifikatni generate_cert.go, OpenSSL yoki mkcert bilan yaratish mumkin. mkcert brauzer ogohlantirishlarisiz ishlaydi.
  • Sertifikatda domenlar SAN kengaytmasida ko‘rsatilishi shart.
  • Yopiq kalit maxfiy: fayl huquqlari 600 bo‘lishi va Git’ga tushmasligi kerak.
  • Go serveri ListenAndServeTLS bilan HTTPS’da ishlaydi va HTTP/2’ni avtomatik yoqadi.
  • Klientda -k yoki InsecureSkipVerify o‘rniga --cacert yoki RootCAs ishlatiladi.
  • Testlarda httptest.NewTLSServer qulay.

Keyingi darsda tls.Config orqali TLS sozlamalarini boshqarishni o‘rganamiz.