ntopng 로그 수집
개요
이 파서는 SYSLOG 또는 JSON 형식의 ntopng 네트워크 모니터링 로그를 추출합니다. 로그 메시지를 파싱하고 관련 필드를 UDM 형식으로 변환하며 제품 및 공급업체 이름과 같은 메타데이터로 이벤트를 보강합니다. 또한 파서는 중첩된 JSON 구조를 처리하고 특정 ntopng 필드를 흐름 알림 및 사용자 리소스 액세스를 비롯한 UDM 네트워크 이벤트에 매핑합니다.
시작하기 전에
- Google SecOps 인스턴스가 있는지 확인합니다.
- ntopng에 대한 권한이 있는지 확인합니다.
ntopng 로그를 수집하도록 Google SecOps에서 피드 구성
- SIEM 설정 > 피드로 이동합니다.
- 새로 추가를 클릭합니다.
- 피드 이름 필드에 피드 이름을 입력합니다 (예: ntopng 로그).
- 소스 유형으로 Webhook을 선택합니다.
- 로그 유형으로 Ntopng을 선택합니다.
- 다음을 클릭합니다.
- 선택사항: 다음 입력 파라미터의 값을 지정합니다.
- 분할 구분 기호: 로그 줄을 구분하는 데 사용되는 구분 기호입니다(예:
\n
). - 애셋 네임스페이스: 애셋 네임스페이스입니다.
- 수집 라벨: 이 피드의 이벤트에 적용된 라벨입니다.
- 분할 구분 기호: 로그 줄을 구분하는 데 사용되는 구분 기호입니다(예:
- 다음을 클릭합니다.
- 확정 화면에서 피드 구성을 검토한 다음 제출을 클릭합니다.
- 보안 비밀 키 생성을 클릭하여 이 피드를 인증하기 위한 보안 비밀 키를 생성합니다.
- 비밀 키를 복사하여 저장합니다. 이 보안 비밀 키는 다시 볼 수 없습니다. 필요한 경우 새 보안 비밀 키를 재생성할 수 있지만 이 작업을 하면 이전 보안 비밀 키는 더 이상 사용할 수 없게 됩니다.
- 세부정보 탭의 엔드포인트 정보 필드에서 피드 엔드포인트 URL을 복사합니다. 클라이언트 애플리케이션에서 이 엔드포인트 URL을 지정해야 합니다.
- 완료를 클릭합니다.
웹훅 피드에 대한 API 키 만들기
Google Cloud 콘솔 > 사용자 인증 정보로 이동합니다.
사용자 인증 정보 만들기를 클릭한 후 API 키를 선택합니다.
Google Security Operations API에 대한 API 키 액세스를 제한합니다.
엔드포인트 URL 지정
- 클라이언트 애플리케이션에서 웹훅 피드에 제공된 HTTPS 엔드포인트 URL을 지정합니다.
다음 형식의 커스텀 헤더의 일부로 API 키와 보안 비밀 키를 지정하여 인증을 사용 설정합니다.
X-goog-api-key = API_KEY X-Webhook-Access-Key = SECRET
권장사항: URL에 API 키를 지정하는 대신 헤더로 지정하세요.
웹훅 클라이언트가 커스텀 헤더를 지원하지 않는 경우 다음 형식의 쿼리 매개변수를 사용하여 API 키와 보안 비밀 키를 지정할 수 있습니다.
ENDPOINT_URL?key=API_KEY&secret=SECRET
다음을 바꿉니다.
ENDPOINT_URL
: 피드 엔드포인트 URL입니다.API_KEY
: Google Security Operations에 인증하기 위한 API 키입니다.SECRET
: 피드를 인증하기 위해 생성한 보안 비밀 키입니다.
Google SecOps용 ntopng에서 Webhook 구성
- ntopng 웹 인터페이스에 로그인합니다.
- 드롭다운에서 시스템 메뉴를 선택합니다.
- 알림 > 엔드포인트로 이동합니다.
- 추가 를 클릭합니다.
- 다음 입력 매개변수의 값을 지정합니다.
- 엔드포인트 이름: 고유하고 설명적인 이름을 입력합니다 (예: Google SecOps).
- 엔드포인트 유형: 목록에서 Webhook을 선택합니다.
- Webhook URL: API_KEY 및 SECRET과 함께 Google SecOps ENDPOINT_URL을 입력합니다.
- 추가를 클릭합니다.
- 알림 > 수신자로 이동합니다.
- 추가 를 클릭합니다.
- 다음 입력 매개변수의 값을 지정합니다.
- 수신자 이름: 고유하고 설명적인 이름을 입력합니다 (예: Google SecOps).
- 엔드포인트 선택: 앞서 만든 엔드포인트를 선택합니다.
- 심각도: Google SecOps로 전송할 심각도를 선택합니다 (예: 정보, 경고, 오류).
- 카테고리 필터: Google SecOps로 전송할 항목을 선택합니다.
- Test Recipient(수신자 테스트)를 클릭하여 연결을 확인합니다.
- 추가를 클릭하여 웹훅을 저장합니다.
ntopng 웹훅 리소스 구독자 구성
- 풀로 이동합니다.
이벤트를 공유할 리소스를 선택합니다.
작업 열에서 연필 아이콘을 클릭합니다.
수신자 드롭다운을 클릭합니다.
Google SecOps 웹훅 수신자를 선택합니다.
수정을 클릭하여 구성을 저장합니다.
다른 리소스에 대해 이 프로세스를 반복합니다.
UDM 매핑 표
로그 필드 | UDM 매핑 | 논리 |
---|---|---|
action |
security_result.detection_fields.key=action , security_result.detection_fields.value=%{action} |
원시 로그의 action 값은 키가 'action'인 security_result.detection_fields 객체에 매핑됩니다. |
alert_generation.host_info.broadcast_domain_host |
security_result.detection_fields.key=host_info broadcast_domain_host , security_result.detection_fields.value=%{alert_generation.host_info.broadcast_domain_host} |
중첩된 JSON의 alert_generation.host_info.broadcast_domain_host 값은 'host_info broadcast_domain_host' 키가 있는 security_result.detection_fields 객체에 매핑됩니다. |
alert_generation.host_info.dhcpHost |
security_result.detection_fields.key=host_info dhcpHost , security_result.detection_fields.value=%{alert_generation.host_info.dhcpHost} |
중첩된 JSON의 alert_generation.host_info.dhcpHost 값은 'host_info dhcpHost' 키가 있는 security_result.detection_fields 객체에 매핑됩니다. |
alert_generation.host_info.is_blacklisted |
security_result.detection_fields.key=host_info is_blacklisted , security_result.detection_fields.value=%{alert_generation.host_info.is_blacklisted} |
중첩된 JSON의 alert_generation.host_info.is_blacklisted 값은 'host_info is_blacklisted' 키가 있는 security_result.detection_fields 객체에 매핑됩니다. |
alert_generation.host_info.is_broadcast |
security_result.detection_fields.key=host_info is_broadcast , security_result.detection_fields.value=%{alert_generation.host_info.is_broadcast} |
중첩된 JSON의 alert_generation.host_info.is_broadcast 값은 'host_info is_broadcast' 키가 있는 security_result.detection_fields 객체에 매핑됩니다. |
alert_generation.host_info.is_multicast |
security_result.detection_fields.key=host_info is_multicast , security_result.detection_fields.value=%{alert_generation.host_info.is_multicast} |
중첩된 JSON의 alert_generation.host_info.is_multicast 값은 'host_info is_multicast' 키가 있는 security_result.detection_fields 객체에 매핑됩니다. |
alert_generation.host_info.localhost |
security_result.detection_fields.key=host_info localhost , security_result.detection_fields.value=%{alert_generation.host_info.localhost} |
중첩된 JSON의 alert_generation.host_info.localhost 값은 'host_info localhost' 키가 있는 security_result.detection_fields 객체에 매핑됩니다. |
alert_generation.host_info.privatehost |
security_result.detection_fields.key=host_info privatehost , security_result.detection_fields.value=%{alert_generation.host_info.privatehost} |
중첩된 JSON의 alert_generation.host_info.privatehost 값은 'host_info privatehost' 키가 있는 security_result.detection_fields 객체에 매핑됩니다. |
alert_generation.host_info.systemhost |
security_result.detection_fields.key=host_info systemhost , security_result.detection_fields.value=%{alert_generation.host_info.systemhost} |
중첩된 JSON의 alert_generation.host_info.systemhost 값은 'host_info systemhost' 키가 있는 security_result.detection_fields 객체에 매핑됩니다. |
alert_generation.script_key |
security_result.category_details=%{alert_generation.script_key} |
중첩된 JSON의 alert_generation.script_key 값이 security_result.category_details 에 매핑됩니다. |
alert_generation.subdir |
security_result.detection_fields.key=alert_generation_subdir , security_result.detection_fields.value=%{alert_generation.subdir} |
중첩된 JSON의 alert_generation.subdir 값은 'alert_generation_subdir' 키가 있는 security_result.detection_fields 객체에 매핑됩니다. |
alert_id |
security_result.detection_fields.key=alert_id , security_result.detection_fields.value=%{alert_id} |
원시 로그의 alert_id 값은 키가 'alert_id'인 security_result.detection_fields 객체에 매핑됩니다. |
alerts_map |
security_result.detection_fields.key=alerts_map , security_result.detection_fields.value=%{alerts_map} |
원시 로그의 alerts_map 값은 키가 'alerts_map'인 security_result.detection_fields 객체에 매핑됩니다. |
cli2srv_bytes |
network.sent_bytes |
원시 로그의 cli2srv_bytes 값은 부호 없는 정수로 변환되고 network.sent_bytes 에 매핑됩니다. |
cli_asn |
principal.resource.attribute.labels.key=cli_asn , principal.resource.attribute.labels.value=%{cli_asn} |
원시 로그의 cli_asn 값이 문자열로 변환되고 키가 'cli_asn'인 principal.resource.attribute.labels 객체에 매핑됩니다. |
cli_blacklisted |
principal.resource.attribute.labels.key=cli_blacklisted , principal.resource.attribute.labels.value=%{cli_blacklisted} |
원시 로그의 cli_blacklisted 값이 문자열로 변환되고 'cli_blacklisted' 키가 있는 principal.resource.attribute.labels 객체에 매핑됩니다. |
cli_city_name |
principal.location.city |
원시 로그의 cli_city_name 값은 principal.location.city 에 매핑됩니다. |
cli_continent_name |
principal.resource.attribute.labels.key=cli_continent_name , principal.resource.attribute.labels.value=%{cli_continent_name} |
원시 로그의 cli_continent_name 값은 'cli_continent_name' 키가 있는 principal.resource.attribute.labels 객체에 매핑됩니다. |
cli_country_name |
principal.location.country_or_region |
원시 로그의 cli_country_name 값은 principal.location.country_or_region 에 매핑됩니다. |
cli_host_pool_id |
principal.resource.attribute.labels.key=cli_host_pool_id , principal.resource.attribute.labels.value=%{cli_host_pool_id} |
원시 로그의 cli_host_pool_id 값이 문자열로 변환되고 'cli_host_pool_id' 키가 있는 principal.resource.attribute.labels 객체에 매핑됩니다. |
cli_ip |
principal.ip , principal.asset.ip |
원시 로그의 cli_ip 값은 principal.ip 및 principal.asset.ip 에 매핑됩니다. |
cli_localhost |
principal.resource.attribute.labels.key=cli_localhost , principal.resource.attribute.labels.value=%{cli_localhost} |
원시 로그의 cli_localhost 값이 문자열로 변환되고 'cli_localhost' 키가 있는 principal.resource.attribute.labels 객체에 매핑됩니다. |
cli_location |
principal.location.name |
원시 로그의 cli_location 값이 문자열로 변환됩니다. '0'이 아니면 principal.location.name 에 매핑됩니다. |
cli_name |
principal.hostname , principal.asset.hostname |
원시 로그의 cli_name 값은 principal.hostname 및 principal.asset.hostname 에 매핑됩니다. |
cli_network |
principal.resource.attribute.labels.key=cli_network , principal.resource.attribute.labels.value=%{cli_network} |
원시 로그의 cli_network 값이 문자열로 변환되고 키가 'cli_network'인 principal.resource.attribute.labels 객체에 매핑됩니다. |
cli_port |
principal.port |
원시 로그의 cli_port 값이 정수로 변환되고 principal.port 에 매핑됩니다. |
entity_id |
principal.resource.attribute.labels.key=entity_id , principal.resource.attribute.labels.value=%{entity_id} |
원시 로그의 entity_id 값이 문자열로 변환되고 'entity_id' 키가 있는 principal.resource.attribute.labels 객체에 매핑됩니다. |
entity_val |
principal.resource.attribute.labels.key=entity_val , principal.resource.attribute.labels.value=%{entity_val} |
원시 로그의 entity_val 값은 ip 값과 같지 않은 한 'entity_val' 키가 있는 principal.resource.attribute.labels 객체에 매핑됩니다. |
event.type |
metadata.event_type |
principal , target , network 필드의 존재를 기반으로 파서 로직에 의해 결정됩니다. 가능한 값: NETWORK_FLOW , NETWORK_UNCATEGORIZED , USER_RESOURCE_ACCESS , GENERIC_EVENT . |
first_seen |
principal.asset.first_seen_time |
원시 로그의 first_seen 값은 문자열로 변환되고, 에포크 이후 밀리초로 파싱되고, principal.asset.first_seen_time 에 매핑됩니다. |
flow_risk_bitmap |
security_result.detection_fields.key=flow_risk_bitmap , security_result.detection_fields.value=%{flow_risk_bitmap} |
원시 로그의 flow_risk_bitmap 값이 문자열로 변환되고 키가 'flow_risk_bitmap'인 security_result.detection_fields 객체에 매핑됩니다. |
granularity |
security_result.detection_fields.key=granularity , security_result.detection_fields.value=%{granularity} |
원시 로그의 granularity 값이 문자열로 변환되고 'granularity' 키가 있는 security_result.detection_fields 객체에 매핑됩니다. |
hash_entry_id |
security_result.detection_fields.key=hash_entry_id , security_result.detection_fields.value=%{hash_entry_id} |
중첩된 JSON의 hash_entry_id 값은 'hash_entry_id' 키가 있는 security_result.detection_fields 객체에 매핑됩니다. |
host_ip |
principal.ip , principal.asset.ip |
메시지의 <INT>Oct 20 15:34:53 1.1.1.1 부분에서 추출된 IP 주소가 principal.ip 및 principal.asset.ip 에 매핑됩니다. |
ifid |
principal.asset_id |
원시 로그의 ifid 값은 문자열로 변환되고 'ifid: ' 접두사로 principal.asset_id 에 매핑됩니다. |
ip |
principal.ip , principal.asset.ip 또는 target.ip , target.asset.ip |
is_client 가 true인 경우 원시 로그의 ip 값이 principal.ip 및 principal.asset.ip 에 매핑됩니다. is_server 이 true인 경우 target.ip 및 target.asset.ip 에 매핑됩니다. |
is_cli_attacker |
security_result.detection_fields.key=is_cli_attacker , security_result.detection_fields.value=%{is_cli_attacker} |
원시 로그의 is_cli_attacker 값이 문자열로 변환되고 'is_cli_attacker' 키가 있는 security_result.detection_fields 객체에 매핑됩니다. |
is_cli_victim |
security_result.detection_fields.key=is_cli_victim , security_result.detection_fields.value=%{is_cli_victim} |
원시 로그의 is_cli_victim 값이 문자열로 변환되고 'is_cli_victim' 키가 있는 security_result.detection_fields 객체에 매핑됩니다. |
is_flow_alert |
security_result.detection_fields.key=is_flow_alert , security_result.detection_fields.value=%{is_flow_alert} , security_result.detection_fields.key=alert type , security_result.detection_fields.value=flow |
원시 로그의 is_flow_alert 값이 문자열로 변환되고 'is_flow_alert' 키가 있는 security_result.detection_fields 객체에 매핑됩니다. is_flow_alert 가 true이면 키가 'alert type'이고 값이 'flow'인 security_result.detection_fields 객체도 생성됩니다. |
is_srv_attacker |
security_result.detection_fields.key=is_srv_attacker , security_result.detection_fields.value=%{is_srv_attacker} |
원시 로그의 is_srv_attacker 값이 문자열로 변환되고 'is_srv_attacker' 키가 있는 security_result.detection_fields 객체에 매핑됩니다. |
is_srv_victim |
security_result.detection_fields.key=is_srv_victim , security_result.detection_fields.value=%{is_srv_victim} |
원시 로그의 is_srv_victim 값이 문자열로 변환되고 'is_srv_victim' 키가 있는 security_result.detection_fields 객체에 매핑됩니다. |
metadata.product_name |
metadata.product_name=NTOPNG |
'NTOPNG'로 하드코딩되었습니다. |
metadata.vendor_name |
metadata.vendor_name=%{vendor_name} |
메시지의 vendor_name 값이 metadata.vendor_name 에 매핑됩니다. |
name |
principal.hostname , principal.asset.hostname 또는 target.hostname , target.asset.hostname |
is_client 가 true이면 원시 로그의 name 값이 principal.hostname 및 principal.asset.hostname 에 매핑됩니다. is_server 이 true인 경우 target.hostname 및 target.asset.hostname 에 매핑됩니다. |
ntopng_key |
security_result.detection_fields.key=ntopng_key , security_result.detection_fields.value=%{ntopng_key} |
중첩된 JSON의 ntopng.key 값 (ntopng_key 로 이름이 변경됨)은 'ntopng_key' 키가 있는 security_result.detection_fields 객체에 매핑됩니다. |
observation_point_id |
observer.asset_id |
원시 로그의 observation_point_id 값이 문자열로 변환됩니다. '0'이 아니면 'id: ' 접두사로 observer.asset_id 에 매핑됩니다. |
pool_id |
principal.resource.attribute.labels.key=pool_id , principal.resource.attribute.labels.value=%{pool_id} |
원시 로그의 pool_id 값이 문자열로 변환되고 'pool_id' 키가 있는 principal.resource.attribute.labels 객체에 매핑됩니다. |
probe_ip |
intermediary.ip |
원시 로그의 probe_ip 값은 intermediary.ip 에 매핑됩니다. |
proto.confidence |
security_result.confidence_details |
원시 로그의 proto.confidence 값이 문자열로 변환되고 security_result.confidence_details 에 매핑됩니다. |
proto.http.last_method |
network.http.method |
원시 로그의 proto.http.last_method 값은 network.http.method 에 매핑됩니다. |
proto.http.last_return_code |
network.http.response_code |
원시 로그의 proto.http.last_return_code 값이 정수로 변환되고 network.http.response_code 에 매핑됩니다. |
proto.http.last_server_name |
network.tls.client.server_name |
원시 로그의 proto.http.server_name 값은 network.tls.client.server_name 에 매핑됩니다. |
proto.http.last_url |
network.http.referral_url |
원시 로그의 proto.http.last_url 값은 network.http.referral_url 에 매핑됩니다. |
proto.http.last_user_agent |
network.http.user_agent |
원시 로그의 proto.http.last_user_agent 값은 network.http.user_agent 에 매핑됩니다. |
proto.http.server_name |
network.tls.client.server_name |
원시 로그의 proto.http.server_name 값은 network.tls.client.server_name 에 매핑됩니다. |
proto.l4 |
network.ip_protocol |
원시 로그의 proto.l4 값은 network.ip_protocol 에 매핑됩니다. |
proto_ndpi |
additional.fields.key=proto ndpi , additional.fields.value.string_value=%{proto_ndpi} , network.application_protocol |
원시 로그의 proto.ndpi 값 (proto_ndpi 로 이름이 변경됨)은 키가 'proto ndpi'인 additional.fields 객체에 매핑됩니다. 'NTP' 및 'HTTP'와 같은 키워드를 기반으로 network.application_protocol 의 값을 결정하는 데도 사용됩니다. |
proto_ndpi_app |
principal.application |
원시 로그의 proto_ndpi_app 값은 principal.application 에 매핑됩니다. |
proto_ndpi_breed |
security_result.detection_fields.key=proto_ndpi_breed , security_result.detection_fields.value=%{proto_ndpi_breed} |
원시 로그의 proto_ndpi_breed 값이 문자열로 변환되고 'proto_ndpi_breed' 키가 있는 security_result.detection_fields 객체에 매핑됩니다. |
proto_ndpi_cat |
security_result.category_details |
원시 로그의 proto_ndpi_cat 값은 security_result.category_details 에 매핑됩니다. |
proto_ndpi_cat_id |
security_result.detection_fields.key=proto_ndpi_cat_id , security_result.detection_fields.value=%{proto_ndpi_cat_id} |
원시 로그의 proto_ndpi_cat_id 값이 문자열로 변환되고 'proto_ndpi_cat_id' 키가 있는 security_result.detection_fields 객체에 매핑됩니다. |
score |
security_result.detection_fields.key=score , security_result.detection_fields.value=%{score} |
원시 로그의 score 값이 문자열로 변환되고 키가 'score'인 security_result.detection_fields 객체에 매핑됩니다. |
srv2cli_bytes |
network.received_bytes |
원시 로그의 srv2cli_bytes 값은 부호 없는 정수로 변환되고 network.received_bytes 에 매핑됩니다. |
srv_asn |
target.resource.attribute.labels.key=srv_asn , target.resource.attribute.labels.value=%{srv_asn} |
원시 로그의 srv_asn 값이 문자열로 변환되고 키가 'srv_asn'인 target.resource.attribute.labels 객체에 매핑됩니다. |
srv_blacklisted |
target.resource.attribute.labels.key=srv_blacklisted , target.resource.attribute.labels.value=%{srv_blacklisted} |
원시 로그의 srv_blacklisted 값이 문자열로 변환되고 'srv_blacklisted' 키가 있는 target.resource.attribute.labels 객체에 매핑됩니다. |
srv_city_name |
target.location.city |
원시 로그의 srv_city_name 값은 target.location.city 에 매핑됩니다. |
srv_continent_name |
target.resource.attribute.labels.key=srv_continent_name , target.resource.attribute.labels.value=%{srv_continent_name} |
원시 로그의 srv_continent_name 값은 키가 'srv_continent_name'인 target.resource.attribute.labels 객체에 매핑됩니다. |
srv_country_name |
target.location.country_or_region |
원시 로그의 srv_country_name 값은 target.location.country_or_region 에 매핑됩니다. |
srv_host_pool_id |
target.resource.attribute.labels.key=srv_host_pool_id , target.resource.attribute.labels.value=%{srv_host_pool_id} |
원시 로그의 srv_host_pool_id 값이 문자열로 변환되고 'srv_host_pool_id' 키가 있는 target.resource.attribute.labels 객체에 매핑됩니다. |
srv_ip |
target.ip , target.asset.ip |
원시 로그의 srv_ip 값은 target.ip 및 target.asset.ip 에 매핑됩니다. |
srv_localhost |
target.resource.attribute.labels.key=srv_localhost , target.resource.attribute.labels.value=%{srv_localhost} |
원시 로그의 srv_localhost 값이 문자열로 변환되고 'srv_localhost' 키가 있는 target.resource.attribute.labels 객체에 매핑됩니다. |
srv_location |
target.location.name |
원시 로그의 srv_location 값이 문자열로 변환됩니다. '0'이 아니면 target.location.name 에 매핑됩니다. |
srv_location_lat |
target.location.region_coordinates.latitude |
원시 로그의 srv_location_lat 값은 target.location.region_coordinates.latitude 에 매핑됩니다. |
srv_location_lon |
target.location.region_coordinates.longitude |
원시 로그의 srv_location_lon 값은 target.location.region_coordinates.longitude 에 매핑됩니다. |
srv_name |
target.hostname , target.asset.hostname |
원시 로그의 srv_name 값은 target.hostname 및 target.asset.hostname 에 매핑됩니다. |
srv_network |
target.resource.attribute.labels.key=srv_network , target.resource.attribute.labels.value=%{srv_network} |
원시 로그의 srv_network 값이 문자열로 변환되고 키가 'srv_network'인 target.resource.attribute.labels 객체에 매핑됩니다. |
srv_port |
target.port |
원시 로그의 srv_port 값이 정수로 변환되고 target.port 에 매핑됩니다. |
tstamp |
additional.fields.key=tstamp , additional.fields.value.string_value=%{tstamp} |
원시 로그의 tstamp 값이 문자열로 변환되고 'tstamp' 키가 있는 additional.fields 객체에 매핑됩니다. |
vlan_id |
principal.resource.attribute.labels.key=vlan_id , principal.resource.attribute.labels.value=%{vlan_id} |
원시 로그의 vlan_id 값이 문자열로 변환되고 'vlan_id' 키가 있는 principal.resource.attribute.labels 객체에 매핑됩니다. |
when |
metadata.event_timestamp |
원시 로그의 when 값은 타임스탬프로 파싱되고 metadata.event_timestamp 에 매핑됩니다. |
변경사항
2024-02-01
- 버그 수정:
- conf 파일의 헤더 주석에서 '=>"를 ':'으로 변경했습니다.
2023-11-16
- 파서를 새로 만들었습니다.