uokadaの見逃し三振は嫌いです

ここで述べられていることは私の個人的な意見に基づくものであり、私が所属する組織には一切の関係はありません。

http.Clientでちゃんとhttpsのリクエストを投げる

SSL証明書使って手元のマシンでhttpsサーバーをたちあげて動作検証してると下のようなSSL証明書周りのエラーが出ませんか?

今回はそんな時の対策方法の紹介です。

go run tlsclient.go
2015/05/07 18:28:58 Get https://localhost/: x509: certificate is valid for hogehoge.jp, not localhost
exit status 1

よくやるのは、hostsファイルをいじってしまいhogehoge.jpをlocalhostにむける方法ですけど、環境を共有しているなどでhostsを気軽にいじれない状況でも簡単に出来る方法をご紹介します。

今回紹介する方法は業務でも使えるちゃんとした方法、SSL証明書の検査も行いかつリクエストをする方法です。(自分の認識違ったらゴメンナサイ。。。)

例として、今回はlocalhostにたてたhttpsサーバーにGETリクエストをなげるサンプルコードなのでこんな感じにRequestオブジェクトを生成します。

u := "https://localhost/"
request, _ := http.NewRequest("GET", u, nil)

次に、SSL証明書に登録されているドメイン(今回はhogehoge.jpとします)をServerNameに設定してtls.Config, http.Transportを生成しそれを使ってさらにhttp.Clientを生成します。
こうすることで正しい証明書を持っているかをチェックした後にリクエストを投げるクライアントが作成されます。

   tr := &http.Transport{
        TLSClientConfig: &tls.Config{ServerName: "hogehoge.jp"},
    }
    client := &http.Client{
        Transport: tr,
    }

最後に生成したクライアントからClient.Doでリクエストを投げて完了です。これだけでhostsをいじらずとも任意のドメインSSL証明書をもった適当なhttpsサーバーにちゃんとしたリクエストを投げられるようになります。

   resp, err := client.Do(request)

いかがでしょうか?ちゃんとしたhttpsのリクエスト投げるのは簡単ですよね。

まとめ

SSL証明書の検査をスルーせずにhttpsのリクエストの投げる方法を紹介をしてみました。 curlだと-kオプション渡してSSL証明書の警告を無視するのエンジニアのほうが多い印象ですがGoはこれぐらいコードを書くだけで簡単にSSL証明書の検査が出来るので今まで適当にSSL証明書の検査せずにリクエストをなげるようなコード書いてた人はこの機会に直してみてはいかがでしょうか?

サンプルコード

package main

import (
    "crypto/tls"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
)

func main() {
    u := "https://localhost/"
    request, _ := http.NewRequest("GET", u, nil)

    tr := &http.Transport{
        TLSClientConfig: &tls.Config{ServerName: "hogehoge.jp"},
    }
    client := &http.Client{
        Transport: tr,
    }
    resp, err := client.Do(request)
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()
    contents, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(resp.StatusCode, string(contents))
}

おまけ

一応、あまりオススメではないですがSSL証明書の検査をせずにリクエストを送りたいなら下のように InsecureSkipVerifyをtrue にすれば適当なSSL証明書を使っていてもサーバーにリクエストが送れます。
(InsecureSkipVerifyはデフォルトfalseなのでサンプルコードでは設定は省略してます)

   tr := &http.Transport{
            TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
    }
    client := &http.Client{
        Transport: tr,
    }