不正な証明書でhttpsリクエストを行う方法は?


128

https://golang.orgプログラムで取得したいとします。現在、golang.org(ssl)には不正な証明書が発行されている*.appspot.comので、これを実行すると、

package main

import (
    "log"
    "net/http"
)

func main() {
    _, err := http.Get("https://golang.org/")
    if err != nil {
        log.Fatal(err)
    }
}

(予想通り)

Get https://golang.org/: certificate is valid for *.appspot.com, *.*.appspot.com, appspot.com, not golang.org

今、私はこの証明書を自分で信頼したいと思います(指紋などを検証できる自己発行の証明書を想像してください)。どのようにリクエストを発行し、証明書を検証/信頼できますか?

おそらくopensslを使用して証明書をダウンロードし、それをファイルにロードして、tls.Config構造体に入力する必要があります!?


5
これは「悪い証明書」ではなく、別のCNを持つ証明書です。InsecureSkipVerifyは、ここでは正当な用途ではありません。接続しようとしているものと一致するようにtls.ConfigでServerNameを設定する必要があります。このStackOverflowの投稿により、Goコードのこの大きなセキュリティホールがいたるところに広がっています。InsecureSkipVerifyは、証明書をまったくチェックしません。CNがホスト名と一致しない場合でも、信頼できるエンティティによって証明書が正当に署名されていることを確認する必要があります。トンネルとNATSは、これを合法的にミスマッチさせる可能性があります。
ロブ

回答:


283

セキュリティ上の注意:セキュリティチェックを無効にすることは危険であり、回避する必要があります

デフォルトクライアントのすべてのリクエストに対して、グローバルにセキュリティチェックを無効にすることができます。

package main

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

func main() {
    http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
    _, err := http.Get("https://golang.org/")
    if err != nil {
        fmt.Println(err)
    }
}

クライアントのセキュリティチェックを無効にすることができます。

package main

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

func main() {
    tr := &http.Transport{
        TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
    }
    client := &http.Client{Transport: tr}
    _, err := client.Get("https://golang.org/")
    if err != nil {
        fmt.Println(err)
    }
}

17
なしで接続を使用できるように、信頼できる証明書をどこに置くのでしょうかInsecureSkipVerify: true。それは可能ですか?
2012

7
NameToCertificate役立つかもしれません、tls.Configドキュメントを参照してください:golang.org/pkg/crypto/tls/#Config
cyberdelia '25

1
カスタムCA証明書プールを追加する例を次に示します。golang.org / pkg / crypto / tls / #example_Dial これは、HTTPクライアントでも使用できます。
2014

7
多くの人が、ホスト名チェックを無効にしようとします(証明書チェックを完全に無効にするわけではありません)。これは間違った答えです。Goでは、接続先のホストのCNと一致するように、tls構成でServerNameを設定する必要があります(接続先のDNS名でない場合)。InsecureSkipVerifyは、ポートへの単純な古いtelnetより安全ではありません。この設定では認証はありません。代わりにユーザーServerName!
ロブ

8
注意:そのように作成されたトランスポートは、ほとんどのフィールドにゼロ値を使用するため、すべてのデフォルトが失われます以下の答えを示している、あなたはそれらをコピーすることもできます。ファイル記述子がなくなったのはなぜか、ファイル記述子が不足している理由を理解するのにかなりの楽しみがありましたDialer.Timeout
mknecht 2017

26

これは、のデフォルト設定を失うことなくDefaultTransport、またユーザーのコメントによる偽のリクエストを必要とせずにそれを行う方法です。

defaultTransport := http.DefaultTransport.(*http.Transport)

// Create new Transport that ignores self-signed SSL
customTransport := &http.Transport{
  Proxy:                 defaultTransport.Proxy,
  DialContext:           defaultTransport.DialContext,
  MaxIdleConns:          defaultTransport.MaxIdleConns,
  IdleConnTimeout:       defaultTransport.IdleConnTimeout,
  ExpectContinueTimeout: defaultTransport.ExpectContinueTimeout,
  TLSHandshakeTimeout:   defaultTransport.TLSHandshakeTimeout,
  TLSClientConfig:       &tls.Config{InsecureSkipVerify: true},
}

更新

より短い方法:

customTransport := &(*http.DefaultTransport.(*http.Transport)) // make shallow copy
customTransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}

適切な方法(Go 1.13以降)(以下の回答で提供):

customTransport := http.DefaultTransport.(*http.Transport).Clone()
customTransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}

警告:テスト/開発目的のみ。それ以外は、自己責任で進めてください!!!


を使用してデフォルトのトランスポート設定をコピーしmytransportsettings := &(*http.DefaultTransport.(*http.Transport))、TLSクライアント構成を変更するだけの方が簡単ではないでしょうmytransportsettings.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}か。
TheDiveO

試してみる価値がある、私は実際のDefaultTransportを変更しないようにしようとしていたと思います
Jonathan Lin

1
これ、あなたがしたように、浅いコピーを作成すること確実にします、それは議論されたユースケースのために十分です。私は実際にこれを作業コードにデプロイしています。
TheDiveO

19

これらの答えはすべて間違っています!InsecureSkipVerifyホスト名と一致しないCNの処理には使用しないでください。Go開発者は賢明にもホスト名チェック(正当な用途-トンネル、NAT、共有クラスター証明書など)を無効にせず、同様に見えるものの実際は証明書チェックを完全に無視することに固執しました。証明書が有効であり、信頼できる証明書によって署名されていることを知っておく必要があります。しかし、一般的なシナリオでは、CNが接続先のホスト名と一致しないことがわかっています。それらについては、に設定ServerNametls.Configます。tls.Config.ServerName== remoteServerCNの場合、証明書のチェックは成功します。これはあなたが望むものです。 InsecureSkipVerify認証がないことを意味します。そして、それは中間者にとって熟したものです。TLSを使用する目的を無効にします。

正当な用途が1つありInsecureSkipVerifyます。それを使用してホストに接続し、その証明書を取得して、すぐに切断します。を使用するようにコードを設定した場合InsecureSkipVerify、それは通常、ServerName適切に設定しなかったことが原因です(env変数などから取得する必要があります。この要件に腹を立てないでください...正しく実行してください)。

特に、クライアント証明書を使用して認証に依存している場合、基本的には、実際にはログインしない偽のログインになります。を行うコードを拒否します。そうしないとInsecureSkipVerify、コードの何が問題なのかを難しい方法で学習します。


1
これをテストできるサイトを知っていますか?golang orgはエラーをスローしなくなりました。
topskip 2017年

3
この答えはひどく誤解を招くものです。ホスト名に関係なく、有効に署名された証明書を受け入れる場合でも、本当のセキュリティは得られません。私が管理しているドメインの有効な証明書を簡単に取得できます。TLSチェックにホスト名を指定するだけの場合、私が本当の自分であるという検証が失われます。その時点では、証明書が「legit」であるという事実は重要ではありません。それはまだ間違っており、あなたはまだ真ん中の人に対して脆弱です。
ダニエルファレル

5
あなたが実際に信頼していない企業では任意の商用CAの(すなわち:彼らは例えば米国外にいる場合)、およびエンタープライズのための1つのCAと交換してください、あなただけの、これはあなたの本命の一つであることを検証する必要があります。ホスト名チェックは、ユーザーがホスト名が一致することを期待しているが、DNSが安全でない場合に使用します。企業では、通常、ホスト名/ IPを一致させることができないマシンのクラスターに接続します。これは、新しいIPの下で生成されたマシンの正確なクローンであるためです。DNS名は証明書を検索し、証明書はDNS名ではなくIDです。
Rob

3
つまり、クライアントコードはエンタープライズCAのみを信頼します。実際には、現在使用されているCAシステムよりもはるかに安全です。その場合、何も(Thawte、Versignなど)...は信頼されません。実行するCAだけです。Webブラウザーには膨大な信頼リストがあります。互いに通信するサービスは、信頼ファイルに1つのCAしかありません。
Rob

1
ありがとう@Rob私のサービスは同じ単一のCAだけを信頼し、それ以外は何も信用しない同じ設定をしています。これは重要な情報であり、多くの助けになります。
user99999991

8

デフォルトのトランスポート設定を維持したい場合、これを行う正しい方法は次のとおりです(Go 1.13以降):

customTransport := http.DefaultTransport.(*http.Transport).Clone()
customTransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
client = &http.Client{Transport: customTransport}

Transport.Cloneは、トランスポートのディープコピーを作成します。このようにして、Transport時間の経過とともに構造体に追加される新しいフィールドの欠落を心配する必要がなくなります。


7

httpパッケージのデフォルト設定を使用するため、新しいトランスポートおよびクライアントオブジェクトを作成する必要がない場合は、次のように変更して、証明書の検証を無視することができます。

tr := http.DefaultTransport.(*http.Transport)
tr.TLSClientConfig.InsecureSkipVerify = true

7
これを行うと、次の結果になりますpanic: runtime error: invalid memory address or nil pointer dereference
OscarRyz 2017年

6
これより前にデフォルトのhttpリクエスターを使用しない場合は、偽のリクエストを強制して、デフォルトのトランスポートが初期化されるようにする必要があります
Cornel Damian

1
これはホスト名チェックを無効にするものではありません。すべての証明書チェックを無効にします。Goは、ServerNameを接続先の証明書のCNに等しく設定するように強制します。InsecureSkipVerifyは、実際のサービスに転送するふりをする不正なMITMサーバーに接続します。InsecureSkipVerifyの正当な用途は、リモートエンドの証明書を取得してすぐに切断することだけです。
Rob

これは、VerifyPeerCertificateも指定した場合にのみ問題ありません。InsecureSkipVerifyを設定しただけでは、まったくチェックされません。ただし、VerifyPeerCertificateが追加されているため、チェックを書き直して必要な処理を実行できます。ホスト名、または場合によっては有効期限を無視することもできます。これを行うVerifyPeerCertificateのさまざまな実装のためのGoogle。
ロブ

0

通常、URLのDNSドメインは、証明書の証明書サブジェクトと一致する必要があります。

以前は、これはドメインを証明書のcnとして設定するか、ドメインをサブジェクトの別名として設定することによって可能でした。

cnのサポートは長い間(RFC 2818の 2000年以降)推奨されておらず、Chromeブラウザはcnを参照しなくなったため、今日ではサブジェクトの別名としてURLのDNSドメインが必要です。

RFC 6125は、DNSドメインのSANが存在する場合はcnのチェックを禁止しますが、IPアドレスのSANが存在する場合は禁止しません。RFC 6125はまた、すでにRFC 2818で述べられているcnが非推奨であることを繰り返します。また、RFC 6125との組み合わせで本質的にcnがDNSドメイン名をチェックされないことを意味する証明機関ブラウザフォーラムが存在することを示します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.