CRS 또는 DRS 규칙 집합 버전 업그레이드

적용 대상: ✔️ Application Gateway V2

Azure Application Gateway WAF(웹 애플리케이션 방화벽)의 Azure 관리 형 DRS(기본 규칙 집합 )는 OWASP 상위 10개 공격 유형을 포함하여 일반적인 취약성 및 악용으로부터 웹 애플리케이션을 보호합니다. 기본 규칙 집합에는 Microsoft 위협 인텔리전스 컬렉션 규칙도 통합됩니다. 항상 최신 보안 업데이트, 규칙 향상 및 수정 사항을 포함하는 최신 규칙 집합 버전을 실행합니다.

Azure 관리형 DRS(기본 규칙 집합)는 Azure WAF의 최신 세대 규칙 집합으로, 이전의 모든 CRS(핵심 규칙 집합) 버전을 대체합니다. DRS 릴리스 중에서는 항상 사용 가능한 가장 높은 버전(DRS 2.2)을 사용하여 최신 보호 기능을 적용받을 수 있도록 하세요.

이 문서에서는 AZURE WAF 정책을 CRS 3.0, CRS 3.1, CRS 3.2 또는 DRS 2.1에서 DRS 2.2로 업그레이드하는 PowerShell 예제를 제공합니다.

비고

PowerShell 코드 조각은 예제일 뿐입니다. 모든 자리 표시자를 사용자 환경의 값으로 대체합니다.

필수 조건

업그레이드 시 주요 고려 사항

Azure WAF 규칙 집합 버전을 업그레이드할 때 다음을 확인합니다.

  • 기존 사용자 지정 유지: 규칙 작업 재정의, 규칙 상태(사용 또는 사용 안 함) 재정의 및 제외를 수행합니다.

  • 제거된 규칙에 대한 사용자 지정 삭제: DRS 2.2에 더 이상 존재하지 않는 규칙에 대한 재정의 또는 제외를 수행하지 마세요. DRS 2.2에 포함되지 않은 규칙에 대한 재정의를 수행하면 정책 업데이트가 실패하고 다음과 같은 The override Rule '<id>' is unknown for RuleGroup '<group>'오류가 발생합니다.

  • 기준 편집증 수준을 고려: DRS 2.2는 기본적으로 편집증 수준 1(PL1)에서 작동하며, 모든 PL2 규칙은 기본적으로 비활성화되어 있습니다. CRS 3.2 및 DRS 2.1에서는 PL2 규칙이 활성화되었습니다. 이전에 사용자 지정한 PL2 규칙은 명시적으로 다시 사용하도록 설정할 때까지 DRS 2.2에서 기본적으로 사용하지 않도록 설정됩니다.

  • 새 규칙의 유효성을 안전하게 검사합니다. 기본적으로 사용하도록 설정된 새로 추가된 규칙(PL1)은 처음에 로그 모드로 설정되므로 차단을 사용하도록 설정하기 전에 영향을 모니터링하고 미세 조정할 수 있습니다.

환경 및 변수 준비

  1. 선택한 구독, 리소스 그룹 및 Azure WAF 정책에 대한 컨텍스트를 설정합니다.

    Import-Module Az.Network
    Set-AzContext -SubscriptionId "<subscription_id>"
    $resourceGroupName = "<resource_group>"
    $wafPolicyName = "<policy_name>"
    
  2. WAF 정책 개체를 가져와 해당 정의를 검색합니다. 현재 관리되는 규칙 집합은 CRS(OWASP) 또는 DRS(Microsoft_DefaultRuleSet) 형식일 수 있습니다.

    $wafPolicy = Get-AzApplicationGatewayFirewallPolicy `
        -Name $wafPolicyName `
        -ResourceGroupName $resourceGroupName
    
    $currentExclusions = $wafPolicy.ManagedRules.Exclusions
    $currentManagedRuleset = $wafPolicy.ManagedRules.ManagedRuleSets |
        Where-Object { $_.RuleSetType -eq "OWASP" -or $_.RuleSetType -eq "Microsoft_DefaultRuleSet" }
    $currentVersion = $currentManagedRuleset.RuleSetVersion
    

기존 사용자 지정 유지

  1. 규칙이 DRS 2.2에 여전히 존재하는 경우에만 재정의 또는 제외를 수행합니다. 다음 함수는 DRS 2.2 규칙의 전체 집합에 대해 규칙 ID의 유효성을 검사하고 제거된 규칙(레거시 및 비활성 규칙(예: $true920460, 및942130)에 대해 반환 920250 합니다. 유효한 규칙 ID의 허용 목록을 사용하면 규칙별 유지 관리를 방지하고 알 수 없는 규칙에서 정책 업데이트가 실패하지 않도록 방지합니다.

    function Test-RuleIsRemovedFromDRS22 {
        param (
            [string]$RuleId,
            [string]$CurrentRulesetVersion  # Retained for compatibility; not used
        )
    
        # Complete set of rule IDs that exist in DRS 2.2.
        # Any override or exclusion for a rule NOT in this set is dropped during migration.
        $drs22RuleIds = @(
            "200002","200003",
            "911100",
            "920100","920120","920121","920160","920170","920171","920180","920181","920190","920200","920201","920210","920220","920230","920240","920260","920270","920271","920280","920290","920300","920310","920311","920320","920330","920340","920341","920350","920420","920430","920440","920450","920470","920480","920500","920530","920620",
            "921110","921120","921130","921140","921150","921151","921160","921190","921200","921422",
            "930100","930110","930120","930130",
            "931100","931110","931120","931130",
            "932100","932105","932110","932115","932120","932130","932140","932150","932160","932170","932171","932180",
            "933100","933110","933120","933130","933140","933150","933151","933160","933170","933180","933200","933210",
            "934100",
            "941100","941101","941110","941120","941130","941140","941150","941160","941170","941180","941190","941200","941210","941220","941230","941240","941250","941260","941270","941280","941290","941300","941310","941320","941330","941340","941350","941360","941370","941380",
            "942100","942110","942120","942140","942150","942160","942170","942180","942190","942200","942210","942220","942230","942240","942250","942260","942270","942280","942290","942300","942310","942320","942330","942340","942350","942360","942361","942370","942380","942390","942400","942410","942430","942440","942450","942470","942480","942500","942510",
            "943100","943110","943120",
            "944100","944110","944120","944130","944200","944210","944240","944250",
            "99005002","99005003","99005004","99005005","99005006",
            "99030001","99030002","99030003","99030004","99030005","99030006",
            "99031001","99031002","99031003","99031004","99031005","99031006",
            "99001001","99001002","99001003","99001004","99001005","99001006","99001007","99001008","99001009","99001010","99001011","99001012","99001013","99001014","99001015","99001016","99001017","99001018",
            "99032001","99032002"
        )
    
        return -not ($drs22RuleIds -contains $RuleId)
    }
    
  2. 새 재정의 개체를 만들 때는 DRS 2.2 그룹 이름을 사용하세요. 다음 함수는 레거시 CRS 그룹 이름을 DRS 그룹에 매핑합니다. 맵에 없는 DRS 원본 그룹 이름(예: DRS 2.1에서 업그레이드하는 경우)은 변경되지 않은 상태로 반환됩니다.

    function Get-DrsRuleGroupName {
        param (
            [Parameter(Mandatory = $true)]
            [string]$SourceGroupName
        )
        $groupMap = @{
            "REQUEST-930-APPLICATION-ATTACK-LFI"             = "LFI"
            "REQUEST-931-APPLICATION-ATTACK-RFI"             = "RFI"
            "REQUEST-932-APPLICATION-ATTACK-RCE"             = "RCE"
            "REQUEST-933-APPLICATION-ATTACK-PHP"             = "PHP"
            "REQUEST-941-APPLICATION-ATTACK-XSS"             = "XSS"
            "REQUEST-942-APPLICATION-ATTACK-SQLI"            = "SQLI"
            "REQUEST-943-APPLICATION-ATTACK-SESSION-FIXATION" = "FIX"
            "REQUEST-944-APPLICATION-ATTACK-JAVA"            = "JAVA"
            "REQUEST-921-PROTOCOL-ATTACK"                    = "PROTOCOL-ATTACK"
            "REQUEST-911-METHOD-ENFORCEMENT"                 = "METHOD-ENFORCEMENT"
            "REQUEST-920-PROTOCOL-ENFORCEMENT"               = "PROTOCOL-ENFORCEMENT"
            "REQUEST-913-SCANNER-DETECTION"                  = $null  # No direct mapping
            "Known-CVEs"                                     = "MS-ThreatIntel-CVEs"
            "General"                                        = "General"
        }
        if ($groupMap.ContainsKey($SourceGroupName)) {
            return $groupMap[$SourceGroupName]
        } else {
            return $SourceGroupName  # No known mapping; pass through (DRS source group names)
        }
    }
    
  3. 다음 PowerShell 코드를 사용하여 규칙의 재정의를 정의하고 기존 규칙 집합 버전에서 재정의를 복제합니다.

    $groupOverrides = @()
    foreach ($group in $currentManagedRuleset.RuleGroupOverrides) {
        $mappedGroupName = Get-DrsRuleGroupName $group.RuleGroupName
        if (-not $mappedGroupName) { continue }  # Skip groups with no DRS equivalent
        foreach ($existingRule in $group.Rules) {
            if (-not (Test-RuleIsRemovedFromDRS22 $existingRule.RuleId $currentVersion)) {
                $existingGroup = $groupOverrides | Where-Object { $_.RuleGroupName -eq $mappedGroupName }
                if ($existingGroup) {
                    if (-not ($existingGroup.Rules | Where-Object { $_.RuleId -eq $existingRule.RuleId })) {
                        $existingGroup.Rules.Add($existingRule)
                    }
                } else {
                    $newGroup = New-AzApplicationGatewayFirewallPolicyManagedRuleGroupOverride `
                        -RuleGroupName $mappedGroupName `
                        -Rule @($existingRule)
                    $groupOverrides += $newGroup
                }
            }
        }
    }
    
  4. 다음 PowerShell 코드를 사용하여 기존 제외를 복제하고 DRS 2.2에 적용합니다.

    # Create new exclusion objects
    $newRuleSetExclusions = @()
    
    if ($currentExclusions -ne $null -and $currentExclusions.Count -gt 0) {
        foreach ($exclusion in $currentExclusions) {
            $newExclusion = New-AzApplicationGatewayFirewallPolicyExclusion `
                -MatchVariable $exclusion.MatchVariable `
                -SelectorMatchOperator $exclusion.SelectorMatchOperator `
                -Selector $exclusion.Selector
    
            # Migrate scopes: RuleSet, RuleGroup, or individual Rules
            if ($exclusion.ExclusionManagedRuleSets) {
                foreach ($scope in $exclusion.ExclusionManagedRuleSets) {
                    # Create RuleGroup objects from existing RuleGroups
                    $ruleGroups = @()
                    foreach ($group in $scope.RuleGroups) {
                        $drsGroupName = Get-DrsRuleGroupName $group.RuleGroupName
                        if ($drsGroupName) {
                            $exclusionRules = @()
                            foreach ($rule in $group.Rules) {
                                if (-not (Test-RuleIsRemovedFromDRS22 $rule.RuleId $currentVersion)) {
                                    $exclusionRules += New-AzApplicationGatewayFirewallPolicyExclusionManagedRule `
                                        -RuleId $rule.RuleId
                                }
                            }
                            if ($exclusionRules -ne $null -and $exclusionRules.Count -gt 0) {
                                $ruleGroups += New-AzApplicationGatewayFirewallPolicyExclusionManagedRuleGroup `
                                    -Name $drsGroupName `
                                    -Rule $exclusionRules
                            } else {
                                $ruleGroups += New-AzApplicationGatewayFirewallPolicyExclusionManagedRuleGroup `
                                    -Name $drsGroupName
                            }
                        }
                    }
    
                    # Create the ManagedRuleSet scope object with the updated RuleGroups
                    if ($ruleGroups.Count -gt 0) {
                        $newRuleSetScope = New-AzApplicationGatewayFirewallPolicyExclusionManagedRuleSet `
                            -Type "Microsoft_DefaultRuleSet" `
                            -Version "2.2" `
                            -RuleGroup $ruleGroups
    
                        # Add to the new exclusion object
                        $newExclusion.ExclusionManagedRuleSets += $newRuleSetScope
                    }
                }
            }
    
            if (-not $newExclusion.ExclusionManagedRuleSets) {
                $newExclusion.ExclusionManagedRuleSets = @()
            }
    
            $newRuleSetExclusions += $newExclusion
        }
    }
    

새 규칙의 유효성을 안전하게 검사

업그레이드할 때 Paranoia Level 1에 속하는 새 DRS 2.2 규칙은 기본적으로 사용하도록 설정됩니다. WAF가 방지 모드인 경우 차단을 사용하도록 설정하기 전에 로그를 검토할 수 있도록 이러한 새 규칙을 먼저 로그 모드로 설정합니다.

Paranoia Level 2에 속하는 규칙은 DRS 2.2에서 기본적으로 사용하지 않도록 설정되며 트래픽을 차단하지 않으므로 이 단계가 필요하지 않습니다. Paranoia 수준 2에서 작동하려면 관련 PL2 규칙을 명시적으로 사용하도록 설정하고 동일한 로그 내 유효성 검사 방법을 따릅니다.

  1. 업그레이드하는 버전과 일치하는 정의를 사용합니다. 각 정의는 해당 버전에 비해 DRS 2.2에서 기본적으로 도입되고 사용하도록 설정된 규칙을 나열합니다.

    # Added and enabled by default in DRS 2.2 compared to CRS 3.0
    $rulesAddedInThisVersionByGroup = @{
        "General"              = @("200002", "200003")
        "PROTOCOL-ENFORCEMENT" = @("920171", "920181", "920470", "920480", "920500", "920530", "920620")
        "PROTOCOL-ATTACK"      = @("921190", "921200")
        "RCE"                  = @("932180")
        "PHP"                  = @("933200", "933210")
        "NODEJS"               = @("934100")
        "XSS"                  = @("941360", "941370")
        "SQLI"                 = @("942500")
        "JAVA"                 = @("944100", "944110", "944120", "944130")
        "MS-ThreatIntel-CVEs"  = @("99001018")
        "MS-ThreatIntel-XSS"   = @("99032001")
    }
    
    # Added and enabled by default in DRS 2.2 compared to CRS 3.1
    $rulesAddedInThisVersionByGroup = @{
        "General"              = @("200002", "200003")
        "PROTOCOL-ENFORCEMENT" = @("920181", "920500", "920530", "920620")
        "PROTOCOL-ATTACK"      = @("921190", "921200")
        "PHP"                  = @("933200", "933210")
        "NODEJS"               = @("934100")
        "XSS"                  = @("941360", "941370")
        "SQLI"                 = @("942500")
        "MS-ThreatIntel-CVEs"  = @("99001018")
        "MS-ThreatIntel-XSS"   = @("99032001")
    }
    
    # Added and enabled by default in DRS 2.2 compared to CRS 3.2
    $rulesAddedInThisVersionByGroup = @{
        "PROTOCOL-ENFORCEMENT" = @("920181", "920500", "920530", "920620")
        "PROTOCOL-ATTACK"      = @("921190", "921200")
        "NODEJS"               = @("934100")
        "XSS"                  = @("941370")
        "MS-ThreatIntel-CVEs"  = @("99001018")
        "MS-ThreatIntel-XSS"   = @("99032001")
    }
    
    # Added and enabled by default in DRS 2.2 compared to DRS 2.1
    $rulesAddedInThisVersionByGroup = @{
        "PROTOCOL-ENFORCEMENT" = @("920530", "920620")
        "MS-ThreatIntel-XSS"   = @("99032001")
    }
    
  2. 다음 PowerShell 코드를 사용하여 이전에 정의한 기존 $groupOverrides 개체에 새 규칙 재정의를 추가하려면:

    foreach ($groupName in $rulesAddedInThisVersionByGroup.Keys) {
        $ruleOverrides = @()
        foreach ($ruleId in $rulesAddedInThisVersionByGroup[$groupName]) {
            $existingGroup = $groupOverrides | Where-Object { $_.RuleGroupName -eq $groupName }
            $alreadyExists = $false
            if ($existingGroup) {
                $alreadyExists = $existingGroup.Rules | Where-Object { $_.RuleId -eq $ruleId }
            }
            if (-not $alreadyExists) {
                $ruleOverrides += New-AzApplicationGatewayFirewallPolicyManagedRuleOverride `
                    -RuleId $ruleId `
                    -Action "Log" `
                    -State "Enabled"
            }
        }
        # Only create or update the group override if we added rules to it
        if ($ruleOverrides.Count -gt 0) {
            $existingGroup = $groupOverrides | Where-Object { $_.RuleGroupName -eq $groupName }
            if ($existingGroup) {
                foreach ($ruleOverride in $ruleOverrides) {
                    $existingGroup.Rules.Add($ruleOverride)
                }
            } else {
                $groupOverrides += New-AzApplicationGatewayFirewallPolicyManagedRuleGroupOverride `
                    -RuleGroupName $groupName `
                    -Rule $ruleOverrides
            }
        }
    }
    

사용자 지정 적용 및 업그레이드

중복되고 업데이트된 규칙 재정의 및 제외를 통합하여 업데이트된 Azure WAF 정책 개체를 정의합니다.

$managedRuleSet = New-AzApplicationGatewayFirewallPolicyManagedRuleSet `
    -RuleSetType "Microsoft_DefaultRuleSet" `
    -RuleSetVersion "2.2" `
    -RuleGroupOverride $groupOverrides

# Replace the existing CRS (OWASP) or DRS (Microsoft_DefaultRuleSet) managed rule set
for ($i = 0; $i -lt $wafPolicy.ManagedRules.ManagedRuleSets.Count; $i++) {
    if ($wafPolicy.ManagedRules.ManagedRuleSets[$i].RuleSetType -eq "OWASP" -or
        $wafPolicy.ManagedRules.ManagedRuleSets[$i].RuleSetType -eq "Microsoft_DefaultRuleSet") {
        $wafPolicy.ManagedRules.ManagedRuleSets[$i] = $managedRuleSet
        break
    }
}

# Assign the migrated exclusions to the policy
$wafPolicy.ManagedRules.Exclusions = $newRuleSetExclusions

# Apply the updated WAF policy
Set-AzApplicationGatewayFirewallPolicy -InputObject $wafPolicy