“Sambungan pokok ditutup: Terjadi kesalahan tak terduga pada pengiriman.” Dengan Sertifikat SSL

120

Masalah: Saya mendapatkan pengecualian ini "THE UNDERLYING CONNECTION WAS CLOSED: AN UNEXPECTED ERROR OCCURRED ON A SEND" di log saya dan ini merusak integrasi OEM kami dengan sistem pemasaran email kami pada waktu acak yang bervariasi dari [1jam - 4 jam]

Situs web saya di-host di windows server 2008 R2 dengan IIS 7.5.7600. Situs web ini memiliki sejumlah besar komponen OEM dan dasbor yang komprehensif. Semuanya berfungsi dengan baik dengan semua elemen lain dari situs web kecuali dengan salah satu komponen pemasaran email kami yang kami gunakan sebagai solusi iframe di dalam dasbor kami. Cara kerjanya adalah, saya mengirim objek httpWebRequest dengan semua kredensial dan saya mendapatkan kembali url yang saya masukkan ke dalam iframe dan berfungsi. Tapi itu hanya bekerja untuk beberapa waktu [1 jam - 4 jam] dan kemudian saya mendapatkan pengecualian di bawah ini "THE UNDERLYING CONNECTION WAS CLOSED: AN UNEXPECTED ERROR OCCURRED ON A SEND" dan bahkan jika sistem mencoba untuk mendapatkan URL dari httpWebRequest itu gagal dengan pengecualian yang sama. Satu-satunya cara untuk membuatnya berfungsi kembali adalah dengan mendaur ulang kumpulan aplikasi atau apa pun yang diedit di web.config.

Opsi mencoba

Ditambahkan secara eksplisit, keep-alive = false

keep-alive = true

Meningkatkan waktu istirahat: <httpRuntime maxRequestLength="2097151" executionTimeout="9999999" enable="true" requestValidationMode="2.0" />

Saya telah mengunggah halaman ini ke situs web non SSL untuk memeriksa apakah sertifikat SSL di server produksi kami membuat koneksi untuk menjatuhkan beberapa caranya.

Segala arah menuju resolusi sangat dihargai.

Kode:

Public Function CreateHttpRequestJson(ByVal url) As String
    Try
        Dim result As String = String.Empty
        Dim httpWebRequest = DirectCast(WebRequest.Create("https://api.xxxxxxxxxxx.com/api/v3/externalsession.json"), HttpWebRequest)
        httpWebRequest.ContentType = "text/json"
        httpWebRequest.Method = "PUT"
        httpWebRequest.ContentType = "application/x-www-form-urlencoded"
        httpWebRequest.KeepAlive = False
        'ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3

        'TODO change the integratorID to the serviceproviders account Id, useremail 
        Using streamWriter = New StreamWriter(httpWebRequest.GetRequestStream())
            Dim json As String = New JavaScriptSerializer().Serialize(New With { _
            Key .Email = useremail, _
            Key .Chrome = "None", _
            Key .Url = url, _
            Key .IntegratorID = userIntegratorID, _
            Key .ClientID = clientIdGlobal _
            })

            'TODO move it to the web.config, Following API Key is holonis accounts API Key
            SetBasicAuthHeader(httpWebRequest, holonisApiKey, "")
            streamWriter.Write(json)
            streamWriter.Flush()
            streamWriter.Close()

            Dim httpResponse = DirectCast(httpWebRequest.GetResponse(), HttpWebResponse)
            Using streamReader = New StreamReader(httpResponse.GetResponseStream())
                result = streamReader.ReadToEnd()
                result = result.Split(New [Char]() {":"})(2)
                result = "https:" & result.Substring(0, result.Length - 2)
            End Using
        End Using
        Me.midFrame.Attributes("src") = result
    Catch ex As Exception
        objLog.WriteLog("Error:" & ex.Message)
        If (ex.Message.ToString().Contains("Invalid Email")) Then
            'TODO Show message on UI
        ElseIf (ex.Message.ToString().Contains("Email Taken")) Then
            'TODO Show message on UI
        ElseIf (ex.Message.ToString().Contains("Invalid Access Level")) Then
            'TODO Show message on UI
        ElseIf (ex.Message.ToString().Contains("Unsafe Password")) Then
            'TODO Show message on UI
        ElseIf (ex.Message.ToString().Contains("Invalid Password")) Then
            'TODO Show message on UI
        ElseIf (ex.Message.ToString().Contains("Empty Person Name")) Then
            'TODO Show message on UI
        End If
    End Try
End Function


Public Sub SetBasicAuthHeader(ByVal request As WebRequest, ByVal userName As [String], ByVal userPassword As [String])
    Dim authInfo As String = Convert.ToString(userName) & ":" & Convert.ToString(userPassword)
    authInfo = Convert.ToBase64String(Encoding.[Default].GetBytes(authInfo))
    request.Headers("Authorization") = "Basic " & authInfo
End Sub`
Arvind Morwal
sumber
Apakah Anda pernah memikirkan hal ini?
Brett G
12
ya saya bisa membuatnya berfungsi dengan kode ini ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls Atau SecurityProtocolType.Ssl3
Arvind Morwal
Saya akan mati untuk masalah yang sama. Butuh waktu beberapa jam untuk berjuang dengan masalah yang sama. Terima kasih atas komentar Anda, itu menyelamatkan hari saya.
Sameers Javed
2
@ user3458212 Anda harus menambahkan komentar Anda sebagai jawaban
icc97
2
Dalam kasus saya, menjalankan situs web di Visual Studio 15 semuanya berjalan dengan baik, tetapi pada akhirnya, karena saya tidak dapat memutakhirkan kerangka kerja di server, dan memaksa TLS 1.2 dan menonaktifkan tetap-hidup tidak berfungsi, saya harus menyiapkan perantara server web untuk mem-proxy server web target yang memutuskan koneksi.
José Roberto García Chico

Jawaban:

194

Bagi saya itu tls12:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
Lanklaas
sumber
42
Perhatikan bahwa Anda harus berhati-hati karena perubahan ini bersifat global untuk AppDomain Anda, dan akan menyebabkan panggilan ke situs apa pun yang tidak menawarkan TLS 1.2 gagal (yang mungkin Anda pilih jika data yang akan dikirim benar-benar sensitif). Untuk memilih TLS 1.2 tetapi masih mengizinkan 1.1 dan 1.0, Anda harus ATAU mereka:ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
Dusty
sama di sini, Anda menyelamatkan hidup saya, menghabiskan begitu banyak waktu untuk mencari tahu apa yang salah dengan RestSharp
darul75
Solusi ini juga berfungsi untuk mereka yang tidak menggunakan RestSharp serta mereka yang tidak menggunakan ServicePointManager. Cukup salin dan tempel baris di atas sebelum panggilan WebRequest Anda atau apa pun yang Anda gunakan untuk membuat permintaan. Saya awalnya mengabaikan solusi ini karena alasan di atas.
goku_da_master
atau tambahkan saja ke yang sudah ada ... System.Net.ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;
uosjead
8
Untuk melakukan ini di PowerShell, "biner atau" bersama-sama seperti ini:[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls
Adam S
64

Jika Anda terjebak dengan .Net 4.0 dan situs target menggunakan TLS 1.2, Anda memerlukan baris berikut. ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;

sumber: TLS 1.2 dan .NET Dukungan: Cara Mencegah Kesalahan Sambungan

Tochi
sumber
5
Hebat! Saya hanya akan menambahkan yang (SecurityProtocolType)768dapat digunakan untuk "Tls11" (yaitu TLS 1.1).
Solomon Rutzky
2
Ini sangat membantu. Ini menyelamatkan hari saya. Saya harus tetap menggunakan .Net 2.0.
Hao Nguyen
24

Kode di bawah menyelesaikan masalah

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls Or SecurityProtocolType.Ssl3
Arvind Morwal
sumber
6
Ini akan berhasil, bagaimanapun, perlu diingat bahwa itu ServicePointManager.SecurityProtocoladalah objek statis yang berarti mengubah nilai ini akan memengaruhi semua sub-urutan WebRequestatau WebClientpanggilan. Anda dapat membuat terpisah AppDomainjika Anda ingin ServicePointManagermemiliki pengaturan yang berbeda. Lihat stackoverflow.com/questions/3791629/… untuk lebih jelasnya.
stack247
1
Bacaan tambahan yang berguna untuk memahami apa yang dilakukan kode ini: stackoverflow.com/questions/26389899/…
Jon Schneider
@Marnee Saya meletakkannya di root komposisi aplikasi saya, jadi ini disetel sebelum I / O apa pun terjadi
JG di SD
@Marnee Letakkan di konstruktor statis, sehingga dijalankan tepat sekali, pertama kali kelas diakses. Saya harus mengaktifkan semua protokol, untuk mencakup semua kasus.
Nyerguds
14

Saya telah mengalami masalah yang sama selama berhari-hari sekarang dengan integrasi yang juga "dulu berfungsi sebelumnya".

Karena depresi belaka, saya hanya mencoba

 ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Ssl3;

Ini memecahkannya untuk saya .. meskipun integrasinya hanya menggunakan SSLv3.

Saya menyadari bahwa ada sesuatu yang mati sejak Fiddler melaporkan mengatakan bahwa ada "cipher negosiasi TLS kosong" atau semacamnya.

Semoga berhasil!

Medismal
sumber
Perhatikan bahwa, meskipun kode Anda tidak memerlukan TLS, jika server yang berkomunikasi dengan DOES, ia akan mencoba untuk bernegosiasi dengan TLS dan gagal jika tidak bisa. Sandi negosiasi TLS yang kosong adalah slot yang mengharapkan pertukaran protokol TLS yang akhirnya Anda berikan. Sepertinya "dulu berfungsi sebelumnya" karena admin server mungkin baru saja mengaktifkan TLS di server yang digunakan untuk berkomunikasi dengan aplikasi Anda.
vapcguy
13

Dalam kasus saya, situs yang saya sambungkan telah ditingkatkan ke TLS 1.2. Akibatnya saya harus menginstal .net 4.5.2 di server web saya untuk mendukungnya.

aboy021
sumber
Dapatkah ini dilakukan di tingkat registri pada mesin? Saya telah menonaktifkan semua protokol SSL, meninggalkan TLS 1.0, 1.1, 1.2, namun menurut pemahaman saya bahwa apa pun yang kurang dari TLS 1.2 harus segera dihapus agar sesuai dengan PCI.
brendo234
13

Buka web.config / App.config Anda untuk memverifikasi runtime .net mana yang Anda gunakan

  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
  </startup>

Inilah solusinya:

  1. .NET 4.6 dan yang lebih baru. Anda tidak perlu melakukan pekerjaan tambahan apa pun untuk mendukung TLS 1.2, ini didukung secara default.

  2. .NET 4.5. TLS 1.2 didukung, tetapi ini bukan protokol default. Anda harus ikut serta untuk menggunakannya. Kode berikut akan menjadikan TLS 1.2 default, pastikan untuk mengeksekusinya sebelum membuat koneksi ke sumber daya yang diamankan:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12

  1. .NET 4.0. TLS 1.2 tidak didukung, tetapi jika Anda memiliki .NET 4.5 (atau lebih tinggi) yang diinstal pada sistem, Anda masih dapat memilih TLS 1.2 meskipun kerangka aplikasi Anda tidak mendukungnya. Satu-satunya masalah adalah SecurityProtocolType di .NET 4.0 tidak memiliki entri untuk TLS1.2, jadi kami harus menggunakan representasi numerik dari nilai enum ini:

ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;

  1. .NET 3.5 atau lebih rendah. TLS 1.2 tidak didukung (*) dan tidak ada solusi. Tingkatkan aplikasi Anda ke versi kerangka kerja yang lebih baru.
Guo Huang
sumber
6

Saya menemukan bahwa ini adalah tanda bahwa server tempat Anda menerapkan kode memiliki kerangka kerja .NET lama yang terpasang dan tidak mendukung TLS 1.1 atau TLS 1.2. Langkah-langkah untuk memperbaiki:

  1. Menginstal .NET Runtime terbaru di server produksi Anda (IIS & SQL)
  2. Menginstal Paket Pengembang .NET terbaru di mesin pengembangan Anda.
  3. Ubah pengaturan "Target framework" di proyek Visual Studio Anda ke framework .NET terbaru.

Anda bisa mendapatkan .NET Developer Pack dan Runtime terbaru dari URL ini: http://getdotnet.azurewebsites.net/target-dotnet-platforms.html

Patrick
sumber
Mengubah kerangka kerja target dari 4.5.2 menjadi 4.6.1, dan mulai bekerja, terima kasih Patrick.
Vivek Sharma
4

Kami mengalami masalah ini ketika situs web yang mengakses API kami mendapatkan pesan "Sambungan yang mendasarinya telah ditutup: Terjadi kesalahan yang tidak terduga saat pengiriman." pesan.

Kode mereka adalah campuran dari .NET 3.x dan 2.2, yang menurut saya berarti mereka menggunakan TLS 1.0.

Jawaban di bawah ini dapat membantu Anda mendiagnosis masalah dengan mengaktifkan TLS 1.0, SSL 2 dan SSL3, tetapi untuk memperjelasnya, Anda tidak ingin melakukan itu dalam jangka panjang karena ketiga protokol tersebut dianggap tidak aman dan seharusnya tidak lagi aman. digunakan :

Agar IIS kami merespons panggilan API mereka, kami harus menambahkan pengaturan registri di server IIS untuk secara eksplisit mengaktifkan versi TLS - CATATAN: Anda harus memulai ulang server Windows (bukan hanya layanan IIS) setelah melakukan perubahan ini:

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS
1.0\Client] "DisabledByDefault"=dword:00000000 "Enabled"=dword:00000001

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS
1.0\Server] "DisabledByDefault"=dword:00000000 "Enabled"=dword:00000001

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS
1.1\Client] "DisabledByDefault"=dword:00000000 "Enabled"=dword:00000001

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS
1.1\Server] "DisabledByDefault"=dword:00000000 "Enabled"=dword:00000001

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS
1.2\Client] "DisabledByDefault"=dword:00000000 "Enabled"=dword:00000001

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS
1.2\Server] "DisabledByDefault"=dword:00000000 "Enabled"=dword:00000001

Jika tidak berhasil, Anda juga dapat bereksperimen dengan menambahkan entri untuk SSL 2.0:

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Client]
"DisabledByDefault"=dword:00000000
"Enabled"=dword:00000001

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Server]
"DisabledByDefault"=dword:00000000
"Enabled"=dword:00000001

Untuk lebih jelasnya, ini bukan solusi yang bagus , dan solusi yang tepat adalah membuat penelepon menggunakan TLS 1.2, tetapi penjelasan di atas dapat membantu mendiagnosis bahwa inilah masalahnya.

Anda dapat dengan cepat menambahkan entri reg tersebut dengan skrip PowerShell ini:

$ProtocolList       = @("SSL 2.0","SSL 3.0","TLS 1.0", "TLS 1.1", "TLS 1.2")
$ProtocolSubKeyList = @("Client", "Server")
$DisabledByDefault = "DisabledByDefault"
$Enabled = "Enabled"
$registryPath = "HKLM:\\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\"

foreach($Protocol in $ProtocolList)
{
    Write-Host " In 1st For loop"
        foreach($key in $ProtocolSubKeyList)
        {         
            $currentRegPath = $registryPath + $Protocol + "\" + $key
            Write-Host " Current Registry Path $currentRegPath"
            if(!(Test-Path $currentRegPath))
            {
                Write-Host "creating the registry"
                    New-Item -Path $currentRegPath -Force | out-Null             
            }
            Write-Host "Adding protocol"
                New-ItemProperty -Path $currentRegPath -Name $DisabledByDefault -Value "0" -PropertyType DWORD -Force | Out-Null
                New-ItemProperty -Path $currentRegPath -Name $Enabled -Value "1" -PropertyType DWORD -Force | Out-Null    
    }
}
 
Exit 0

Itu adalah versi skrip yang dimodifikasi dari halaman bantuan Microsoft untuk Menyiapkan TLS untuk VMM . Ini artikel basics.net adalah halaman yang awalnya memberi saya ide untuk melihat pengaturan ini.

tomRedox
sumber
Masalah kami adalah seputar pipa rilis melalui Team City yang tiba-tiba berhenti saat kami mengubah sertifikat untuk server langsung Anda. Kami telah mengubah server untuk hanya menggunakan TLS1.2 dan pipeline Team City kami berhenti berfungsi ... Bekerja seperti mimpi ... menambahkan entri regist dan memulai ulang server ... BOOM !!! Terima kasih tomRedox !!
Gwasshoppa
@Gwasshoppa, hanya untuk menegaskan kembali bahwa hal di atas hanya sementara untuk mendiagnosis masalah. Sekarang Anda tahu bahwa ini adalah masalah versi TLS, solusinya adalah mengubah pipeline rilis sehingga dapat bekerja dengan TLS1.2 dan kemudian matikan TLS <1.2 dan SSL 2 dan 3 lagi. Saya telah memperbarui jawaban di atas sedikit untuk menekankan hal itu juga.
tomRedox
4

Tambahkan saja:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

M. Qudah
sumber
1
Mohon berikan penjelasan dengan jawaban Anda.
Word Rearranger
4
Jawaban ini juga tidak menambahkan apa pun ke jawaban sebelumnya.
Arvindh Mani
2

Jika membantu seseorang, masalah kami adalah dengan sertifikat yang hilang. Lingkungan adalah Windows Server 2016 Standard dengan .Net 4.6.

Ada URI https layanan WCF yang dihosting sendiri, di mana Service.Open () akan dijalankan tanpa kesalahan. Utas lain akan tetap mengakses https: // OurIp: 443 / OurService? Wsdl untuk memastikan bahwa layanan itu tersedia. Mengakses WSDL biasanya gagal dengan:

Koneksi yang mendasari ditutup: Terjadi kesalahan yang tidak terduga pada pengiriman.

Menggunakan ServicePointManager.SecurityProtocol dengan pengaturan yang berlaku tidak berfungsi. Bermain dengan peran dan fitur server juga tidak membantu. Kemudian melangkah ke Jaise George , SE, menyelesaikan masalah dalam beberapa menit. Jaise memasang sertifikat yang ditandatangani sendiri di IIS, mengatasi masalah tersebut. Inilah yang dia lakukan untuk mengatasi masalah tersebut:

(1) Buka manajer IIS (inetmgr) (2) Klik pada node server di panel kiri, dan klik dua kali "Sertifikat server". (3) Klik "Buat Sertifikat yang Ditandatangani Sendiri" di panel kanan dan ketik apa pun yang Anda inginkan untuk nama yang ramah. (4) Klik "Situs Web Default" di panel kiri, klik "Bindings" di panel kanan, klik "Tambah", pilih "https", pilih sertifikat yang baru saja Anda buat, dan klik "OK" (5) Akses URL https, itu harus dapat diakses.

Rajin Karma
sumber
Anda pasti mengira admin server akan menambahkan sertifikat SSL! D'oh! lol :) Saya dapat melihat ini terjadi, meskipun - atau sertifikat kedaluwarsa yang perlu diperbarui kemungkinan akan menjadi skenario yang lebih dapat diterapkan.
vapcguy
2

Anda cukup mengubah versi aplikasi Anda seperti 4.0 menjadi 4.6 dan mempublikasikan kode tersebut.

Tambahkan juga baris kode di bawah ini:

httpRequest.ProtocolVersion = HttpVersion.Version10; 
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
Viresh
sumber
1

Menggunakan proxy debugging HTTP dapat menyebabkan ini - seperti Fiddler.

Saya sedang memuat sertifikat PFX dari file lokal (otentikasi ke Apple.com) dan gagal karena Fiddler tidak dapat meneruskan sertifikat ini.

Coba nonaktifkan Fiddler untuk memeriksa dan jika itu solusinya maka Anda mungkin perlu menginstal sertifikat pada mesin Anda atau dengan cara tertentu agar Fiddler dapat menggunakannya.

Simon_Weaver
sumber
0

Kode di bawah ini memecahkan masalah saya:

request.ProtocolVersion = HttpVersion.Version10; // THIS DOES THE TRICK
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
Perangkat Lunak Kolonel
sumber