├── LICENSE ├── .gitignore ├── readme.md └── secureserver.go /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2016 David Pennington http://davidpennington.me 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Go template 3 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 4 | *.o 5 | *.a 6 | *.so 7 | 8 | # Folders 9 | _obj 10 | _test 11 | 12 | # Architecture specific extensions/prefixes 13 | *.[568vq] 14 | [568vq].out 15 | 16 | *.cgo1.go 17 | *.cgo2.c 18 | _cgo_defun.c 19 | _cgo_gotypes.go 20 | _cgo_export.* 21 | 22 | _testmain.go 23 | 24 | *.exe 25 | *.test 26 | *.prof 27 | ### Linux template 28 | *~ 29 | 30 | # temporary files which can be created if a process still has a handle open of a deleted file 31 | .fuse_hidden* 32 | 33 | # KDE directory preferences 34 | .directory 35 | 36 | # Linux trash folder which might appear on any partition or disk 37 | .Trash-* 38 | ### OSX template 39 | *.DS_Store 40 | .AppleDouble 41 | .LSOverride 42 | 43 | # Icon must end with two \r 44 | Icon 45 | 46 | # Thumbnails 47 | ._* 48 | 49 | # Files that might appear in the root of a volume 50 | .DocumentRevisions-V100 51 | .fseventsd 52 | .Spotlight-V100 53 | .TemporaryItems 54 | .Trashes 55 | .VolumeIcon.icns 56 | .com.apple.timemachine.donotpresent 57 | 58 | # Directories potentially created on remote AFP share 59 | .AppleDB 60 | .AppleDesktop 61 | Network Trash Folder 62 | Temporary Items 63 | .apdisk 64 | ### Windows template 65 | # Windows image file caches 66 | Thumbs.db 67 | ehthumbs.db 68 | 69 | # Folder config file 70 | Desktop.ini 71 | 72 | # Recycle Bin used on file shares 73 | $RECYCLE.BIN/ 74 | 75 | # Windows Installer files 76 | *.cab 77 | *.msi 78 | *.msm 79 | *.msp 80 | 81 | # Windows shortcuts 82 | *.lnk 83 | 84 | *.iml 85 | .idea/ 86 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ## Go secureserver 2 | 3 | Out-of-the-box, Go is a fully capable HTTP/HTTPS server. However, it is not 4 | configured correctly to avoid malicious clients, timeouts, or even simple SSL 5 | auto setup with [LetsEncrypt.org](https://letsencrypt.org/). 6 | 7 | This repository exists to help go developers launch a secure, simple HTTPS server. 8 | 9 | This configuration blocks major attacks like: 10 | 11 | - BEAST attack 12 | - POODLE (SSLv3) 13 | - POODLE (TLS) 14 | - Heartbleed 15 | - CRIME 16 | - FUBAR 17 | - OpenSSL CCS vulnerability (CVE-2014-0224) 18 | - OpenSSL Padding Oracle vulnerability 19 | 20 | Achieving forward secrecy and low server load are a focus. 21 | 22 | ## Reading 23 | 24 | - https://blog.bracebin.com/achieving-perfect-ssl-labs-score-with-go 25 | - https://blog.gopheracademy.com/advent-2016/exposing-go-on-the-internet/ 26 | - https://blog.cloudflare.com/the-complete-guide-to-golang-net-http-timeouts/ 27 | - https://cipherli.st/ 28 | - https://wiki.mozilla.org/Security/Server_Side_TLS 29 | 30 | ## Install 31 | 32 | go get github.com/xeoncross/secureserver 33 | 34 | ## Demo Server 35 | 36 | You can quickly run a test HTTP/HTTPS server like so: 37 | 38 | package main 39 | 40 | import ( 41 | "github.com/xeoncross/secureserver" 42 | ) 43 | 44 | func main() { 45 | domain := "example.com" 46 | HSTS := false // enable/disable HSTS 47 | secureserver.RunHTTPRedirectServer() 48 | secureserver.RunDemoHTTPSServer(domain, HSTS) // blocks 49 | } 50 | 51 | ## Usage 52 | 53 | package main 54 | 55 | import ( 56 | "github.com/xeoncross/secureserver" 57 | ) 58 | 59 | func main() { 60 | domain := "example.com" 61 | secureserver.RunHTTPRedirectServer() 62 | s := secureserver.GetHTTPSServer(domain) 63 | 64 | mux := http.NewServeMux() 65 | mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { 66 | w.Header().Add("Strict-Transport-Security", "max-age=63072000; includeSubDomains") 67 | w.Write([]byte("This is an example server on " + domain + ".\n")) 68 | }) 69 | 70 | s.Handler = mux 71 | 72 | log.Fatal(s.ListenAndServeTLS("", "")) 73 | } 74 | 75 | # Todo 76 | 77 | - Implement support for [graceful shutdown](https://tip.golang.org/pkg/net/http/#Server.Shutdown) 78 | 79 | 80 | ## Contributions Required 81 | 82 | To serve a source of information about current Go best-practices; pull requests, 83 | issues, and documentation are welcome. 84 | -------------------------------------------------------------------------------- /secureserver.go: -------------------------------------------------------------------------------- 1 | package secureserver 2 | 3 | import ( 4 | "crypto/tls" 5 | "log" 6 | "net/http" 7 | "time" 8 | 9 | "golang.org/x/crypto/acme/autocert" 10 | ) 11 | 12 | // CipherSuites without known attacks or extreme CPU usage 13 | // https://golang.org/src/crypto/tls/cipher_suites.go#L75 14 | var CipherSuites = []uint16{ 15 | tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 16 | tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 17 | tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 18 | tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 19 | 20 | // Go 1.8 only 21 | // tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, 22 | // tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, 23 | 24 | // Best disabled, as they don't provide Forward Secrecy, 25 | // but might be necessary for some clients 26 | tls.TLS_RSA_WITH_AES_256_GCM_SHA384, 27 | tls.TLS_RSA_WITH_AES_128_GCM_SHA256, 28 | 29 | // tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 30 | // tls.TLS_RSA_WITH_AES_256_GCM_SHA384, 31 | // tls.TLS_RSA_WITH_AES_256_CBC_SHA, 32 | } 33 | 34 | // Curves without known attacks or extreme CPU usage 35 | // https://golang.org/src/crypto/tls/common.go#L542 36 | var Curves = []tls.CurveID{ 37 | // Only use curves which have assembly implementations 38 | tls.CurveP256, 39 | // tls.X25519, // Go 1.8 only 40 | // tls.CurveP384, 41 | // tls.CurveP521, 42 | } 43 | 44 | // TLSConfig for including autocert manager 45 | func TLSConfig(domain string) *tls.Config { 46 | certManager := GetCertificate(domain) 47 | 48 | return &tls.Config{ 49 | MinVersion: tls.VersionTLS12, 50 | PreferServerCipherSuites: true, 51 | GetCertificate: certManager.GetCertificate, 52 | CurvePreferences: Curves, 53 | CipherSuites: CipherSuites, 54 | } 55 | } 56 | 57 | // GetCertificate using autocert 58 | func GetCertificate(domain string) autocert.Manager { 59 | return autocert.Manager{ 60 | Prompt: autocert.AcceptTOS, 61 | HostPolicy: autocert.HostWhitelist(domain), 62 | } 63 | } 64 | 65 | // GetHTTPSServer fully secured 66 | func GetHTTPSServer(domain string) (s *http.Server) { 67 | 68 | s = &http.Server{ 69 | ReadTimeout: 5 * time.Second, 70 | WriteTimeout: 10 * time.Second, 71 | // IdleTimeout: 120 * time.Second, // go 1.8 72 | 73 | Addr: ":443", 74 | TLSConfig: TLSConfig(domain), 75 | 76 | // Disable HTTP/2 (until go 1.8) 77 | TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler), 0), 78 | } 79 | 80 | return s 81 | } 82 | 83 | // RunHTTPRedirectServer to send all HTTP traffic to HTTPS 84 | func RunHTTPRedirectServer() (s *http.Server) { 85 | s = &http.Server{ 86 | ReadTimeout: 5 * time.Second, 87 | WriteTimeout: 5 * time.Second, 88 | Handler: http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { 89 | w.Header().Set("Connection", "close") 90 | url := "https://" + req.Host + req.URL.String() 91 | http.Redirect(w, req, url, http.StatusMovedPermanently) 92 | }), 93 | } 94 | go func() { log.Fatal(s.ListenAndServe()) }() 95 | return s 96 | } 97 | 98 | // RunDemoHTTPSServer to demo a working example 99 | func RunDemoHTTPSServer(domain string, HSTS bool) (s *http.Server) { 100 | s = GetHTTPSServer(domain) 101 | 102 | mux := http.NewServeMux() 103 | mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { 104 | if HSTS { 105 | // Recommend HTTPS only for the next hour (just an example) 106 | w.Header().Add("Strict-Transport-Security", "max-age=3600") 107 | 108 | // Or for 1 year (also on all subdomains) 109 | // w.Header().Add("Strict-Transport-Security", "max-age=31536000; includeSubDomains") 110 | } 111 | w.Write([]byte("This is an example server on " + domain + ".\n")) 112 | }) 113 | 114 | s.Handler = mux 115 | 116 | log.Fatal(s.ListenAndServeTLS("", "")) 117 | return 118 | } 119 | --------------------------------------------------------------------------------