爲何要使用HTTPS?使用HTTPS的途徑有哪些?如何用Go來部署HTTPS?拿出你的小本本,你要的乾貨都在這兒!html
HTTPS的好處咱們已在以前的文章中提升好多。它加密瀏覽器和服務器之間的流量,保障你密碼傳輸的安全,讓你的頁面加載速度飛快,有助於網站的SEO優化還有對HTTP網站百般嫌棄的瀏覽器廠商......這些都是使用HTTPS的理由。那麼問題來了,怎樣能夠又快又好地部署HTTPS呢?git
好比說CloudFlare,他們的免費方案爲你那僅支持HTTP的網站提供仿HTTPS代理服務。github
要使用CloudFlare:golang
瀏覽器與CloudFlare對話,CloudFlare負責提供SSL證書,並代理通向你的服務器的通訊。因爲額外的通訊量,這可能會減慢網絡速度,也可能因爲CloudFlare服務器比你的服務器要快(變得更快是他們的工做),因此致使網絡速度變快。web
AWS、谷歌雲以及其它一些主機服務提供商也爲託管在他們那裏的服務器提供免費HTTPS服務。數據庫
另外一個選項是在支持HTTPS的反向代理服務器(如Caddy)後面運行你的服務器。瀏覽器
好久好久之前,想要一張ssl證書就必須每一年爲一個域名花不少錢。而如今,Let's Encrypt改變了這一切。緩存
這是一個非營利性機構,它提供免費證書,而且提供HTTP API來得到證書。API容許自動化處理這一過程。安全
在Let’s Encrypt出現以前,你可能會購買一個證書,而這僅僅是一串字節而已。你會把證書存放在一個文件中,並配置你的網絡服務器來使用它。服務器
有了Let’s Encrypt之後,你就可以使用他們的API來免費得到證書了,並且這一過程是在你的服務器啓動後自動完成的。
值得慶幸的是,全部與API進行對話的艱苦工做都已由其餘人作完了。咱們只須要安裝插件就能夠了。
有兩個Go庫能夠實現Let’s Encrypt支持。
我一直在使用golang.org/x/crypto/acme/autocert,它是由Go的核心開發人員開發的。
如今已經有幾個月了,它運行一切正常。
下面是怎樣啓動一個使用Let’s Encrypt提供的免費SSL證書的HTTPS網絡服務器的方法。
完整的例子請看:free-ssl-certificates/main.go。
const (
htmlIndex = `Welcome!`
inProduction = true
)
func handleIndex(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, htmlIndex)
}
func makeHTTPServer() *http.Server {
mux := &http.ServeMux{}
mux.HandleFunc("/", handleIndex)
// set timeouts so that a slow or malicious client doesn't
// hold resources forever
return &http.Server{
ReadTimeout: 5 * time.Second,
WriteTimeout: 5 * time.Second,
IdleTimeout: 120 * time.Second,
Handler: mux,
}
}
func main() {
var httpsSrv *http.Server
// when testing locally it doesn't make sense to start
// HTTPS server, so only do it in production.
// In real code, I control this with -production cmd-line flag
if inProduction {
// Note: use a sensible value for data directory
// this is where cached certificates are stored
dataDir := "."
hostPolicy := func(ctx context.Context, host string) error {
// Note: change to your real domain
allowedHost := "www.mydomain.com"
if host == allowedHost {
return nil
}
return fmt.Errorf("acme/autocert: only %s host is allowed", allowedHost)
}
httpsSrv = makeHTTPServer()
m := autocert.Manager{
Prompt: autocert.AcceptTOS,
HostPolicy: hostPolicy,
Cache: autocert.DirCache(dataDir),
}
httpsSrv.Addr = ":443"
httpsSrv.TLSConfig = &tls.Config{GetCertificate: m.GetCertificate}
go func() {
err := httpsSrv.ListenAndServeTLS("", "")
if err != nil {
log.Fatalf("httpsSrv.ListendAndServeTLS() failed with %s", err)
}
}()
}
httpSrv := makeHTTPServer()
httpSrv.Addr = ":80"
err := httpSrv.ListenAndServe()
if err != nil {
log.Fatalf("httpSrv.ListenAndServe() failed with %s", err)
}}
須要注意的是:
這些請求被限制到每週處理20個,以免Let’s Encrypt服務器過載。
所以,在某個地方緩存證書是很是重要的。在咱們的例子中,咱們將證書緩存到磁盤上,使用的是autocert.DirCache命令。
緩存只是一個界面,因此你能夠在一個SQL數據庫或Redis中執行你所存儲的。
爲覈實你確實是你所申請證書的域的全部者,Let’s Encrypt服務器會回叫你的服務器。
爲了正常工做,DNS名必須解析到你的服務器的IP地址。
這意味着,HTTPS代碼-路徑的本地測試是很難的。我一般不這麼作。
若是你真的想這麼作,你可使用ngrok來將你的本地端口暴露給互聯網,設置DNS來將你的域名解析到ngrok建立的公共DNS上,而後等待確認DNS信息傳給Let’s Encrypt的計算機。
正如我提到的, Let’s Encrypt限制了證書供應,因此你須要確保服務器不會向其請求你不關心的域的證書。Autocert的文檔很好地解釋了這一點。
咱們的例子假設的是最多見的狀況:一個服務器僅響應一個域。你能夠很容易地改變這一點。
當在你的筆記本電腦上進行本地測試時,運行HTTPS版本是毫無心義的。
你的計算機極可能沒有可見公用IP地址,因此Let’s Encrypt服務器沒法達到你那裏,因此你將不會獲得證書。
咱們也不能綁定到HTTPS端口443(只有根進程能夠綁定到1024如下的端口)。
在這個例子中,我使用inProduction標記來決定是否應該啓動HTTPS服務器。
在實際代碼中,我會加入檢查-production命令行標誌的代碼,並使用它。
若是你可以使用HTTPS了,那麼提供純HTTP就毫無心義了。
咱們能夠將全部HTTP請求重定向到一樣的HTTPS上,以得到更好的安全性和搜索引擎優化效果。
func makeServerFromMux(mux *http.ServeMux) *http.Server {
// set timeouts so that a slow or malicious client doesn't
// hold resources forever
return &http.Server{
ReadTimeout: 5 * time.Second,
WriteTimeout: 5 * time.Second,
IdleTimeout: 120 * time.Second,
Handler: mux,
}
}
func makeHTTPToHTTPSRedirectServer() *http.Server {
handleRedirect := func(w http.ResponseWriter, r *http.Request) {
newURI := "https://" + r.Host + r.URL.String()
http.Redirect(w, r, newURI, http.StatusFound)
}
mux := &http.ServeMux{}
mux.HandleFunc("/", handleRedirect)
return makeServerFromMux(mux)
}
func main() {
httpSrv := makeHTTPToHTTPSRedirectServer()
httpSrv.Addr = ":80"
fmt.Printf("Starting HTTP server on %s\n", httpSrv.Addr)
err := httpSrv.ListenAndServe()
if err != nil {
log.Fatalf("httpSrv.ListenAndServe() failed with %s", err)
}
}
技術部分到此爲止了。
有種意見認爲,因爲一個設計錯誤,SSL協議不只進行加密,還會向瀏覽器證實網站的身份。它擔負着責任,使得咱們能夠追蹤google.com網站的全部者,而且看到該網站的確是由美國谷歌公司,而不是由莫斯科的黑客伊萬全部。
咱們只信任極少數公司(證書頒發機構)會頒發可以證實網站全部者身份的證書。
當你申請一個證書時,證書頒發機構必須覈實你的身份。他們經過查看你的文件來作這項工做。
覈實文件須要人力。保證證書安全也須要人力。證書頒發機構爲頒發證書而收費是合理的。
信任並非成比例的。瀏覽器和操做系統銷售商能夠信任10家公司不會頒發無效證書,但他們不可能信任1000家。
咱們不想讓隨便一家公司變成騙子證書頒發機構,而後爲黑客伊萬頒發google.com域的證書。
爲了獲得僅有的幾個理想結果而連續審覈數千家證書頒發機構,將會花費太多的精力。
由少數幾家公司控制市場極可能致使壟斷,這樣,因爲缺少競爭,價格將居高不下。
這正是SSL證書市場當前的行情。你每一年只花60美圓就能夠擁有一臺低端服務器,但一個證書卻比這要昂貴。
這是一個問題,由於SSL證書的成本是全部網站採用加密技術的明顯障礙。
少數幾家公司決定共享他們的資源來解決這一問題,從而更有利於整個互聯網。因而他們資助了Let’s Encrypt這樣一家證書頒發機構,而後編制一些必要的軟件並運營着頒發證書的服務器。
這就是免費證書的來歷。