← 아티클 목록

시리즈AI를 보안 분석에 붙여 본 기록1편 · 공개 5편

AI Security

이상 탐지 모델을 골라도 임계값에서 다시 갈린다

LOF, One-Class SVM, Isolation Forest, Autoencoder가 각각 무엇을 이상이라고 부르는지 비교하고, 같은 모델이 임계값·평가 단위·라벨 품질에 따라 어떻게 다른 성적을 내는지, 특징을 바꾸는 회피와 탐지기 투표까지 정리한 개념 노트.

목차 8

같은 데이터에서 모델마다 다른 것을 이상이라고 부른다

비지도 이상 탐지는 정상과 공격을 모두 라벨로 학습하기 어려울 때, 데이터 분포에서 벗어난 관측치를 조사 후보로 올리는 방식이다. 알고리즘마다 ’벗어났다’의 정의가 달라서 같은 데이터를 넣어도 탐지 대상과 순위가 갈린다.

알고리즘 이상 판단 기준 강점 주의점
LOF 주변 이웃보다 국소 밀도가 낮음 지역적으로 드문 패턴 거리 계산과 n_neighbors에 민감
One-Class SVM 정상 데이터가 이루는 경계 밖 비선형 정상 영역 표현 Scaling과 nu, gamma 조정
Autoencoder 정상 데이터보다 복원 오차가 큼 복잡한 비선형 패턴 학습 학습 데이터와 임계값 품질에 민감
Isolation Forest 무작위 분할에서 짧은 경로로 고립됨 빠르고 표 형태 데이터에 붙이기 쉬움 희귀하지만 정상인 사건도 이상으로 본다

LOF와 One-Class SVM은 거리와 경계를 계산하므로 특징의 단위가 결과에 직접 들어간다. 요청 수가 300이고 오류율이 0.25인 표를 그대로 넣으면 거리는 사실상 요청 수 하나로 결정된다. Autoencoder도 복원 오차가 특정 특징의 단위에 지배되지 않도록 정규화해야 한다. Isolation Forest는 트리 기반이라 Scaling이 필수는 아니지만, 결측값이나 잘못 잡은 집계 단위까지 대신 해결해 주지는 않는다.

모델을 고르는 기준은 데이터의 모양에 따라 갈린다. 빠른 기준선이 필요하면 Isolation Forest, 지역별 밀도 차이가 중요하면 LOF, 정상 영역의 경계를 그리고 싶으면 One-Class SVM, 정상 학습 데이터가 충분하고 패턴이 복잡하면 Autoencoder를 본다. 어느 쪽이든 같은 데이터 분할과 같은 평가 단위로 비교해야 비교가 성립한다.

규칙 기반 탐지와 나란히 두면 서로의 빈칸이 보인다. 규칙은 아는 문자열과 행동을 빠르고 설명 가능하게 잡지만 변형과 새 공격을 놓치고, ML은 규칙에 없는 패턴을 잡을 수 있지만 정상 이벤트를 공격처럼 올리고 결과를 설명하기 어렵다. 그래서 탐지 결과를 규칙만 낸 경보, 둘 다 낸 경보, ML만 낸 경보로 나눠 본다. 세 번째에는 규칙이 놓친 공격과 ML의 오탐이 함께 있을 수 있어 원본 로그와 정답 라벨을 대조해야 한다.

연결한 실습의 첫 비교에서 0이었던 것은 ML만 잡은 참 공격의 수다. 그 로그의 공격은 기존 규칙이 모두 잡을 수 있었으므로 참 공격의 순증이 없었다. 이것이 ML만 낸 경보 전체가 0이었다는 뜻은 아니다. 추가로 찾은 공격 수와 조사해야 할 오탐 수는 따로 세어야 한다(이상 탐지를 재려면 로그가 두 조건을 만족해야 한다).

Isolation Forest는 몇 번 만에 고립되는지를 센다

Isolation Forest는 특징과 분할 지점을 무작위로 골라 관측치를 반복해서 나눈다. 다른 데이터와 쉽게 떨어지는 관측치는 평균적으로 더 짧은 경로에서 혼자 남으므로 이상 가능성이 높다고 본다. 정상 데이터가 상대적으로 밀집해 있고, 이상이 드물고, 선택한 특징에서 둘이 구분될 때 동작하는 방법이다.

보안 로그에 붙일 때의 흐름은 이렇다.

원시 로그
  -> 파싱과 정제
  -> IP 또는 세션 단위 집계
  -> 수치 특징 생성
  -> Isolation Forest 학습·예측
  -> 이상 점수 순위화
  -> 원본 로그와 규칙 결과 교차 검증

세션 단위로 쓰는 특징은 req_count, unique_paths, error_rate, avg_gap_sec, special_char_ratio, resp_size_std, status4xx_ratio 같은 것들이다. 이 값들은 공격 그 자체가 아니라 행동을 수치로 옮긴 관측치다. 연결한 실습에서는 요청 단위에서 IP 세션 단위로 바꾸면서 특징 구성도 함께 바꿨다. 순위 차이는 이 두 변화가 함께 반영된 결과다(무엇을 한 행으로 둘 것인가).

Python
from sklearn.ensemble import IsolationForest

model = IsolationForest(
    contamination=0.1,
    random_state=42,
)

result["pred"] = model.fit_predict(features)
result["anomaly_score"] = model.decision_function(features)

fit_predict()가 돌려주는 -1이 이상, 1이 정상으로 분류된 표본이다. decision_function()은 값이 낮을수록 더 비정상적인 방향이고, 0보다 작으면 기본 결정 경계에서 이상 쪽이다. random_state는 무작위 분할을 재현하려고 고정한다.

contamination은 학습 데이터에서 예상하는 이상치 비율로 결정 경계를 옮기는 값이다. 이 값을 올리면 표시되는 사건 수가 늘지만 실제 공격 수가 느는 것은 아니다. 값마다 Precision, Recall, F1과 함께 조사해야 할 경보 건수를 같이 놓고 봐야 하는데, 실제로 재 보면 contamination 0.20은 정확도 설정이 아니라 전체 요청의 20%를 사람이 열어 보겠다는 선언에 가깝다(요청 단위 Isolation Forest의 contamination별 측정).

PCA는 여러 특징을 2차원으로 눌러 탐지 결과를 눈으로 보는 보조 도구다. PCA 전에 StandardScaler를 적용하지 않으면 요청 수처럼 범위가 큰 특징이 주성분을 차지한다. 산점도에서 점이 떨어져 보이는 것은 차원을 줄이는 과정에서 정보를 버린 뒤의 그림이므로, 모델이 공격을 확정했다는 뜻이 아니라 원래 특징과 원본 로그를 다시 열어 볼 대상이 생겼다는 뜻이다.

Autoencoder는 복원 오차를 이상 점수로 쓴다

Autoencoder는 입력을 잠재 표현으로 압축했다가 다시 원래 형태로 되돌리도록 학습하는 신경망이다. 정상 데이터만으로 학습하면 정상 패턴은 비교적 잘 복원하고 학습 분포와 다른 데이터는 복원 오차가 커진다는 가정 위에서 이상을 판정한다.

입력 -> Encoder -> 잠재 표현 -> Decoder -> 복원 출력
                         입력과 복원의 차이 = 이상 점수

Dense Autoencoder는 네트워크 플로우 하나를 독립된 특징 벡터로 처리한다. 실습에서 쓴 특징은 duration, src_bytes, dst_bytes, packet_count, syn_ratio, failed_login, connection_count, cpu_ratio 여덟 개다. 정상 학습 데이터로 모델을 학습하고, 검증 데이터에서 복원 오차의 임계값을 정한 뒤, 테스트 표본의 오차가 그 임계값을 넘으면 이상으로 본다.

Python
reconstruction_error = np.mean(
    np.square(x_test - reconstructed),
    axis=1,
)
prediction = reconstruction_error > threshold

GRU Autoencoder는 연속된 여러 플로우를 하나의 시퀀스로 받아 시간 방향의 패턴까지 학습한다. timesteps=10이면 연속한 10개 플로우와 8개 특징을 함께 처리하고, 복원 오차도 시간축과 특징축에 대해 계산한다.

Python
sequence_error = np.mean(
    np.square(x_test - reconstructed),
    axis=(1, 2),
)

여기서 평가 단위가 바뀐다. Dense 쪽의 한 표본은 플로우 하나지만 GRU 쪽의 한 표본은 플로우 10개 묶음이다. 겹치는 시퀀스를 쓰면 같은 플로우가 여러 평가 표본에 들어가므로, 두 모델의 숫자를 나란히 놓기 전에 데이터 분할과 비교 방식을 먼저 맞춰야 한다.

임계값과 데이터 쪽에서 어긋나기 쉬운 지점은 다음과 같다.

  • Scaling 기준은 학습 데이터에서 계산하고 검증·테스트에 그대로 적용한다.
  • 정상 학습 데이터에 공격이 섞이면 모델이 공격 패턴까지 잘 복원하도록 학습한다.
  • 95 percentile 같은 경험적 임계값과 검증 F1이 최대인 임계값은 서로 다른 결과를 낸다.
  • 데이터 드리프트가 생기면 정상 패턴의 복원 오차도 함께 올라간다.
  • 모델 구조와 학습 횟수뿐 아니라 데이터 수집 범위와 분할 방식도 같이 기록해 둔다.

Accuracy 99%가 아무것도 말하지 않을 때

모델은 점수나 복원 오차를 계산한 뒤 임계값으로 정상과 이상을 나눈다. 판정 결과는 네 칸으로 떨어진다.

구분 의미
TP 공격을 이상으로 탐지
FP 정상을 이상으로 오탐
TN 정상을 정상으로 판정
FN 공격을 정상으로 미탐

이 네 칸에서 나오는 지표들이 각각 다른 질문에 답한다.

지표 계산 해석
Accuracy (TP + TN) / 전체 전체 판정 중 정답 비율
Precision TP / (TP + FP) 이상 경보 중 실제 공격 비율
Recall TP / (TP + FN) 실제 공격 중 탐지한 비율
F1 Precision과 Recall의 조화평균 두 지표의 균형
ROC-AUC 여러 임계값의 TPR·FPR 관계 전반적인 순위 분리 능력
PR-AUC 여러 임계값의 Precision·Recall 관계 공격이 드문 데이터에서 유용

공격이 전체의 1%인 데이터에서는 모든 표본을 정상이라고 답해도 Accuracy가 99%가 된다. 보안 이상 탐지의 데이터는 대부분 이런 모양이라, Accuracy 한 칸으로는 아무 판단도 못 한다. 대신 Recall, Precision, PR-AUC와 실제로 쌓이는 경보 건수, 그 경보를 처리하는 비용을 함께 본다.

점수가 좋은 모델이 임계값에서 무너진다

실습에서 저장된 평가 결과가 이 지점을 그대로 보여 준다.

모델 Precision Recall F1 PR-AUC FPR
Dense Autoencoder 0.9931 1.0000 0.9965 0.9999 0.0009
GRU Autoencoder 1.0000 0.6661 0.7996 0.9996 0.0000

GRU Autoencoder의 PR-AUC는 0.9996이다. 여러 임계값을 훑었을 때 공격 표본의 점수가 정상 표본보다 대체로 위에 있다는 뜻이므로, 점수 자체는 공격과 정상을 거의 갈라 놓고 있다. 그런데 선택된 임계값 하나에서는 Recall이 0.666으로 떨어진다. 공격 셋 중 하나를 놓친 셈이다. 모델의 점수 능력과 최종 판정은 다른 칸이고, PR-AUC가 좋다고 해서 지금 돌아가는 탐지기가 잘 잡고 있다는 뜻은 아니다.

두 줄을 위아래로 비교해 어느 모델이 낫다고 말할 수도 없다. Dense 쪽은 플로우 단위, GRU 쪽은 시퀀스 단위로 평가 대상이 달라서 분모가 같은 것을 세지 않는다. 이 표는 코드가 만든 합성 데이터에 대한 저장 산출물이고, 그 코드는 문법 오류와 의존 파일 누락으로 그대로 재실행되지 않는다. 실제 트래픽에서 같은 숫자가 나온다는 근거로는 쓸 수 없다.

임계값을 어디에 둘지는 지표가 아니라 비용이 정한다.

  • 민감하게 두면 Recall이 오르기 쉽지만 FP와 조사 비용이 같이 오른다.
  • 보수적으로 두면 Precision이 오를 수 있지만 FN이 는다.
  • 검증 데이터에서 F1이 가장 높은 임계값은 수업용 기준은 되지만 운영 비용의 최적값과 같지 않다.
  • 운영에서는 공격을 놓쳤을 때의 비용, 정상 사용자를 막았을 때의 비용, 분석 인력이 하루에 처리할 수 있는 경보 수를 넣어 정한다.

규칙 결과를 정답으로 쓰면 무엇이 어긋나나

라벨이 없는 로그에서 평가를 하려면 규칙 탐지 결과를 정답 대신 쓰는 방법이 있다. 이 라벨은 규칙의 오탐과 미탐을 그대로 물려받는다. ML이 규칙에 없는 새 패턴을 찾아내도 채점표에는 FP로 적히고, 규칙이 잘못 잡은 정상 요청은 TP로 적힌다. 새 공격을 찾겠다고 붙인 방법을 규칙으로 채점하면, 규칙과 다르게 답할수록 점수가 깎인다.

그래서 이 라벨을 Ground Truth로 읽지 않는다. 별도의 검증 표본이나 수동 분석 결과를 함께 쓰고, 시간 기반으로 분할하고, 학습과 검증에 같은 IP나 거의 같은 이벤트가 동시에 들어가지 않았는지 확인한다.

특징을 바꾸면 탐지에서 빠질 수 있다

공격자는 탐지기가 어떤 특징을 보는지 추정해 행동을 정상처럼 바꿀 수 있다. 회피를 살펴보는 목적은 어떤 특징이 조작 가능하고 단일 모델이 어디서 무너지는지 확인해 방어를 고치는 데 있다.

특징 공격자가 바꿀 수 있는 행동 탐지 영향
req_count 요청 수를 줄임 대량 요청 신호 감소
avg_gap_sec 요청 간격을 늘림 자동화 속도 신호 감소
special_char_ratio Payload를 인코딩·변형 문자열 기반 특징 약화
status4xx_ratio, error_rate 성공 가능성이 높은 요청을 섞음 오류 비율 신호 약화

행동 특징만 정상처럼 바꾸면 내용 특징이 남아 걸리고, 내용 특징까지 바꾸면 단일 모델의 순위에서 한참 밀린다. 탐지기가 빈도, 시간, 내용, 응답, 세션 관계를 함께 보고 특징 하나에 기대지 않아야 하는 이유가 여기에 있다.

Isolation Forest에서 공격자의 anomaly_score가 양수로 바뀌거나 이상 집합에서 빠졌다고 해서 공격이 사라진 것은 아니다. 지금 고른 특징과 임계값에서 정상으로 분류되었다는 사실만 확인된 것이다. 모델끼리 점수를 비교할 때도 주의할 지점이 있다. anomaly_score의 방향과 범위가 모델마다 달라서 원값을 그대로 더하면 안 되고, 모델별 순위로 바꾸거나 같은 범위로 보정한 뒤 합친다.

탐지기를 여러 개 두고 투표시키면

단일 탐지기의 빈칸을 메우는 방법으로 여러 탐지기의 결과를 모아 표를 세는 방식이 있다.

규칙 기반 + Isolation Forest + LOF + One-Class SVM
                      -> IP별 득표수
                      -> 임계값 이상이면 조사 후보
투표 임계값 성격 운영 영향
1표 민감 새 공격 후보를 넓게 보지만 오탐 증가
2표 균형 둘 이상의 관점이 동의한 사건 우선
3표 이상 보수 경보는 줄지만 단일 관점의 공격을 놓친다

앙상블이 효과를 내려면 모델들의 오류가 서로 달라야 한다. 같은 데이터에 비슷한 특징으로 학습한 모델들은 같은 자리에서 같이 틀리고, 그러면 득표수가 3표여도 신뢰도가 3배가 되지 않는다. 서로 다른 관점(문자열, 빈도, 밀도, 경계)을 섞는 것이 표를 늘리는 것보다 앞선다.

운영에서 표 수를 읽는 방식은 이렇게 갈린다. 만장일치 사건은 우선 조사 대상에 올리고, 한두 모델만 잡은 사건은 오탐으로 버리는 대신 새 패턴 후보 큐에 남긴다. 분석가가 확정한 결과는 특징과 규칙, 임계값을 고치는 데 되돌린다. 실제로 성격이 다른 탐지기 여럿을 한 파이프라인에 이어 보면 알고리즘보다 출력 스키마를 맞추는 일이 먼저 나온다(탐지기 넷을 잇는 데 든 것은 새 알고리즘이 아니라 어댑터 네 개였다). 회피 실험은 본인 소유이거나 명시적으로 허가된 합성·로컬 환경에서만 한다.

여기까지는 강의와 문서로 정리한 것이고, 직접 돌려서 확인한 범위는 Isolation Forest를 요청 단위와 세션 단위로 나눠 재 본 것까지다. Autoencoder와 GRU Autoencoder의 지표표는 재실행하지 못한 합성 데이터 산출물을 옮겨 적은 것이고, LOF와 One-Class SVM은 표에 적힌 판단 기준만 확인했을 뿐 같은 로그에 붙여 순위를 비교해 보지 않았다. 탐지기 투표도 표 수를 바꿔 가며 실제 경보 건수가 어떻게 움직이는지는 아직 재 보지 않았다.

2026-09-25 정정: 연결된 실습은 집계 단위와 특징 구성을 함께 바꾼 비교이므로, 집계 단위만의 효과로 설명하지 않도록 고쳤다. ML만 낸 경보와 ML만 잡은 참 공격의 순증도 구분했다.