Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions terraform/common/waf/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -90,22 +90,79 @@ resource "aws_wafv2_web_acl" "this" {
rule {
name = "AWS-Managed-Bot-Control-Rule-Set"
priority = 40

override_action {
none {}
}

statement {
managed_rule_group_statement {
vendor_name = "AWS"
name = "AWSManagedRulesBotControlRuleSet"

rule_action_override {
name = "SignalNonBrowserUserAgent"
action_to_use {
count {}
}
}
}
}

visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "aws-managed-bot-control"
sampled_requests_enabled = true
}
}

# 임시 조치로 ua가 node일 경우만 통과시킴
rule {
name = "Block-Non-Node-User-Agents"
priority = 41

action {
block {}
}

Comment on lines +119 to +127
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

User-Agent 기반 우회는 쉽게 스푸핑 가능 — 추가 방어선 필요

임시 조치라 하더라도 UA 문자열은 누구나 위조할 수 있습니다. 최소한 다음 중 하나 이상을 병행하세요:

  • 특정 소스 IP/VPC/LB 오리진만 허용(allowlist).
  • 전용 경로/리소스(예: 로그인)로 범위 축소.
  • 커스텀 시크릿 헤더/HMAC 서명 또는 mTLS로 식별 강화.

향후 커스텀 UA로 전환 시, UA만으로 신뢰하지 말고 상기 수단 중 하나를 함께 적용해 주세요.

🤖 Prompt for AI Agents
In terraform/common/waf/main.tf around lines 119-127, the WAF rule currently
allowing requests based solely on User-Agent ("node") is insecure because UA can
be spoofed; replace or augment this UA-only rule with at least one stronger
control: restrict by source (allowlist specific IP ranges, VPC or LB origin),
narrow the rule to specific paths/resources (e.g., only login endpoints), or
require a strong provenance token such as a custom secret header with HMAC
signature or mTLS. Update the WAF rule to include the chosen additional
condition(s) and corresponding configuration (trusted IPs, path matching,
header/HMAC validation, or client cert requirement) so UA-based allowance is not
the sole trust signal.

statement {
and_statement {
statement {
label_match_statement {
scope = "LABEL"
key = "awswaf:managed:aws:bot-control:signal:non_browser_user_agent"
}
}

statement {
not_statement {
statement {
byte_match_statement {
search_string = "node"
field_to_match {
single_header {
name = "user-agent"
}
}
positional_constraint = "CONTAINS"
text_transformation {
priority = 0
type = "NONE"
}
Comment on lines +141 to +151
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

케이스 민감도 때문에 실제 Node UA가 차단될 수 있음 (치명적)

search_string = "node"인데 text_transformationNONE라서 User-Agent: Node.js/18...처럼 대문자/혼합 케이스는 매치되지 않습니다. 현재 규칙은 "NOT contains 'node'" 조건을 만족시키므로 오히려 Node 클라이언트를 차단할 수 있습니다. 반드시 소문자 정규화를 적용하세요.

아래 패치를 적용하세요:

-                text_transformation {
-                  priority = 0
-                  type     = "NONE"
-                }
+                text_transformation {
+                  priority = 0
+                  type     = "LOWERCASE"
+                }

또는 regex_pattern_set_reference_statement(?i)node(대소문자 무시) 사용을 권장합니다.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
search_string = "node"
field_to_match {
single_header {
name = "user-agent"
}
}
positional_constraint = "CONTAINS"
text_transformation {
priority = 0
type = "NONE"
}
search_string = "node"
field_to_match {
single_header {
name = "user-agent"
}
}
positional_constraint = "CONTAINS"
text_transformation {
priority = 0
type = "LOWERCASE"
}
🤖 Prompt for AI Agents
In terraform/common/waf/main.tf around lines 141 to 151, the rule uses
search_string = "node" with text_transformation = "NONE", causing mixed-case
User-Agent values like "Node.js/18" to miss the match; update the statement to
either (A) add a text_transformation block that lowercases the inspected text
(type = "LOWERCASE", priority appropriately set) so the CONTAINS check matches
any case variant, or (B) replace the current string statement with a
regex_pattern_set_reference_statement using a case-insensitive pattern like
(?i)node and reference that regex set; implement one of these fixes and ensure
priority/order of transformations is correct.

}
}
}
}
}
}

visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "block-non-node-uas"
sampled_requests_enabled = true
}
}

# Anonymous IP list
rule {
name = "AWS-Managed-Anonymous-IP-List"
Expand Down