“Kết nối cơ bản đã bị đóng: Đã xảy ra lỗi không mong muốn khi gửi.” Với chứng chỉ SSL


119

Vấn đề: Tôi nhận được ngoại lệ này "KẾT NỐI DƯỚI ĐÂY ĐÃ ĐÓNG CỬA: LỖI KHÔNG PHÁT HIỆN ĐƯỢC THÀNH CÔNG KHI GỬI" trong nhật ký của tôi và nó đang phá vỡ sự tích hợp OEM của chúng tôi với hệ thống tiếp thị qua email của chúng tôi vào những thời điểm ngẫu nhiên thay đổi từ [1 giờ - 4 giờ]

Trang web của tôi được lưu trữ trên máy chủ windows 2008 R2 với IIS 7.5.7600. Trang web này có một số lượng lớn các thành phần OEM và bảng điều khiển toàn diện. Mọi thứ hoạt động tốt với tất cả các yếu tố khác của trang web ngoại trừ một trong các thành phần tiếp thị qua email của chúng tôi mà chúng tôi đang sử dụng như một giải pháp iframe trong bảng điều khiển của chúng tôi. Cách hoạt động của nó là, tôi gửi một httpWebRequestobject với tất cả thông tin đăng nhập và tôi nhận lại được một url mà tôi đã đặt trong iframe và nó hoạt động. Nhưng nó chỉ hoạt động trong một khoảng thời gian [1 giờ - 4 giờ] và sau đó tôi nhận được ngoại lệ dưới đây "KẾT NỐI DƯỚI ĐÂY ĐÃ ĐƯỢC ĐÓNG CỬA: MỘT LỖI KHÔNG PHÁT HIỆN ĐƯỢC PHÁT HIỆN TRÊN GỬI" và ngay cả khi hệ thống cố gắng lấy URL từ httpWebRequest nó không thành công với cùng một ngoại lệ. Cách duy nhất để làm cho nó hoạt động trở lại là tái chế nhóm ứng dụng hoặc bất kỳ thứ gì được chỉnh sửa trong web.config.

Tùy chọn đã thử

Đã thêm rõ ràng, keep-alive = false

keep-alive = true

Tăng thời gian chờ: <httpRuntime maxRequestLength="2097151" executionTimeout="9999999" enable="true" requestValidationMode="2.0" />

Tôi đã tải trang này lên một trang web không có SSL để kiểm tra xem chứng chỉ SSL trên máy chủ sản xuất của chúng tôi có đang thực hiện kết nối để giảm một số cách hay không.

Bất kỳ hướng giải quyết nào đều được đánh giá rất cao.

Mã:

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`

Bạn đã bao giờ con số này ra?
Brett G

11
vâng, tôi đã có thể làm cho nó hoạt động với mã này ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls Hoặc SecurityProtocolType.Ssl3
Arvind Morwal

Tôi sắp chết vì vấn đề tương tự. Tôi đã mất vài giờ vật lộn với cùng một vấn đề. Cảm ơn bạn đã bình luận, nó đã lưu ngày của tôi.
Sameers Javed

2
@ user3458212 bạn nên thêm nhận xét của bạn vào như một câu trả lời
icc97

2
Trong trường hợp của tôi, chạy trang web trong Visual Studio 15 mọi thứ đều ổn, nhưng cuối cùng, vì tôi không thể nâng cấp khung trong máy chủ và buộc TLS 1.2 và tắt tính năng giữ sống không hoạt động, tôi phải thiết lập một trung gian máy chủ web để ủy quyền máy chủ web mục tiêu làm rớt kết nối.
José Roberto García Chico

Câu trả lời:


193

Đối với tôi đó là tls12:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

42
Lưu ý rằng bạn phải cẩn thận vì thay đổi này là toàn cầu đối với AppDomain của bạn và sẽ khiến các cuộc gọi đến bất kỳ trang web nào không cung cấp TLS 1.2 không thành công (bạn có thể thích điều này nếu dữ liệu được vận chuyển thực sự nhạy cảm). Để thích TLS 1.2 nhưng vẫn cho phép 1.1 và 1.0, bạn phải HOẶC chúng:ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
Dusty

tương tự ở đây, bạn đã cứu mạng tôi, đã dành rất nhiều thời gian để tìm ra những gì đã xảy ra với RestSharp
darul75

Giải pháp này cũng hoạt động cho những người không sử dụng RestSharp cũng như cho những người không sử dụng ServicePointManager. Chỉ cần sao chép và dán dòng trên trước lệnh gọi WebRequest của bạn hoặc bất cứ thứ gì bạn đang sử dụng để thực hiện yêu cầu. Ban đầu tôi bỏ qua giải pháp này vì những lý do trên.
goku_da_master

hoặc chỉ thêm nó vào những gì đã có ... System.Net.ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;
uosjead

8
Để thực hiện việc này trong PowerShell, hãy "nhị phân hoặc" chúng kết hợp với nhau như vậy:[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls
Adam S

62

Nếu bạn gặp khó khăn với .Net 4.0 và trang web đích đang sử dụng TLS 1.2, bạn cần dòng sau để thay thế. ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;

nguồn: TLS 1.2 và Hỗ trợ .NET: Cách tránh lỗi kết nối


5
Tuyệt vời! Tôi chỉ cần thêm rằng (SecurityProtocolType)768có thể được sử dụng cho "Tls11" (tức là TLS 1.1).
Solomon Rutzky

2
Điều này thực sự hữu ích. Nó đã cứu một ngày của tôi. Tôi phải gắn bó với .Net 2.0.
Hao Nguyen

22

Đoạn mã dưới đây đã giải quyết được sự cố

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls Or SecurityProtocolType.Ssl3

5
Tuy nhiên, điều này sẽ hoạt động, hãy nhớ rằng đó ServicePointManager.SecurityProtocollà một đối tượng tĩnh có nghĩa là việc thay đổi giá trị này sẽ ảnh hưởng đến tất cả các chuỗi con WebRequesthoặc WebClientlệnh gọi. Bạn có thể tạo riêng biệt AppDomainnếu bạn muốn ServicePointManagercó các cài đặt khác nhau. Xem stackoverflow.com/questions/3791629/… để biết thêm chi tiết.
stack247

1
Đọc thêm hữu ích để hiểu những gì mã này được thực hiện: stackoverflow.com/questions/26389899/...
Jon Schneider

@Marnee tôi đặt nó trong thư mục gốc thành phần ứng dụng của tôi, vì vậy nó được thiết lập trước khi bất kỳ I / O bao giờ xảy ra
JG trong SD

@Marnee Đặt nó trong một phương thức khởi tạo tĩnh, vì vậy nó được thực thi chính xác một lần, lần đầu tiên lớp được truy cập. Mặc dù vậy, tôi đã phải bật tất cả các giao thức để bao gồm tất cả các trường hợp.
Nyerguds

14

Tôi đã gặp vấn đề tương tự trong nhiều ngày nay với một tích hợp cũng chỉ "từng hoạt động trước đây".

Thoát khỏi trầm cảm tuyệt đối, tôi chỉ cố gắng

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

Điều này đã giải quyết nó cho tôi .. mặc dù việc tích hợp chỉ sử dụng SSLv3.

Tôi nhận ra rằng có điều gì đó xảy ra khi Fiddler báo cáo rằng có một "mật mã thương lượng TLS trống" hoặc một cái gì đó tương tự.

Hy vọng rằng nó hoạt động!


Lưu ý rằng, ngay cả khi mã của bạn không cần TLS, nếu máy chủ mà nó đang giao tiếp với DOES, nó sẽ cố gắng thương lượng với TLS và thất bại nếu không thể. Mật mã thương lượng TLS trống là vị trí mong đợi trao đổi giao thức TLS mà bạn cuối cùng đã cung cấp. Nó có khả năng "từng hoạt động trước đây" vì quản trị viên máy chủ có thể vừa bật TLS trên máy chủ mà ứng dụng của bạn đang giao tiếp.
vapcguy

13

Trong trường hợp của tôi, trang web mà tôi đang kết nối đã nâng cấp lên TLS 1.2. Do đó, tôi phải cài đặt .net 4.5.2 trên máy chủ web của mình để hỗ trợ nó.


Điều này có thể được thực hiện ở cấp đăng ký trên máy không? Tôi đã vô hiệu hóa tất cả các giao thức SSL, để lại TLS 1.0, 1.1, 1.2, tuy nhiên, tôi hiểu rằng bất kỳ thứ gì nhỏ hơn TLS 1.2 sẽ sớm bị loại bỏ để tuân thủ PCI.
brendo234

12

Truy cập web.config / App.config của bạn để xác minh thời gian chạy .net nào bạn đang sử dụng

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

Đây là giải pháp:

  1. .NET 4.6 trở lên. Bạn không cần thực hiện thêm bất kỳ công việc nào để hỗ trợ TLS 1.2, nó được hỗ trợ theo mặc định.

  2. .NET 4.5. TLS 1.2 được hỗ trợ, nhưng nó không phải là giao thức mặc định. Bạn cần chọn tham gia để sử dụng nó. Mã sau sẽ đặt TLS 1.2 làm mặc định, hãy đảm bảo thực thi nó trước khi thực hiện kết nối với tài nguyên được bảo mật:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12

  1. .NET 4.0. TLS 1.2 không được hỗ trợ, nhưng nếu bạn đã cài đặt .NET 4.5 (trở lên) trên hệ thống thì bạn vẫn có thể chọn tham gia TLS 1.2 ngay cả khi khung ứng dụng của bạn không hỗ trợ nó. Vấn đề duy nhất là SecurityProtocolType trong .NET 4.0 không có mục nhập cho TLS1.2, vì vậy chúng tôi sẽ phải sử dụng biểu diễn số của giá trị enum này:

ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;

  1. .NET 3.5 trở xuống. TLS 1.2 không được hỗ trợ (*) và không có giải pháp thay thế. Nâng cấp ứng dụng của bạn lên phiên bản mới hơn của khuôn khổ.

6

Tôi nhận thấy rằng đây là dấu hiệu cho thấy máy chủ nơi bạn đang triển khai mã đã cài đặt khuôn khổ .NET cũ không hỗ trợ TLS 1.1 hoặc TLS 1.2. Các bước khắc phục:

  1. Cài đặt .NET Runtime mới nhất trên máy chủ sản xuất của bạn (IIS & SQL)
  2. Cài đặt .NET Developer Pack mới nhất trên máy phát triển của bạn.
  3. Thay đổi cài đặt "Khung mục tiêu" trong các dự án Visual Studio của bạn thành khung .NET mới nhất.

Bạn có thể tải .NET Developer Pack và Runtime mới nhất từ ​​URL này: http://getdotnet.azurewebsites.net/target-dotnet-platforms.html


Đã thay đổi khung mục tiêu từ 4.5.2 thành 4.6.1 và bắt đầu hoạt động, cảm ơn Patrick.
Vivek Sharma

4

Chúng tôi gặp sự cố này, theo đó một trang web đang truy cập API của chúng tôi nhận được thông báo "Kết nối cơ bản đã bị đóng: Đã xảy ra lỗi không mong muốn khi gửi." thông điệp.

Mã của họ là sự kết hợp của .NET 3.x và 2.2, theo tôi hiểu thì có nghĩa là họ đang sử dụng TLS 1.0.

Câu trả lời dưới đây có thể giúp bạn chẩn đoán sự cố bằng cách bật TLS 1.0, SSL 2 và SSL3, nhưng rất rõ ràng, bạn không muốn làm điều đó lâu dài vì cả ba giao thức đó đều được coi là không an toàn và không nên nữa đã sử dụng :

Để IIS của chúng tôi phản hồi các lệnh gọi API của họ, chúng tôi phải thêm cài đặt đăng ký trên máy chủ của IIS để kích hoạt các phiên bản TLS một cách rõ ràng - LƯU Ý: Bạn phải khởi động lại máy chủ Windows (không chỉ dịch vụ IIS) sau khi thực hiện các thay đổi này:

[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

Nếu điều đó không hiệu quả, bạn cũng có thể thử nghiệm thêm mục nhập cho 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

Để rõ ràng, đây không phải là một giải pháp hay và giải pháp phù hợp là yêu cầu người gọi sử dụng TLS 1.2, nhưng những điều trên có thể giúp chẩn đoán rằng đây là vấn đề.

Bạn có thể tăng tốc độ thêm các mục đăng ký đó bằng tập lệnh powershell này:

$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

Đó là phiên bản đã sửa đổi của tập lệnh từ trang trợ giúp của Microsoft về Thiết lập TLS cho VMM . Bài viết basics.net này là trang ban đầu cho tôi ý tưởng để xem các cài đặt này.


Vấn đề của chúng tôi là xung quanh một đường dẫn phát hành qua Team City đột ngột dừng lại khi chúng tôi thay đổi chứng chỉ cho máy chủ trực tiếp của bạn. Chúng tôi đã thay đổi máy chủ để chỉ sử dụng TLS1.2 và đường dẫn Team City của chúng tôi ngừng hoạt động ... Hoạt động như một giấc mơ ... đã thêm các mục đăng ký và khởi động lại máy chủ ... BÙM !!! Cảm ơn tomRedox !!
Gwasshoppa

@Gwasshoppa, chỉ để nhắc lại rằng phần trên chỉ là một sơ đồ dừng để chẩn đoán sự cố. Bây giờ bạn biết đó là vấn đề phiên bản TLS, giải pháp là thay đổi đường dẫn phát hành để nó có thể hoạt động với TLS1.2 và sau đó tắt TLS <1.2 và SSL 2 và 3 một lần nữa. Tôi đã cập nhật câu trả lời ở trên một chút để nhấn mạnh điều đó.
tomRedox

4

Chỉ cần thêm:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;


1
Vui lòng cung cấp lời giải thích với câu trả lời của bạn.
Word Rearranger

4
Câu trả lời này cũng không bổ sung gì cho những câu trước.
Arvindh Mani

2

Nó nếu giúp ai đó, thì vấn đề của chúng tôi là thiếu chứng chỉ. Môi trường là Windows Server 2016 Standard với .Net 4.6.

Có một dịch vụ WCF tự lưu trữ https URI, mà Service.Open () sẽ thực thi mà không có lỗi. Một chuỗi khác sẽ tiếp tục truy cập https: // OurIp: 443 / OurService? Wsdl để đảm bảo rằng dịch vụ có sẵn. Không thể truy cập WSDL được sử dụng với:

Kết nối cơ bản đã bị đóng: Đã xảy ra lỗi không mong muốn khi gửi.

Sử dụng ServicePointManager.SecurityProtocol với các cài đặt áp dụng không hoạt động. Chơi với các vai trò và tính năng của máy chủ cũng không giúp được gì. Sau đó, đến Jaise George , SE, giải quyết vấn đề trong vài phút. Jaise đã cài đặt chứng chỉ tự ký trong IIS, giải quyết vấn đề. Đây là những gì anh ấy đã làm để giải quyết vấn đề:

(1) Mở trình quản lý IIS (inetmgr) (2) Nhấp vào nút máy chủ trong bảng điều khiển bên trái và nhấp đúp vào "Chứng chỉ máy chủ". (3) Nhấp vào "Tạo chứng chỉ tự ký" trên bảng bên phải và nhập bất cứ thứ gì bạn muốn cho tên thân thiện. (4) Nhấp vào "Trang web mặc định" trong bảng điều khiển bên trái, nhấp vào "Liên kết" trên bảng điều khiển bên phải, nhấp vào "Thêm", chọn "https", chọn chứng chỉ bạn vừa tạo và nhấp vào "OK" (5) Truy cập URL https, nó phải có thể truy cập được.


Tuy nhiên, bạn sẽ nghĩ rằng quản trị viên máy chủ sẽ thêm chứng chỉ SSL! Ôi! lol :) Tôi có thể thấy điều này đang xảy ra - hoặc một chứng chỉ đã hết hạn cần gia hạn có thể sẽ là tình huống áp dụng hơn.
vapcguy

2

Bạn chỉ cần thay đổi phiên bản ứng dụng của mình như 4.0 thành 4.6 và xuất bản các mã đó.

Đồng thời thêm các dòng mã bên dưới:

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

1

Sử dụng proxy gỡ lỗi HTTP có thể gây ra điều này - chẳng hạn như Fiddler.

Tôi đang tải chứng chỉ PFX từ một tệp cục bộ (xác thực cho Apple.com) và nó không thành công vì Fiddler không thể chuyển chứng chỉ này vào.

Thử tắt Fiddler để kiểm tra và nếu đó là giải pháp thì có lẽ bạn cần phải cài đặt chứng chỉ trên máy của mình hoặc theo một cách nào đó mà Fiddler có thể sử dụng nó.


0

Đoạn mã dưới đây đã giải quyết được vấn đề của tôi:

request.ProtocolVersion = HttpVersion.Version10; // THIS DOES THE TRICK
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.