-
침입 판정 기준값 데이터 준비tip 2025. 1. 4. 18:01
04_determine_intrusion_detection_threshold 침입 감지를 판정할 d_ts의 기준값을 준비한다.¶
- 침입이 있다면 메시지 전송 간격인 d_ts (= timestamp의 diff라는 의미로 d_ts)가 줄어들게 된다.
- 칩입이 없을 때 d_ts의 최소값을 d_ts_min이라고 하자.
- 침입 판정 기준을 d_ts_intrusion_detection_threshold라고 하자.
- d_ts가 d_ts_min 보다 작아으면 침입으로 감지로 의심할 수 있다.
- d_ts_min을 구하는데 사용된 데이터가 충분히 많다고 할 수 없다.
- 내가 사용한 데이터는 3분 30초 길이로 너무 짧다.
- 내가 했던 주행도 매우 평범하여 제어기에 연산 하중이 매우 작았을 것이다. 그래서 전송 주기에 영향이 거의 없었을 것이다.
- 데이터가 충분하지 않아 너무 민감하게 침입을 감지할 가능성이 있다.
- 메시지별 d_ts 분포를 보고 3번 셀의 방법으로 보상을 해주기로 한다.
- 보상 방업의 정확성 보다는 민감 감지를 방지하는 조치의 필요성이 전달되면 이 데모의 목적 달성에 충분하다.
- d_ts_intrusion_detection_threshold = d_ts_min - d_ts_intrusion_detection_desensitizer 이다.
- 기준값들을 파일로 저장하고, 미니프로그램에서 파일을 로드하여 기준값들을 사용할 수 있도록 한다.
In [1]:import pandas as pd from pathlib import Path
In [2]:# 메시지별 d_ts 통계값을 저장한 xlsx 파일을 읽는다. xlsx_d_ts_distribution = Path.cwd() / 'd_ts_distribution.xlsx' df_d_ts_distribution = pd.read_excel(xlsx_d_ts_distribution, sheet_name='Sheet1', header=0, index_col=0) df_d_ts_distribution.head(3)
Out[2]:count mean std min 25% 50% 75% max 042.asc 384 0.999332 0.000104 0.999062 0.999282 0.999332 0.999387 0.999562 043.asc 384 0.999332 0.000104 0.999062 0.999282 0.999332 0.999387 0.999561 044.asc 387 0.991565 0.083612 0.040136 0.999277 0.999332 0.999386 0.999561 In [3]:def get_d_ts_intrusion_detection_threshold(row): if row['mean'] < 0.011: d_ts_intrusion_detection_desensitizer = 0.003 elif row['mean'] < 0.021: d_ts_intrusion_detection_desensitizer = 0.004 elif row['mean'] < 0.051: d_ts_intrusion_detection_desensitizer = 0.005 elif row['mean'] < 0.101: d_ts_intrusion_detection_desensitizer = 0.006 elif row['mean'] < 0.201: d_ts_intrusion_detection_desensitizer = 0.007 elif row['mean'] < 0.501: d_ts_intrusion_detection_desensitizer = 0.008 else: d_ts_intrusion_detection_desensitizer = 0.009 d_ts_intrusion_detection_threshold = row['min'] - d_ts_intrusion_detection_desensitizer return d_ts_intrusion_detection_threshold
In [4]:df_d_ts_distribution['d_ts_intrusion_detection_threshold'] = df_d_ts_distribution.apply(get_d_ts_intrusion_detection_threshold, axis=1) df_d_ts_distribution.sample(3)
Out[4]:count mean std min 25% 50% 75% max d_ts_intrusion_detection_threshold 557.asc 3840 0.100004 0.000708 0.096538 0.099807 0.100011 0.100208 0.104078 0.090538 280.asc 38393 0.010000 0.000369 0.008293 0.009876 0.010005 0.010138 0.011689 0.005293 5A0.asc 384 0.999825 0.000886 0.994424 0.999810 0.999896 1.000041 1.005045 0.985424 미니프로그램에서 사용할 데이터를 만든다.¶
white list¶
In [5]:# white_list # m_id들이다. 10진수로 변환한다. id_white_list = [int(id.strip('.asc'), base=16) for id in list(df_d_ts_distribution.index)] print(id_white_list)
[66, 67, 68, 128, 129, 273, 274, 275, 292, 339, 356, 399, 512, 544, 593, 608, 640, 688, 790, 809, 832, 838, 844, 884, 897, 899, 902, 903, 909, 916, 1047, 1078, 1155, 1170, 1191, 1253, 1254, 1255, 1265, 1280, 1282, 1287, 1292, 1294, 1322, 1342, 1345, 1349, 1351, 1353, 1363, 1366, 1367, 1427, 1440, 1456, 1486, 1487, 1530]
d_ts_intrusion_detection_threshold¶
In [6]:# d_ts_intrusion_detection_threshold # TSMaster의 timer는 usec 단위이다. sec를 usec로 변환한다. thresholds = df_d_ts_distribution['d_ts_intrusion_detection_threshold'].tolist() thresholds = [int(threshold * 1_000_000) for threshold in thresholds] # convert to usec d_ts_instrusion_detection_threshold = dict(zip(id_white_list, thresholds)) print(d_ts_instrusion_detection_threshold)
{66: 990061, 67: 990061, 68: 31135, 128: 5272, 129: 5274, 273: 6095, 274: 6095, 275: 6072, 292: 5273, 339: 5872, 356: 5302, 399: 5127, 512: 5290, 544: 4866, 593: 5311, 608: 5293, 640: 5293, 688: 4684, 790: 4672, 809: 4903, 832: 2953, 838: 5452, 844: 5503, 884: 5501, 897: 13229, 899: 10295, 902: 13361, 903: 12671, 909: 10686, 916: 12500, 1047: 189472, 1078: 41182, 1155: 187964, 1170: 40929, 1191: 489171, 1253: 90180, 1254: 90177, 1255: 90178, 1265: 12281, 1280: 88256, 1282: 91622, 1287: 88490, 1292: 90296, 1294: 32996, 1322: 29902, 1342: 89216, 1345: 31633, 1349: 89077, 1351: 89070, 1353: 88865, 1363: 32842, 1366: 90035, 1367: 90537, 1427: 189663, 1440: 985424, 1456: 987279, 1486: 91103, 1487: 90860, 1530: 987349}
ts_last¶
In [7]:# ts_last # 지난 번 메시지의 수신 ts이다. 초기값을 0으로 설정한다. ts_last = dict(zip(id_white_list, [0] * len(id_white_list))) print(ts_last)
{66: 0, 67: 0, 68: 0, 128: 0, 129: 0, 273: 0, 274: 0, 275: 0, 292: 0, 339: 0, 356: 0, 399: 0, 512: 0, 544: 0, 593: 0, 608: 0, 640: 0, 688: 0, 790: 0, 809: 0, 832: 0, 838: 0, 844: 0, 884: 0, 897: 0, 899: 0, 902: 0, 903: 0, 909: 0, 916: 0, 1047: 0, 1078: 0, 1155: 0, 1170: 0, 1191: 0, 1253: 0, 1254: 0, 1255: 0, 1265: 0, 1280: 0, 1282: 0, 1287: 0, 1292: 0, 1294: 0, 1322: 0, 1342: 0, 1345: 0, 1349: 0, 1351: 0, 1353: 0, 1363: 0, 1366: 0, 1367: 0, 1427: 0, 1440: 0, 1456: 0, 1486: 0, 1487: 0, 1530: 0}
데이터 구조¶
- 데이터 구조를 잘 만들면 프로그램이 읽기 쉽고 간단해질 것 같다.
- m_id와 용도를 키로 하는 x라는 딕셔너리를 만든다.
In [8]:# 데이터를 파일로 저장할 때 흔히 사용되는 pickle 모듈을 이용한다. import pickle
In [9]:# 앞에서 저장해두었던 m_id별 dlc 변수를 로드한다. id_dlc = pickle.load(open('id_dlc.pkl', 'rb')) print(id_dlc)
{66: 8, 67: 8, 68: 8, 128: 8, 129: 8, 273: 8, 274: 8, 275: 8, 292: 8, 339: 8, 356: 4, 399: 8, 512: 6, 544: 8, 593: 8, 608: 8, 640: 8, 688: 6, 790: 8, 809: 8, 832: 8, 838: 8, 844: 8, 884: 8, 897: 8, 899: 8, 902: 8, 903: 8, 909: 8, 916: 8, 1047: 8, 1078: 4, 1155: 8, 1170: 8, 1191: 2, 1253: 8, 1254: 8, 1255: 8, 1265: 4, 1280: 1, 1282: 4, 1287: 4, 1292: 8, 1294: 8, 1322: 8, 1342: 6, 1345: 8, 1349: 8, 1351: 8, 1353: 8, 1363: 8, 1366: 8, 1367: 8, 1427: 6, 1440: 8, 1456: 4, 1486: 8, 1487: 8, 1530: 8}
In [11]:# m_id와 용도를 키로 하는 x라는 딕셔너리를 만든다. x = {} # x에 m_id별로 d_ts_min을 추가한다. for k, v in d_ts_instrusion_detection_threshold.items(): x[k] = {} x[k]['d_ts_min'] = v x[k]['dlc'] = 0 x[k]['ts_last'] = 0.0 # x에 m_id별로 dlc를 추가한다. for k, v in id_dlc.items(): x[k]['dlc'] = v # x에 m_id별로 ts_last를 추가한다. for k, v in ts_last.items(): x[k]['ts_last'] = v # x를 pickle 파일로 저장한다. pickle.dump(x, open('x.pkl', 'wb')) # 저장이 잘 되었는지, 로드가 잘 되는지 확인한다. x = pickle.load(open('x.pkl', 'rb')) print(x)
{66: {'d_ts_min': 990061, 'dlc': 8, 'ts_last': 0}, 67: {'d_ts_min': 990061, 'dlc': 8, 'ts_last': 0}, 68: {'d_ts_min': 31135, 'dlc': 8, 'ts_last': 0}, 128: {'d_ts_min': 5272, 'dlc': 8, 'ts_last': 0}, 129: {'d_ts_min': 5274, 'dlc': 8, 'ts_last': 0}, 273: {'d_ts_min': 6095, 'dlc': 8, 'ts_last': 0}, 274: {'d_ts_min': 6095, 'dlc': 8, 'ts_last': 0}, 275: {'d_ts_min': 6072, 'dlc': 8, 'ts_last': 0}, 292: {'d_ts_min': 5273, 'dlc': 8, 'ts_last': 0}, 339: {'d_ts_min': 5872, 'dlc': 8, 'ts_last': 0}, 356: {'d_ts_min': 5302, 'dlc': 4, 'ts_last': 0}, 399: {'d_ts_min': 5127, 'dlc': 8, 'ts_last': 0}, 512: {'d_ts_min': 5290, 'dlc': 6, 'ts_last': 0}, 544: {'d_ts_min': 4866, 'dlc': 8, 'ts_last': 0}, 593: {'d_ts_min': 5311, 'dlc': 8, 'ts_last': 0}, 608: {'d_ts_min': 5293, 'dlc': 8, 'ts_last': 0}, 640: {'d_ts_min': 5293, 'dlc': 8, 'ts_last': 0}, 688: {'d_ts_min': 4684, 'dlc': 6, 'ts_last': 0}, 790: {'d_ts_min': 4672, 'dlc': 8, 'ts_last': 0}, 809: {'d_ts_min': 4903, 'dlc': 8, 'ts_last': 0}, 832: {'d_ts_min': 2953, 'dlc': 8, 'ts_last': 0}, 838: {'d_ts_min': 5452, 'dlc': 8, 'ts_last': 0}, 844: {'d_ts_min': 5503, 'dlc': 8, 'ts_last': 0}, 884: {'d_ts_min': 5501, 'dlc': 8, 'ts_last': 0}, 897: {'d_ts_min': 13229, 'dlc': 8, 'ts_last': 0}, 899: {'d_ts_min': 10295, 'dlc': 8, 'ts_last': 0}, 902: {'d_ts_min': 13361, 'dlc': 8, 'ts_last': 0}, 903: {'d_ts_min': 12671, 'dlc': 8, 'ts_last': 0}, 909: {'d_ts_min': 10686, 'dlc': 8, 'ts_last': 0}, 916: {'d_ts_min': 12500, 'dlc': 8, 'ts_last': 0}, 1047: {'d_ts_min': 189472, 'dlc': 8, 'ts_last': 0}, 1078: {'d_ts_min': 41182, 'dlc': 4, 'ts_last': 0}, 1155: {'d_ts_min': 187964, 'dlc': 8, 'ts_last': 0}, 1170: {'d_ts_min': 40929, 'dlc': 8, 'ts_last': 0}, 1191: {'d_ts_min': 489171, 'dlc': 2, 'ts_last': 0}, 1253: {'d_ts_min': 90180, 'dlc': 8, 'ts_last': 0}, 1254: {'d_ts_min': 90177, 'dlc': 8, 'ts_last': 0}, 1255: {'d_ts_min': 90178, 'dlc': 8, 'ts_last': 0}, 1265: {'d_ts_min': 12281, 'dlc': 4, 'ts_last': 0}, 1280: {'d_ts_min': 88256, 'dlc': 1, 'ts_last': 0}, 1282: {'d_ts_min': 91622, 'dlc': 4, 'ts_last': 0}, 1287: {'d_ts_min': 88490, 'dlc': 4, 'ts_last': 0}, 1292: {'d_ts_min': 90296, 'dlc': 8, 'ts_last': 0}, 1294: {'d_ts_min': 32996, 'dlc': 8, 'ts_last': 0}, 1322: {'d_ts_min': 29902, 'dlc': 8, 'ts_last': 0}, 1342: {'d_ts_min': 89216, 'dlc': 6, 'ts_last': 0}, 1345: {'d_ts_min': 31633, 'dlc': 8, 'ts_last': 0}, 1349: {'d_ts_min': 89077, 'dlc': 8, 'ts_last': 0}, 1351: {'d_ts_min': 89070, 'dlc': 8, 'ts_last': 0}, 1353: {'d_ts_min': 88865, 'dlc': 8, 'ts_last': 0}, 1363: {'d_ts_min': 32842, 'dlc': 8, 'ts_last': 0}, 1366: {'d_ts_min': 90035, 'dlc': 8, 'ts_last': 0}, 1367: {'d_ts_min': 90537, 'dlc': 8, 'ts_last': 0}, 1427: {'d_ts_min': 189663, 'dlc': 6, 'ts_last': 0}, 1440: {'d_ts_min': 985424, 'dlc': 8, 'ts_last': 0}, 1456: {'d_ts_min': 987279, 'dlc': 4, 'ts_last': 0}, 1486: {'d_ts_min': 91103, 'dlc': 8, 'ts_last': 0}, 1487: {'d_ts_min': 90860, 'dlc': 8, 'ts_last': 0}, 1530: {'d_ts_min': 987349, 'dlc': 8, 'ts_last': 0}}
사용법¶
- 미니프로그램이 있는 디렉토리에 x.pkl를 복사한다.
- 미니프로그램에 아래 코드를 추가하여 x를 로드한다.
import pickle x = pickle.load(open('[파일 경로]\x.pkl', 'rb'))
'tip' 카테고리의 다른 글
Python 미니프로그램: 코드에서 CAN 메시지의 신호를 읽는 방법 (0) 2025.01.07 IDS 오감지/ 민감 감지에 관한 고찰 (0) 2025.01.04 asc 파일을 pandas 데이터프레임으로 변환하기 (0) 2025.01.04 asc 파일을 m_id별로 분리하기 (0) 2025.01.04 mdf 데이터 파일을 읽어서 그래프 그리기 (1) 2025.01.01