2012-08-25 7 views
79

Powiedz, że chcę programowo uzyskać https://golang.org. Obecnie golang.org (SSL) posiada który jest wydawany *.appspot.com Więc kiedy biegnę złe świadectwo to:golang: Jak wykonać żądanie https ze złym certyfikatem?

package main 

import (
    "log" 
    "net/http" 
) 

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

dostać (jak się spodziewałem)

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

Teraz chcę zaufać tym zaświadczenie (wyobraź sobie samopozywalny certyfikat, w którym mogę potwierdzić odcisk palca itp.): w jaki sposób mogę złożyć wniosek i potwierdzić/zaufać certyfikatowi?

Prawdopodobnie potrzebuję użyć openssl, aby pobrać certyfikat, załadować go do mojego pliku i wypełnić strukturę tls.Config!

+0

to nie jest "zły certyfikat", to certyfikat z innym CN. InsecureSkipVerify nie jest tutaj dozwolonym prawem. Musisz ustawić ServerName w tls.Config, aby dopasować to, z którym próbujesz się połączyć. Ten post Stackoverflow powoduje, że ta duża luka w zabezpieczeniach kodu Go rozprzestrzenia się wszędzie. InsecureSkipVerify nie sprawdza certyfikatu AT ALL. To, czego chcesz, to sprawdzenie, czy certyfikat został prawnie podpisany przez zaufany podmiot, nawet jeśli CN nie jest zgodny z nazwą hosta. Tunele i NATS mogą zgodnie z prawem powodować to niedopasowanie. – Rob

Odpowiedz

167

uwaga Bezpieczeństwo: Wyłączenie kontroli bezpieczeństwa jest niebezpieczne i należy unikać

Można wyłączyć sprawdzanie zabezpieczeń globalnie dla wszystkich żądań domyślnego klienta:

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) 
    } 
} 

można wyłączyć sprawdzanie zabezpieczeń dla klient:

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) 
    } 
} 
+15

Zastanawiam się, gdzie umieścić zaufany certyfikat, aby połączenie mogło być używane bez 'InsecureSkipVerify: true'. Czy to jest możliwe? – topskip

+7

"NameToCertificate" może pomóc, zobacz dokumentację 'tls.Config': http://golang.org/pkg/crypto/tls/#Config – cyberdelia

+0

Podczas korzystania z tej metody, aby wyłączyć kontrolę, działało w przypadkach, w których certyfikat był wygasł, ale nie dotyczy przypadków samopodpisanych certyfikatów. Czy funkcja InsecureSkipVerify naprawdę pomija test bezpieczeństwa? – Alexander

7

Jeśli chcesz użyć ustawień domyślnych z pakietu http, Nie trzeba tworzyć nowy transport i przedmiot Client, można zmienić, aby zignorować weryfikację certyfikatu takiego:

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

Powoduje to "panikę: błąd środowiska wykonawczego: nieprawidłowy adres pamięci lub zerowy wskaźnik dereferencji" – OscarRyz

+4

Jeśli nie używasz wcześniej domyślnego requestera http, musisz wymusić fałszywe żądanie, aby domyślny transport został zainicjowany –

+0

to nie jest wyłączanie sprawdzania nazwy hosta. wyłącza wszystkie kontrole certyfikatów. Wymusza ustawienie wartości ServerName na wartość CN w certyfikacie tego, z czym łączysz się. InsecureSkipVerify połączy się z fałszywym serwerem MITM, który udaje, że przekazuje dalej prawdziwe usługi. JEDYNYM legalnym użyciem dla InsecureSkipVerify jest pobranie certyfikatu zdalnego końca i natychmiastowe rozłączenie. – Rob

2

oto sposób to zrobić bez utraty ustawień domyślnych z DefaultTransport i bez potrzebując fałszywe żądanie zgodnie z komentarzem użytkownika.

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

// Create new Transport that ignores self-signed SSL 
httpClientWithSelfSignedTLS := &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}, 
} 
+0

Zobacz komentarze powyżej. WSZYSTKO z nich jest błędnych! – Rob

+0

Awesome, thanks. To powinna być zaakceptowana odpowiedź! –

1

Wszystkie te odpowiedzi są błędne! Nie używaj InsecureSkipVerify do obsługi CN, która nie jest zgodna z nazwą hosta. Twórcy Go nierozsądnie byli nieugięci w kwestii wyłączania sprawdzania nazw hostów (które ma uzasadnione zastosowania - tunele, naty, wspólne certyfikaty klastrów, itp.), A jednocześnie mają coś, co wygląda podobnie, ale w rzeczywistości całkowicie ignoruje sprawdzanie certyfikatu pod numerem. Musisz wiedzieć, że certyfikat jest ważny i podpisany przez certyfikat, któremu ufasz. Ale w typowych scenariuszach wiesz, że CN nie będzie pasować do nazwy hosta, z którą się łączyłeś. W tym celu ustaw ServerName na tls.Config. Jeśli tls.Config.ServerName == remoteServerCN, to sprawdzenie certyfikatu zakończy się pomyślnie. To jest to, czego chcesz. InsecureSkipVerify oznacza, że ​​NIE ma uwierzytelnienia; i jest dojrzałe dla Man-In-the-Middle; pokonując cel używania TLS.

Jest jedno uzasadnione użycie dla InsecureSkipVerify: użyj go, aby połączyć się z hostem i pobrać jego certyfikat, a następnie natychmiast się rozłączyć. Jeśli skonfigurowałeś kod do używania InsecureSkipVerify, to na ogół dlatego, że nie ustawiłeś prawidłowo ServerName (będzie musiał pochodzić z env var lub czegoś - nie boleć z brzucha o tym wymaganiu ... zrób to poprawnie).

W szczególności, jeśli korzystasz z certyfikatów klienta i polegasz na nich w celu uwierzytelnienia, w zasadzie masz fałszywe logowanie, które już się nie loguje. Odmówić kod, który ma InsecureSkipVerify, lub dowiesz się, co jest nie tak z tym trudnym!

+0

Czy znasz stronę, na której mogę to sprawdzić? golang org teraz już nie generuje błędu. – topskip

+0

użyj narzędzi openssl do tworzenia certyfikatów. możesz napisać testy jednostkowe, aby dokładnie to przetestować. – Rob

+0

Ta odpowiedź jest strasznie myląca. Jeśli akceptujesz każdy poprawnie podpisany certyfikat niezależnie od nazwy hosta, nadal nie uzyskujesz prawdziwych zabezpieczeń. Mogę łatwo uzyskać ważny certyfikat dla dowolnych domen, które kontroluję; jeśli masz zamiar podać moją nazwę hosta do sprawdzenia TLS, tracisz potwierdzenie, że naprawdę jestem tym, za kogo się podaje. W tym momencie fakt, że certyfikat jest "zgodny", nie ma znaczenia; to jest nie w porządku, a ty jesteś podatny na człowieka w środku. –

Powiązane problemy