استكشاف أخطاء التطبيقات التي لا تدعم بروتوكول أمان طبقة النقل الإصدار 1.2 وإصلاحها

هام

تم الآن إهمال Cloud Services (كلاسيكي) للعملاء الجدد وسيتم استبعادها في 31 أغسطس 2024 لجميع العملاء. ينبغي أن تستخدم عمليات النشر الجديدة نموذج النشر الجديد القائم على Azure Resource Manager ‏‏Azure Cloud Services (الدعم الموسع).

توضح هذه المقالة كيفية تمكين بروتوكولات أمان طبقة النقل الأقدم (بروتوكول أمان طبقة النقل الإصداران 1.0 و1.1) بالإضافة إلى تطبيق مجموعات التشفير القديمة لدعم البروتوكولات الإضافية على أدوار العامل وويب خدمة سحابة Windows Server 2019.

نحن نتفهم أنه بينما نتخذ خطوات لإيقاف بروتوكول أمان طبقة النقل الإصدار 1.0 وبروتوكول أمان طبقة النقل الإصدار 1.1، قد يحتاج عملاؤنا إلى دعم البروتوكولات القديمة ومجموعات التشفير حتى يتمكنوا من التخطيط لإيقافها. وفي حين أننا لا نوصي بإعادة تمكين هذه القيم القديمة، إلا إننا نقدم إرشادات لمساعدة العملاء. نحن نشجع العملاء على تقييم مخاطر التراجع قبل تنفيذ التغييرات الموضحة في هذه المقالة.

إشعار

يفرض نظام تشغيل الضيف إصدار Family 6 بروتوكول أمان طبقة النقل الإصدار 1.2 من خلال تعطيل بروتوكول أمان طبقة النقل الإصدار 1.0 وبروتوكول أمان طبقة النقل الإصدار 1.1 بشكل صريح وتحديد مجموعة معينة من مجموعات التشفير. لمزيد من المعلومات حول عائلات نظام تشغيل الضيف، راجع أخبار إصدار نظام تشغيل الضيف

قطع الدعم عن بروتوكول أمان طبقة النقل الإصدار 1.0 وبروتوكول أمان طبقة النقل الإصدار 1.1 ومجموعات التشفير الأقدم

دعماً لالتزامنا باستخدام التشفير الأفضل في فئته، أعلنت Microsoft عن خطط لبدء الترحيل بعيداً عن بروتوكول أمان طبقة النقل الإصدارين 1.0 و1.1 في يونيو 2017. منذ هذا الإعلان الأولي، أعلنت Microsoft عزمنا عن تعطيل بروتوكول أمان طبقة النقل (TLS) الإصدارين 1.0 و1.1 بشكل افتراضي في الإصدارات المدعومة من Microsoft Edge وInternet Explorer 11 في النصف الأول من عام 2020. تشير إعلانات مماثلة من Apple وGoogle وMozilla إلى الاتجاه الذي تتجه إليه الصناعة.

لمزيد من المعلومات، راجع إعداد بروتوكول أمان طبقة النقل الإصدار 1.2 في Microsoft Azure

تكوين TLS

تم تكوين نسخة خادم سحابة Windows Server 2019 مع تعطيل بروتوكول أمان طبقة النقل الإصدار 1.0 وبروتوكول أمان طبقة النقل الإصدار 1.1 على مستوى التسجيل. هذا يعني أن التطبيقات التي تم نشرها في هذا الإصدار من Windows واستخدام مكدس الذاكرة المؤقتة في Windows لمعالجة بروتوكول أمان طبقة النقل لن تسمح باتصال بروتوكول أمان طبقة النقل الإصدار 1.0 وبروتوكول أمان طبقة النقل الإصدار 1.1.

يأتي الخادم أيضاً مع مجموعة محدودة من مجموعات التشفير:

    TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 
    TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 
    TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 
    TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 
    TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 
    TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 
    TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 
    TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 

الخطوة 1: إنشاء برنامج PowerShell النصي لتمكين بروتوكول أمان طبقة النقل الإصدار 1.0 وبروتوكول أمان طبقة النقل الإصدار 1.1

استخدم التعليمات البرمجية التالية كمثال لإنشاء برنامج نصي يمكّن البروتوكولات القديمة ومجموعات التشفير. لأغراض هذه الوثائق، ستتم تسمية هذا البرنامج النصي: TLSsettings.ps1. خزّن هذا البرنامج النصي على سطح المكتب المحلي لسهولة الوصول إليه في الخطوات اللاحقة.

# You can use the -SetCipherOrder (or -sco) option to also set the TLS cipher 
# suite order. Change the cipherorder variable below to the order you want to set on the 
# server. Setting this requires a reboot to take effect.

Param(
 [parameter(Mandatory=$false)]
 [alias("sco")]
 [switch]$SetCipherOrder)

 Function DisableRC4 {
   param ( $restart)
  $subkeys = Get-Item -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL"
  $ciphers = $subkeys.OpenSubKey("Ciphers", $true)

  if($ciphers.SubKeyCount -eq 0) {
    $k1 = $ciphers.CreateSubKey("RC4 128/128")
    $k1.SetValue("Enabled", 0, [Microsoft.Win32.RegistryValueKind]::DWord)
    $restart = $true
    $k2 = $ciphers.CreateSubKey("RC4 64/128")
    $k2.SetValue("Enabled", 0, [Microsoft.Win32.RegistryValueKind]::DWord)
    $k3 = $ciphers.CreateSubKey("RC4 56/128")
    $k3.SetValue("Enabled", 0, [Microsoft.Win32.RegistryValueKind]::DWord)
    $k4 = $ciphers.CreateSubKey("RC4 40/128")
    $k4.SetValue("Enabled", 0, [Microsoft.Win32.RegistryValueKind]::DWord)
  }

  $restart

}

Function Set-CryptoSetting {
  param (
    $keyindex,
    $value,
    $valuedata,
    $valuetype,
    $restart
  )

  # Check for existence of registry key, and create if it does not exist
  If (!(Test-Path -Path $regkeys[$keyindex])) {
    New-Item $regkeys[$keyindex] | Out-Null
  }

  # Get data of registry value, or null if it does not exist
  $val = (Get-ItemProperty -Path $regkeys[$keyindex] -Name $value -ErrorAction SilentlyContinue).$value

  If ($null -eq $val) {
    # Value does not exist - create and set to desired value
    New-ItemProperty -Path $regkeys[$keyindex] -Name $value -Value $valuedata -PropertyType $valuetype | Out-Null
    $restart = $True
    Write-Host "Configuring $regkeys[$keyindex]...."

  } Else {

    # Value does exist - if not equal to desired value, change it
    If ($val -ne $valuedata) {
      Set-ItemProperty -Path $regkeys[$keyindex] -Name $value -Value $valuedata
      $restart = $True
      Write-Host "Configuring $regkeys[$keyindex]..."
    }
  }

  $restart

}

$regkeys = @(
"HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0",
"HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Client",
"HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Server", #2
"HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1",
"HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Client", #4
"HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Server",
"HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2",        #6
"HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client",
"HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Server", #8
"HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0",
"HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Client", #10
"HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Server",
"HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0",        #12
"HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0\Client",
"HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0\Server", #14
"HKLM:\SOFTWARE\Policies\Microsoft\Cryptography\Configuration\SSL\00010002"
)

Function Set-Windows10PlusCurveOrder {
    param ( $reboot)
    $desiredOrder = "NistP384;NistP256".Split(";")
    If ([Environment]::OSVersion.Version.Major -ge 10) {
        If (!(Test-Path -Path $regkeys[15])) {
            New-Item $regkeys[15] | Out-Null
            $reboot = $True
        }

        $val = (Get-Item -Path $regkeys[15] -ErrorAction SilentlyContinue).GetValue("EccCurves", $null)

        if( $null -eq $val) {
            New-ItemProperty -Path $regkeys[15] -Name EccCurves -Value $desiredOrder -PropertyType MultiString | Out-Null
            $reboot = $True

        } else {

            if ([System.String]::Join(';', $val) -ne [System.String]::Join(';', $desiredOrder)) {
                Write-Host "The original curve order ", `n, $val, `n, "needs to be updated to ", $desiredOrder
                Set-ItemProperty -Path $regkeys[15] -Name EccCurves -Value $desiredOrder
                $reboot = $True
            }
        }
    }

    $reboot

}

If ([Environment]::OSVersion.Version.Major -lt 10) {
  # This is for Windows before 10 
  Write-Host "Configuring Windows before 10..."
  $cipherorder =  "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384_P384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256_P256,"
  $cipherorder += "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384_P384,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256_P256,"
  $cipherorder += "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256,"
  $cipherorder += "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA_P256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA_P256,"
  $cipherorder += "TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_GCM_SHA256,"
  $cipherorder += "TLS_RSA_WITH_AES_256_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,"
  $cipherorder += "TLS_RSA_WITH_AES_256_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA"

} Else {

 # this is for windows 10 or above
 Write-Host "Configuring Windows 10+..."
 $cipherorder = "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,"
 $cipherorder += "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,"
 $cipherorder += "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,"
 $cipherorder += "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,"
 $cipherorder += "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,"
 $cipherorder += "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,"
 $cipherorder += "TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_GCM_SHA256,"
 $cipherorder += "TLS_RSA_WITH_AES_256_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,"
 $cipherorder += "TLS_RSA_WITH_AES_256_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA"
}

# If any settings are changed, this will change to $True and the server will reboot
$reboot = $False

# Check for existence of registry keys (SSL 2.0, SSL 3.0, TLS 1.0, TLS 1.1, TLS 1.2), and create if they do not exist
For ($i = 0; $i -le 14; $i = $i + 1) {
  If (!(Test-Path -Path $regkeys[$i])) {
    New-Item $regkeys[$i] | Out-Null
  }
}

# Ensure SSL 2.0 disabled for client/server
$reboot = Set-CryptoSetting 10 DisabledByDefault 1 DWord $reboot
$reboot = Set-CryptoSetting 10 Enabled 0 DWord $reboot
$reboot = Set-CryptoSetting 11 DisabledByDefault 1 DWord $reboot
$reboot = Set-CryptoSetting 11 Enabled 0 DWord $reboot

# Ensure SSL 3.0 disabled for client/server
$reboot = Set-CryptoSetting 13 DisabledByDefault 1 DWord $reboot
$reboot = Set-CryptoSetting 13 Enabled 0 DWord $reboot
$reboot = Set-CryptoSetting 14 DisabledByDefault 1 DWord $reboot
$reboot = Set-CryptoSetting 14 Enabled 0 DWord $reboot

# Ensure TLS 1.0 enabled for client/server
$reboot = Set-CryptoSetting 1 DisabledByDefault 0 DWord $reboot
$reboot = Set-CryptoSetting 1 Enabled 1 DWord $reboot
$reboot = Set-CryptoSetting 2 DisabledByDefault 0 DWord $reboot
$reboot = Set-CryptoSetting 2 Enabled 1 DWord $reboot

# Ensure TLS 1.1 enabled for client/server
$reboot = Set-CryptoSetting 4 DisabledByDefault 0 DWord $reboot
$reboot = Set-CryptoSetting 4 Enabled 1 DWord $reboot
$reboot = Set-CryptoSetting 5 DisabledByDefault 0 DWord $reboot
$reboot = Set-CryptoSetting 5 Enabled 1 DWord $reboot

# Ensure TLS 1.2 enabled for client/server
$reboot = Set-CryptoSetting 7 DisabledByDefault 0 DWord $reboot
$reboot = Set-CryptoSetting 7 Enabled 1 DWord $reboot
$reboot = Set-CryptoSetting 8 DisabledByDefault 0 DWord $reboot
$reboot = Set-CryptoSetting 8 Enabled 1 DWord $reboot

$reboot = DisableRC4($reboot)

If ($SetCipherOrder) {
      If (!(Test-Path -Path $regkeys[15])) {
        New-Item $regkeys[15] | Out-Null
        $reboot = $True
      }

      $val = (Get-Item -Path $regkeys[15] -ErrorAction SilentlyContinue).GetValue("Functions", $null)

      if ($val -ne $cipherorder)
      {
        Write-Host "The original cipher suite order needs to be updated", `n, $val
        Set-ItemProperty -Path $regkeys[15] -Name Functions -Value $cipherorder
        $reboot = $True
      }
  }

$reboot = Set-Windows10PlusCurveOrder $reboot

If ($reboot) {
  # Randomize the reboot timing since it could be run in a large cluster.
  $tick = [System.Int32]([System.DateTime]::Now.Ticks % [System.Int32]::MaxValue)
  $rand = [System.Random]::new($tick)
  $sec = $rand.Next(30, 600)
  Write-Host "Rebooting after", $sec, " second(s)..."
  Write-Host  "shutdown.exe /r /t $sec /c ""Crypto settings changed"" /f /d p:2:4"
  shutdown.exe /r /t $sec /c "Crypto settings changed" /f /d p:2:4

} Else {

  Write-Host "Nothing get updated."
}

الخطوة 2: إنشاء ملف أمر

أنشئ ملف CMD المسمى RunTLSSettings.cmd باستخدام الوارد أدناه. خزّن هذا البرنامج النصي على سطح المكتب المحلي لسهولة الوصول إليه في الخطوات اللاحقة.

SET LOG_FILE="%TEMP%\StartupLog.txt"
SET EXECUTE_PS1=0

IF "%ComputeEmulatorRunning%" == "" (
       SET EXECUTE_PS1=1
)

IF "%ComputeEmulatorRunning%" == "false" (
       SET EXECUTE_PS1=1
)

IF %EXECUTE_PS1% EQU 1 (
       echo "Invoking TLSsettings.ps1 on Azure service at %TIME% on %DATE%" >> %LOG_FILE% 2>&1       
       PowerShell -ExecutionPolicy Unrestricted %~dp0TLSsettings.ps1 -sco  >> %LOG_FILE% 2>&1
) ELSE (
       echo "Skipping TLSsettings.ps1 invocation on emulated environment" >> %LOG_FILE% 2>&1       
)

EXIT /B %ERRORLEVEL%

الخطوة 3: إضافة مهمة بدء التشغيل إلى تعريف خدمة الدور (csdef)

أضف القصاصة البرمجية التالية إلى ملف تعريف الخدمة الموجود.

	<Startup> 
		<Task executionContext="elevated" taskType="simple" commandLine="RunTLSSettings.cmd"> 
		</Task> 
	</Startup> 

وفيما يلي مثال يوضح دور العامل ودور الويب.

<?xmlversion="1.0" encoding="utf-8"?> 
<ServiceDefinitionname="CloudServiceName" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition" schemaVersion="2015-04.2.6"> 
	<WebRolename="WebRole1" vmsize="Standard_D1_v2"> 
		<Sites> 
			<Sitename="Web"> 
				<Bindings> 
					<Bindingname="Endpoint1" endpointName="Endpoint1"/> 
				</Bindings> 
			</Site> 
		</Sites> 
		<Startup> 
			<Task executionContext="elevated" taskType="simple" commandLine="RunTLSSettings.cmd"> 
			</Task> 
		</Startup> 
		<Endpoints> 
			<InputEndpointname="Endpoint1" protocol="http" port="80"/> 
		</Endpoints> 
	</WebRole> 
<WorkerRolename="WorkerRole1" vmsize="Standard_D1_v2"> 
	<Startup> 
		<Task executionContext="elevated" taskType="simple" commandLine="RunTLSSettings.cmd"> 
		</Task> 
	</Startup> 
</WorkerRole> 
</ServiceDefinition> 

الخطوة 4: إضافة البرامج النصية إلى خدمة Cloud

  1. في Visual Studio، انقر بزر الماوس الأيمن على WebRole أو WorkerRole
  2. حدد إضافة
  3. ثم حدد Existing Item
  4. في مستكشف الملفات، انتقل إلى سطح المكتب حيث خزنت الملفين TLSsettings.ps1 وRunTLSSettings.cmd
  5. حدد الملفين لإضافتهما إلى مشروع خدمات Cloud

الخطوة 5: تمكين النسخ إلى دليل الإخراج

لضمان تحميل البرامج النصية مع كل تحديث يتم دفعه من Visual Studio، يجب ضبط الإعداد Copy to Output Directory إلى Copy Always

  1. ضمن WebRole أو WorkerRole، انقر بزر الماوس الأيمن على RunTLSSettings.cmd
  2. حدد Properties
  3. في علامة التبويب الخصائص، غيّر Copy to Output Directory إلى Copy Always"
  4. كرر الخطوات لـ TLSsettings.ps1

الخطوة 6: النشر والتحقق من الصحة

الآن بعد اكتمال الخطوات المذكورة أعلاه، انشر التحديث في خدمة Cloud الحالية.

يمكنك استخدام SSLLabs للتحقق من صحة حالة بروتوكول أمان طبقة النقل لنقاط النهاية