Проблемы при создании сервера HTTPS для обслуживания двоичных файлов и других файлов - PullRequest
0 голосов
/ 29 сентября 2019

Чего я хочу достичь: HTTPS-сервер, разработанный специально для обслуживания двоичных файлов примерно для 1000 устройств, иногда в одно и то же время (клиенты будут загружать двоичные файлы с помощью wget, curl, загрузки из браузера и т. Д.).

Основные функциональные возможности:

  • клиент не сможет загрузить двоичный файл без сертификата
  • сервер разрешит каталог клиентапросмотр / загрузка через браузер (если у клиента есть сертификат)
  • сервер оптимизирован для стабильности и безопасности, тогда для скорости
  • сервер должен использовать шифры высокой безопасности и TLS1.2

Чего мне удалось достичь

package main

import (
    "log"
    "net/http"
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
        w.Header().Set("Content-Type", "text/plain; charset=utf-8")
        http.ServeFile(w, req, "/")
    })

    log.Printf("Server running\nAccess the server via: https://localhost:9900/")
    log.Fatal(http.ListenAndServeTLS(":9900", "cert.crt", "priv.key", http.FileServer(http.Dir("/"))))
}

Теперь это работает нормально, хотя не проверяет все функции и не очень гибко, и почему-то я хотел сделать его болеебудущее, так как я хочу учиться, создавая этот проект, а также расширять его в будущем, поскольку мне интересно больше узнать о серверах.

После небольшого исследования я нашел несколько фрагментов кода на GitHub и в учебных пособиях, которые побудили меня собрать следующий фрагмент кода:

package main

import (
    "crypto/tls"
    "log"
    "net/http"
)

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
        w.Header().Add("Strict-Transport-Security", "max-age=63072000; includeSubDomains")
        http.ServeFile(w, req, "/")

    })
    cfg := &tls.Config{
        MinVersion:               tls.VersionTLS12,
        CurvePreferences:         []tls.CurveID{tls.CurveP521, tls.CurveP384, tls.CurveP256},
        PreferServerCipherSuites: true,
        CipherSuites: []uint16{
            tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
            tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
            tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
            tls.TLS_RSA_WITH_AES_256_CBC_SHA,
            tls.TLS_AES_256_GCM_SHA384,
        },
    }

    srv := &http.Server{
        Addr:         ":9900",
        Handler:      mux,
        TLSConfig:    cfg,
        TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler), 0),
    }
    log.Printf("Server running\nAccess the server via: https://localhost:9900/")
    log.Fatal(srv.ListenAndServeTLS("cert.crt", "priv.key"), http.FileServer(http.Dir("/")))

}

Проблема в том, что при запуске сервераи я подключаюсь к нему через браузер, мне предоставляют корневой каталог, но каждый раз, когда я нажимаю на папку, URL увеличивает адрес, но страница просто обновляется в каталоге "/".

А точнее:

  • Сначала я подключаюсь к серверу и мне представляется корневой каталог, мне показывают Dir1, Dir2, Dir3
  • Я нажимаю Dir1
  • URL изменяется с https://localhost:9900 на https://localhost:9900/Dir1
  • Но я все еще в корневом каталоге

Из того, что я могу видеть ... Я думаю, что где-то создаю петлю. Если кто-нибудь знает, что мне нужно сделать, чтобы сделать это функциональным, помощь будет принята с благодарностью.

ПРИМЕЧАНИЕ Вышеуказанное поведение наблюдается в Firefox, в Chrome Я получаю одну из 2 ошибок в журнале ошибок сервера, в зависимости от внесенных изменений:

  • 2019/09/29 19:59:37 http: Ошибка квитирования TLS от [:: 1]: 53287: EOF
  • 2019/09/29 19:15:59 http: Ошибка квитирования TLS от [:: 1]: 50457: tls: клиент не поддерживает выбранный сертификат

1 Ответ

1 голос
/ 30 сентября 2019

В другом месте есть несколько примеров того, как это сделать (как было прокомментировано).

Вот рабочий пример, в котором обработчик файлового сервера является улучшенной версией того, что в стандартной библиотеке поддерживает больше заголовков кэшаи локально сжатые файлы. Вместо этого можно добавить стандартный обработчик файлового сервера, если это то, что вам нужно.

package main

import (
    "crypto/tls"
    "flag"
    "fmt"
    "log"
    "net/http"
    "time"

    "github.com/rickb777/servefiles/v3"
)

var path = flag.String("path", "..", "directory for the files tp be served")
var cert = flag.String("cert", "", "file containing the certificate (optional)")
var key = flag.String("key", "", "file containing the private key (optional)")
var port = flag.Int("port", 8080, "TCP port to listen on")
var maxAge = flag.String("maxage", "", "Maximum age of assets sent in response headers - causes client caching")
var verbose = flag.Bool("v", false, "Enable verbose messages")

func main() {
    flag.Parse()

    if *verbose {
        servefiles.Debugf = log.Printf
    }

    if (*cert != "" && *key == "") ||
        (*cert == "" && *key != "") {
        log.Fatal("Both certificate file (-cert) and private key file (-key) are required.")
    }

    h := servefiles.NewAssetHandler(*path)

    if *maxAge != "" {
        d, err := time.ParseDuration(*maxAge)
        log.Printf("MaxAge: %s %v\n", d, err)
        h = h.WithMaxAge(d)
    }

    srv := &http.Server{
        Addr:    fmt.Sprintf(":%d", *port),
        Handler: h,
    }

    if *cert != "" {
        srv.TLSConfig = &tls.Config{
            MinVersion:               tls.VersionTLS12,
            CurvePreferences:         []tls.CurveID{tls.CurveP521, tls.CurveP384, tls.CurveP256},
            PreferServerCipherSuites: true,
            CipherSuites: []uint16{
                tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
                tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
                tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
                tls.TLS_RSA_WITH_AES_256_CBC_SHA,
                tls.TLS_AES_256_GCM_SHA384,
            },
        }
        log.Printf("Access the server via: https://localhost:%d/", *port)
        log.Fatal(srv.ListenAndServeTLS(*cert, *key))

    } else {
        log.Printf("Access the server via: http://localhost:%d/", *port)
        log.Fatal(srv.ListenAndServe())
    }
}

Исходный код https://github.com/rickb777/servefiles/blob/master/v3/webserver/example.go

...