Come fare una richiesta HTTPS con certificato non valido?


128

Di 'che voglio ottenere https://golang.orgprogrammaticamente. Attualmente golang.org (ssl) ha un certificato non valido che viene rilasciato a *.appspot.comQuindi quando eseguo questo:

package main

import (
    "log"
    "net/http"
)

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

Ottengo (come mi aspettavo)

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

Ora, voglio fidarmi di questo certificato (immagina un certificato auto-emesso in cui posso convalidare l'impronta digitale ecc.): Come posso fare una richiesta e convalidare / fidarmi del certificato?

Probabilmente ho bisogno di usare openssl per scaricare il certificato, caricarlo nel mio file e riempire tls.Configstruct!?


5
questo non è un "certificato non valido", è un certificato con un CN diverso. InsecureSkipVerify non è un uso legittimo qui. È necessario impostare ServerName in tls.Config in modo che corrisponda a ciò a cui si sta tentando di connettersi. Questo post StackOverflow sta causando la diffusione di questo grande buco di sicurezza nel codice Go ovunque. InsecureSkipVerify non controlla TUTTO il certificato. Quello che vuoi è verificare che il certificato sia stato legittimamente firmato da un'entità fidata, anche se il CN non corrisponde al nome host. Tunnel e NATS possono legittimamente causare una mancata corrispondenza.
Rob,

Risposte:


283

Nota sulla sicurezza: disabilitare i controlli di sicurezza è pericoloso e dovrebbe essere evitato

È possibile disabilitare i controlli di sicurezza a livello globale per tutte le richieste del client predefinito:

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

È possibile disabilitare il controllo di sicurezza per un client:

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
Mi chiedo dove mettere un certificato attendibile in modo che la connessione possa essere utilizzata senza InsecureSkipVerify: true. È possibile?
inizio

7
NameToCertificatepotrebbe aiutare, consultare la tls.Configdocumentazione: golang.org/pkg/crypto/tls/#Config
cyberdelia

1
Ecco un esempio per l'aggiunta di pool di certificati CA personalizzati: golang.org/pkg/crypto/tls/#example_Dial È possibile utilizzarlo anche in un client HTTP.
Bitborato l'

7
Molte persone finiscono qui per provare a disabilitare i controlli dei nomi host (non disabilitando completamente i controlli dei certificati). Questa è la risposta sbagliata Go richiede di impostare ServerName nella configurazione tls in modo che corrisponda al CN dell'host a cui ci si sta connettendo, se non è il nome DNS con cui ci si è connessi. InsecureSkipVerify non è più sicuro di un semplice vecchio telnet alla porta. Non c'è autenticazione con questa impostazione. Utente ServerName invece!
Rob,

8
Attenzione: un trasporto creato in questo modo utilizza valori zero per la maggior parte dei suoi campi e quindi perde tutti i valori predefiniti . Come suggerisce la risposta di seguito , potresti copiarli. Ci siamo divertiti molto a capire perché stiamo esaurendo i descrittori di file , perché abbiamo perso il file Dialer.Timeout.
mknecht,

26

Ecco un modo per farlo senza perdere le impostazioni predefinite di DefaultTransport, e senza bisogno della falsa richiesta come da commento dell'utente.

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

AGGIORNARE

Modo più breve:

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

Modo corretto (a partire da Go 1.13) (fornito dalla risposta di seguito ):

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

Avvertenza : solo a scopo di test / sviluppo. Nient'altro, procedi a tuo rischio e pericolo !!!


non sarebbe più semplice semplicemente copiare le impostazioni di trasporto predefinite usando mytransportsettings := &(*http.DefaultTransport.(*http.Transport))e quindi modificando la configurazione del client TLS mytransportsettings.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}?
TheDiveO

Vale la pena provare, penso che stavo cercando di assicurarmi di non modificare il vero DefaultTransport
Jonathan Lin

1
questo assicura una copia superficiale, come hai fatto tu, che è sufficiente per il caso d'uso discusso. In realtà sto distribuendo questo nel codice di lavoro.
TheDiveO

19

Tutte queste risposte sono sbagliate! Non utilizzare InsecureSkipVerifyper gestire una CN che non corrisponde al nome host. Gli sviluppatori Go sono stati sgarbatamente irremovibili di non disabilitare i controlli dei nomi host (che hanno usi legittimi - tunnel, nat, certificati cluster condivisi, ecc.), Pur avendo qualcosa che sembra simile ma in realtà ignora completamente il controllo del certificato. Devi sapere che il certificato è valido e firmato da un certificato di cui ti fidi. Ma in scenari comuni, sai che la CN non corrisponderà al nome host con cui ti sei connesso. Per chi, impostare ServerNamesu tls.Config. Se tls.Config.ServerName== remoteServerCN, il controllo del certificato avrà esito positivo. Questo è quello che vuoi. InsecureSkipVerifysignifica che NON esiste autenticazione; ed è maturo per un Man-In-The-Middle; sconfiggere lo scopo dell'utilizzo di TLS.

C'è un uso legittimo per InsecureSkipVerify: usarlo per connettersi a un host e prendere il suo certificato, quindi disconnettersi immediatamente. Se configuri il tuo codice per l'uso InsecureSkipVerify, è generalmente perché non hai impostato ServerNamecorrettamente (dovrà provenire da un ambiente o qualcosa del genere - non mal di pancia per questo requisito ... fallo correttamente).

In particolare, se usi certificati client e fai affidamento su di essi per l'autenticazione, in pratica hai un accesso falso che in realtà non effettua più l'accesso. Rifiuta il codice che lo fa InsecureSkipVerify, o imparerai cosa c'è di sbagliato in esso nel modo più duro!


1
Ti capita di conoscere un sito dove posso provarlo? Golang Org ora non genera più un errore.
topskip

3
Questa risposta è terribilmente fuorviante. Se si accetta un certificato validamente firmato indipendentemente dal nome host, non si ottiene ancora la sicurezza reale. Posso facilmente ottenere un certificato valido per tutti i domini che controllo; se hai intenzione di specificare il mio nome host per il controllo TLS, perdi la convalida che io sono davvero quello che dico di essere. A quel punto, il fatto che il certificato sia "legittimo" non ha importanza; è ancora sbagliato e sei ancora vulnerabile all'uomo nel mezzo.
Daniel Farrell,

5
In un'impresa in cui in realtà non ti fidi di nessuna delle CA commerciali (ovvero: se sono al di fuori degli Stati Uniti per esempio) e sostituisci con una CA per la tua impresa, devi solo confermare che questa è una delle tue certificazioni. Il controllo del nome host è per le situazioni in cui gli utenti si aspettano che il nome host corrisponda, ma il DNS non è sicuro. Nell'azienda, generalmente ci si connette a un cluster di macchine in cui non è possibile far corrispondere il nome host / IP, poiché si tratta di cloni esatti di una macchina generata con nuovi IP. Il nome DNS trova il certificato e certificato è l'id, non il nome DNS.
Rob,

3
l'idea è che il codice client si fidi solo della CA aziendale. è in realtà molto più sicuro del sistema CA attualmente in uso. In tal caso, nulla (Thawte, Versign, ecc.) ... è attendibile. Solo la CA che gestiamo. I browser Web hanno enormi elenchi di fiducia. I servizi che parlano tra loro hanno solo una CA nel suo file di fiducia.
Rob,

1
grazie @Rob Ho una configurazione identica in cui i nostri servizi si affidano solo alla stessa CA singola e nient'altro. Questa è un'informazione vitale e molto aiuto.
user99999991

8

Il modo corretto per eseguire questa operazione se si desidera mantenere le impostazioni di trasporto predefinite è ora (a partire da Go 1.13):

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

Transport.Clone esegue una copia approfondita del trasporto. In questo modo non devi preoccuparti di perdere nuovi campi che vengono aggiunti alla Transportstruttura nel tempo.


7

Se si desidera utilizzare le impostazioni predefinite dal pacchetto http, quindi non è necessario creare un nuovo oggetto Transport and Client, è possibile modificare per ignorare la verifica del certificato in questo modo:

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

7
Ciò comporterebbepanic: runtime error: invalid memory address or nil pointer dereference
OscarRyz il

6
Se non si utilizza prima il richiedente http predefinito, è necessario forzare una richiesta falsa in modo che il trasporto predefinito sia inizializzato
Cornel Damian

1
questo non disabilita i controlli del nome host. disabilita tutti i controlli dei certificati. Go ti costringe a impostare ServerName uguale alla CN nel certificato di ciò a cui ti connetti. InsecureSkipVerify si connetterà a un server MITM non autorizzato che finge di inoltrare ai servizi reali. L'UNICO uso legittimo per un InsecureSkipVerify è quello di afferrare il certificato dell'estremità remota e disconnettersi immediatamente.
Rob,

Questo va bene solo se si specifica ANCHE un VerifyPeerCertificate. Se hai appena impostato InsecureSkipVerify, questo non controlla affatto. Ma è stato aggiunto un certificato VerifyPeer in modo da poter riscrivere il controllo per fare ciò di cui hai bisogno. Potresti voler ignorare il nome host o forse anche la data di scadenza. Google per varie implementazioni di VerifyPeerCertificate che lo fanno.
Rob

0

In genere, il dominio DNS dell'URL DEVE corrispondere all'oggetto certificato del certificato.

In passato ciò poteva avvenire impostando il dominio come cn del certificato o impostando il dominio come Nome alternativo soggetto.

Il supporto per cn è stato deprecato per molto tempo (dal 2000 in RFC 2818 ) e il browser Chrome non guarderà più nemmeno il cn, quindi oggi è necessario avere il dominio DNS dell'URL come nome alternativo soggetto.

RFC 6125 che proibisce il controllo del cn se è presente il dominio SAN per DNS, ma non se è presente l'indirizzo SAN per IP. RFC 6125 ripete anche che cn è deprecato, come già detto in RFC 2818. E 'presente il forum del browser dell'autorità di certificazione che, in combinazione con RFC 6125, significa essenzialmente che cn non verrà mai controllato per il nome di dominio DNS.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.