Как обеспечить безопасность HTTP-соединений в Go-приложении с помощью HTTPS/TLS?

Ответ

Безопасность HTTP-соединений обеспечивается с помощью протокола HTTPS (HTTP Secure), который представляет собой HTTP, работающий поверх криптографического протокола TLS (Transport Layer Security) или его устаревшего предшественника SSL.

Основные принципы безопасности TLS:

  1. Шифрование (Confidentiality): Данные, передаваемые между клиентом и сервером, шифруются, что делает их нечитаемыми для третьих лиц.
  2. Аутентификация (Authentication): Сервер предоставляет клиенту цифровой сертификат, выданный доверенным центром сертификации (CA). Это доказывает, что сервер является тем, за кого себя выдает.
  3. Целостность (Integrity): Используются криптографические хэш-функции (MAC) для проверки того, что данные не были изменены во время передачи.

Реализация в Go

Простейший способ запустить HTTPS-сервер — использовать http.ListenAndServeTLS:

package main

import (
    "log"
    "net/http"
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Это безопасное соединение!"))
    })

    // server.crt - публичный сертификат
    // server.key - приватный ключ
    err := http.ListenAndServeTLS(":443", "server.crt", "server.key", nil)
    if err != nil {
        log.Fatal("ListenAndServeTLS: ", err)
    }
}

Лучшие практики в Go:

  • Автоматическое получение сертификатов: Для публичных серверов используйте пакет golang.org/x/crypto/acme/autocert для автоматического получения и обновления бесплатных сертификатов от Let's Encrypt.

  • Тонкая настройка TLS: Для максимальной безопасности создайте кастомный http.Server и настройте tls.Config, чтобы указать минимальную версию TLS и предпочтительные наборы шифров.

    tlsConfig := &tls.Config{
        MinVersion:               tls.VersionTLS12,
        CurvePreferences:         []tls.CurveID{tls.CurveP521, tls.CurveP384, tls.CurveP256},
        PreferServerCipherSuites: true,
    }
    server := &http.Server{
        Addr:      ":443",
        TLSConfig: tlsConfig,
    }
    log.Fatal(server.ListenAndServeTLS("server.crt", "server.key"))
  • HSTS (HTTP Strict Transport Security): Настройте заголовок Strict-Transport-Security, чтобы браузеры всегда подключались к вашему сайту по HTTPS.

  • Перенаправление с HTTP на HTTPS: Запустите отдельную горутину, которая слушает порт 80 и перенаправляет весь трафик на 443 порт.

Ответ 18+ 🔞

А, слушай, смотри-ка, вот этот ваш HTTPS, это же просто HTTP, который натянул на себя бронежилет из TLS, ну или из его старого деда SSL, который уже на пенсии, блядь. Суть в трёх китах, которые держат всю эту банду:

  1. Шифрование (Тайна, ёпта): Всё, что летит туда-сюда между тобой и сервером, превращается в такую абракадабру, что любой, кто перехватит, нихуя не поймёт. Чистая магия, блядь.
  2. Аутентификация (Ты кто такой?): Сервер тычет тебе в лицо свою «корочку» — цифровой сертификат. И если эта бумажка подписана каким-нибудь уважаемым центром (CA), то можно верить, что это не левый чел в подвале, а тот самый сайт.
  3. Целостность (Чтоб не подменили): Тут такие криптографические штуки подключаются (типа MAC), которые сразу орут, если данные по дороге кто-то пальцем тронул. Всё должно прилететь в целости и сохранности, блядь.

Как это в Go делается, спрашиваешь?

Ну, самый простой способ, для ленивых — это http.ListenAndServeTLS. Берёшь и подсовываешь ему два файла: сертификат (публичный) и ключ (приватный, его никому не показывай, ёпта!).

package main

import (
    "log"
    "net/http"
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Это безопасное соединение!"))
    })

    // server.crt - публичный сертификат
    // server.key - приватный ключ
    err := http.ListenAndServeTLS(":443", "server.crt", "server.key", nil)
    if err != nil {
        log.Fatal("ListenAndServeTLS: ", err)
    }
}

А если по-взрослому, то вот тебе лучшие практики, чтоб не облажаться:

  • Не парись с сертификатами: Для нормального, публичного сайта бери пакет golang.org/x/crypto/acme/autocert. Эта хитрая жопа сама будет выпрашивать у Let's Encrypt бесплатные сертификаты и вовремя их менять, когда срок подойдёт. Вообще красота, блядь.

  • Настрой TLS под себя: Если хочешь, чтобы было овердохуища безопасно, не ленись и поковыряй tls.Config. Укажи, что старый хлам вроде TLS 1.0 нам не нужен, и выбери самые крутые шифры.

    tlsConfig := &tls.Config{
        MinVersion:               tls.VersionTLS12, // Ниже 1.2 — иди нахуй
        CurvePreferences:         []tls.CurveID{tls.CurveP521, tls.CurveP384, tls.CurveP256},
        PreferServerCipherSuites: true, // Слушайся сервер, он умный
    }
    server := &http.Server{
        Addr:      ":443",
        TLSConfig: tlsConfig,
    }
    log.Fatal(server.ListenAndServeTLS("server.crt", "server.key"))
  • Включи HSTS: Это такой заголовок Strict-Transport-Security. Он говорит браузеру: «Запомни, чувак, сюда только по HTTPS, и даже не думай пытаться по HTTP». Надёжно, блядь.

  • Перенаправляй всех на HTTPS: Запусти отдельную горутину, которая будет слушать порт 80 (старый добрый HTTP) и всех, кто пришёл, пинком под жопу отправлять на порт 443 (HTTPS). Чтобы даже дураку было понятно, куда идти.