- Authors

- Name
- Youngju Kim
- @fjvbn20031
보안: 위협과 방어
운영체제 보안은 시스템의 자원을 무단 접근, 악의적 수정, 파괴로부터 보호하는 것을 목표로 합니다. 이 글에서는 보안 위협의 종류, 공격 기법, 암호화 기초, 인증 방법, 그리고 시스템 수준의 방어 메커니즘을 살펴봅니다.
1. 보안 문제 개요
보안의 3요소 (CIA Triad)
기밀성
(Confidentiality)
╱ ╲
╱ 보안 ╲
╱ 목표 ╲
╱ ╲
가용성 ─────────── 무결성
(Availability) (Integrity)
| 요소 | 설명 | 위협 예시 |
|---|---|---|
| 기밀성 | 인가된 사용자만 정보 접근 | 도청, 데이터 유출 |
| 무결성 | 인가된 방법으로만 정보 수정 | 데이터 변조, 위조 |
| 가용성 | 인가된 사용자가 필요 시 접근 가능 | DoS 공격, 랜섬웨어 |
보안 위협 계층
┌──────────────────────────────────────┐
│ 공격 표면 │
│ │
│ 물리적: 서버 직접 접근, USB 공격 │
│ │ │
│ 네트워크: 원격 공격, 패킷 스니핑 │
│ │ │
│ 운영체제: 권한 상승, 커널 익스플로잇│
│ │ │
│ 애플리케이션: 코드 인젝션, XSS │
│ │ │
│ 사회공학: 피싱, 스피어피싱 │
└──────────────────────────────────────┘
2. 프로그램 위협 (Program Threats)
맬웨어 (Malware) 분류
┌────────────────────────────────────────────────┐
│ 맬웨어 분류 │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ 바이러스│ │ 웜 │ │ 트로이 │ │
│ │ │ │ │ │ 목마 │ │
│ │숙주 필요│ │자가 전파│ │위장 │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ 랜섬 │ │ 스파이 │ │ 루트킷 │ │
│ │ 웨어 │ │ 웨어 │ │ │ │
│ │파일 암호│ │정보 수집│ │은닉 │ │
│ └─────────┘ └─────────┘ └─────────┘ │
└────────────────────────────────────────────────┘
코드 인젝션 (Code Injection)
외부 입력을 통해 악의적 코드를 실행하는 공격입니다.
// SQL 인젝션 예시 - 취약한 코드
void login(const char *username, const char *password) {
char query[512];
// 위험: 사용자 입력을 직접 쿼리에 삽입
sprintf(query, "SELECT * FROM users WHERE name='%s' AND pass='%s'",
username, password);
execute_query(query);
}
// 공격 입력:
// username: admin' --
// password: (아무 값)
// 생성되는 쿼리:
// SELECT * FROM users WHERE name='admin' --' AND pass='...'
// -- 이후는 주석 처리되어 비밀번호 검증 우회
// 방어: 준비된 문장(Prepared Statement) 사용
void login_safe(const char *username, const char *password) {
// 매개변수화된 쿼리 - 입력이 데이터로만 처리됨
prepare_statement("SELECT * FROM users WHERE name=? AND pass=?");
bind_parameter(1, username);
bind_parameter(2, password);
execute_prepared();
}
버퍼 오버플로 (Buffer Overflow)
가장 고전적이면서도 여전히 위험한 공격 기법입니다.
// 취약한 코드 예시
void vulnerable_function(const char *input) {
char buffer[64];
// 위험: 입력 길이를 확인하지 않음
strcpy(buffer, input); // 64바이트 이상 입력 시 오버플로
}
스택 구조 (오버플로 전):
┌──────────────────┐ 높은 주소
│ 반환 주소 │
├──────────────────┤
│ 이전 프레임 포인터│
├──────────────────┤
│ buffer[64] │
│ (64 바이트) │
├──────────────────┤ 낮은 주소
스택 구조 (오버플로 후):
┌──────────────────┐ 높은 주소
│ 악성 코드 주소 │ ← 반환 주소 덮어씀!
├──────────────────┤
│ AAAAAAAAAAAAAAAA │ ← 덮어씀
├──────────────────┤
│ AAAAAAAAAAAAAAAA │ ← 공격 데이터
│ (64 바이트 이상) │
├──────────────────┤ 낮은 주소
// 방어: 안전한 문자열 함수 사용
void safe_function(const char *input) {
char buffer[64];
// 길이를 제한하는 안전한 복사
strncpy(buffer, input, sizeof(buffer) - 1);
buffer[sizeof(buffer) - 1] = '\0';
}
3. 시스템 및 네트워크 위협
웜 (Worm)
네트워크를 통해 자동으로 전파되는 자기 복제 프로그램입니다.
감염된 호스트 A
│
├── 네트워크 스캔 (취약 호스트 탐색)
│
├── 호스트 B 감염 (취약점 악용)
│ ├── 호스트 D 감염
│ └── 호스트 E 감염
│
└── 호스트 C 감염 (취약점 악용)
├── 호스트 F 감염
└── ...
지수적 전파 → 짧은 시간에 대규모 감염
포트 스캐닝
공격자 대상 서버
│ │
├── SYN → 포트 22 ──────────────→│
│←──────────── SYN-ACK ─────────│ 포트 22: 열림 (SSH)
│ │
├── SYN → 포트 23 ──────────────→│
│←──────────── RST ─────────────│ 포트 23: 닫힘
│ │
├── SYN → 포트 80 ──────────────→│
│←──────────── SYN-ACK ─────────│ 포트 80: 열림 (HTTP)
│ │
├── SYN → 포트 443 ─────────────→│
│←──────────── SYN-ACK ─────────│ 포트 443: 열림 (HTTPS)
...
DoS (Denial of Service) 공격
일반 요청:
클라이언트 → [정상 요청] → 서버 → [정상 응답]
DoS 공격:
공격자 → [대량의 요청] → 서버 (과부하) → 정상 사용자 접근 불가
DDoS (분산 DoS):
봇넷 호스트 1 ─→ ┐
봇넷 호스트 2 ─→ ├→ 서버 (과부하)
봇넷 호스트 3 ─→ ┤
... ─→ ┘
SYN Flood 공격:
공격자가 SYN 패킷만 대량 발송, SYN-ACK 응답 무시
→ 서버의 연결 대기 큐 고갈
4. 암호화 (Cryptography)
대칭 키 암호화
하나의 키로 암호화와 복호화를 모두 수행합니다.
송신자 수신자
┌──────┐ ┌──────────┐ ┌──────┐
│평문 │─→ │암호화 │─→ │암호문│─→ ... ─→ ┌──────────┐─→ ┌──────┐
│Hello │ │(비밀 키) │ │X7k9p│ │복호화 │ │Hello │
└──────┘ └──────────┘ └──────┘ │(같은 키) │ └──────┘
└──────────┘
알고리즘: AES (128/192/256비트), ChaCha20
문제: 키 교환 - 어떻게 안전하게 키를 공유할 것인가?
비대칭 키 암호화 (공개 키 암호화)
공개 키와 개인 키 쌍을 사용합니다.
수신자의 키 쌍:
┌──────────┐ ┌──────────┐
│ 공개 키 │ │ 개인 키 │
│ (공개) │ │ (비밀) │
└──────────┘ └──────────┘
암호화:
송신자: 평문 + 수신자 공개 키 → 암호문
복호화:
수신자: 암호문 + 수신자 개인 키 → 평문
디지털 서명:
서명자: 해시 + 서명자 개인 키 → 서명
검증자: 서명 + 서명자 공개 키 → 해시 확인
알고리즘: RSA, ECC (Elliptic Curve Cryptography)
해시 함수
임의 길이 입력을 고정 길이 출력으로 변환합니다.
입력 SHA-256 해시
"Hello" → 185f8db32271fe25f561a6fc938b2e26
4306ec304eda518007d1764826381969
"Hello!" → 334d016f755cd6dc58c53a86e183882f
8ec14f52fb05345887c8a5edd42c87b7
특성:
- 단방향: 해시로부터 원본 복원 불가
- 충돌 저항성: 같은 해시를 만드는 다른 입력 찾기 어려움
- 눈사태 효과: 입력 1비트 변경 시 해시가 크게 변함
용도: 비밀번호 저장, 무결성 검증, 디지털 서명
알고리즘: SHA-256, SHA-3, bcrypt (비밀번호용)
// 비밀번호 해싱 예시 (의사 코드)
#include <openssl/sha.h>
#include <string.h>
#include <stdio.h>
void hash_password(const char *password, const char *salt,
unsigned char *hash_out) {
char salted[256];
// 솔트(salt)를 추가하여 레인보우 테이블 공격 방지
snprintf(salted, sizeof(salted), "%s%s", salt, password);
SHA256((unsigned char *)salted, strlen(salted), hash_out);
}
int verify_password(const char *input, const char *salt,
const unsigned char *stored_hash) {
unsigned char computed[SHA256_DIGEST_LENGTH];
hash_password(input, salt, computed);
return memcmp(computed, stored_hash, SHA256_DIGEST_LENGTH) == 0;
}
5. 사용자 인증 (User Authentication)
인증 방법 분류
┌─────────────────────────────────────────────┐
│ 인증 요소 (Factor) │
│ │
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ │
│ │ 지식 기반 │ │ 소유 기반 │ │ 생체 기반 │ │
│ │ (알고있는 │ │ (가지고 │ │ (자신의 │ │
│ │ 것) │ │ 있는 것) │ │ 특성) │ │
│ │ │ │ │ │ │ │
│ │ 비밀번호 │ │ 보안 토큰 │ │ 지문 │ │
│ │ PIN │ │ 스마트카드│ │ 홍채 │ │
│ │ 보안 질문 │ │ OTP │ │ 얼굴 인식 │ │
│ └───────────┘ └───────────┘ └───────────┘ │
│ │
│ 다중 요소 인증 (MFA): │
│ 두 가지 이상의 요소를 결합하여 보안 강화 │
└─────────────────────────────────────────────┘
비밀번호 보안
취약한 비밀번호 저장:
┌──────────────────────────────────┐
│ users 테이블 │
│ username │ password │
│ admin │ admin123 ← 평문! │
│ user1 │ password1 ← 위험! │
└──────────────────────────────────┘
안전한 비밀번호 저장:
┌──────────────────────────────────────────────┐
│ users 테이블 │
│ username │ salt │ hashed_password │
│ admin │ x7k2m9 │ a3f2e8... (해시값) │
│ user1 │ p4q8n1 │ b7d1c5... (해시값) │
└──────────────────────────────────────────────┘
→ 솔트 + 느린 해시 (bcrypt, Argon2)
6. 보안 방어 (Security Defenses)
방화벽 (Firewall)
외부 네트워크 (인터넷)
│
┌────┴─────────────────┐
│ 방화벽 │
│ │
│ 규칙 예시: │
│ 허용: TCP 80 (HTTP) │
│ 허용: TCP 443 (HTTPS)│
│ 차단: TCP 23 (Telnet)│
│ 차단: 기타 모든 포트 │
└────┬─────────────────┘
│
내부 네트워크 (LAN)
┌────┴────┬────────┐
│ │ │
서버1 서버2 서버3
침입 탐지 시스템 (IDS)
네트워크 트래픽
│
▼
┌─────────────────────┐
│ IDS 엔진 │
│ │
│ 시그니처 기반: │
│ 알려진 공격 패턴 │
│ 매칭 │
│ │
│ 이상 탐지 기반: │
│ 정상 패턴 학습 후 │
│ 비정상 행위 감지 │
│ │
│ 매칭 시 → 알림 │
└─────────────────────┘
│
▼
관리자에게 경고
(또는 IPS가 자동 차단)
ASLR (Address Space Layout Randomization)
버퍼 오버플로 공격을 어렵게 만드는 기법입니다.
ASLR 없이 (고정 주소): ASLR 적용 (랜덤 주소):
┌──────────────────┐ ┌──────────────────┐
│ 0x08048000 코드 │ │ 0x55a3b000 코드 │ ← 매번 다른 주소
│ ... │ │ ... │
│ 0x0804A000 데이터│ │ 0x55a3d000 데이터│
│ ... │ │ ... │
│ 0xBFFF0000 스택 │ │ 0x7FFD2000 스택 │ ← 매번 다른 주소
│ ... │ │ ... │
│ 0xB7E00000 라이브│ │ 0x7F4A1000 라이브│
│ 러리 │ │ 러리 │
└──────────────────┘ └──────────────────┘
공격자가 주소 예측 가능 공격자가 주소 예측 불가
추가 방어 기법
┌─────────────────────────────────────────┐
│ 보안 방어 기법 │
│ │
│ 스택 카나리 (Stack Canary): │
│ ┌──────────┐ │
│ │ 반환 주소│ │
│ ├──────────┤ │
│ │ 카나리값 │ ← 함수 반환 시 검증 │
│ ├──────────┤ 값 변경 시 → 프로그램 종료│
│ │ buffer │ │
│ └──────────┘ │
│ │
│ DEP (Data Execution Prevention): │
│ 스택/힙 영역의 코드 실행 금지 │
│ W^X: 쓰기 가능 ⊕ 실행 가능 │
│ │
│ CFI (Control Flow Integrity): │
│ 프로그램의 제어 흐름이 예상 경로만 │
│ 따르도록 강제 │
└─────────────────────────────────────────┘
7. 정리
- 프로그램 위협: 맬웨어(바이러스, 웜, 랜섬웨어), 코드 인젝션, 버퍼 오버플로
- 네트워크 위협: 포트 스캐닝, DoS/DDoS 공격, 중간자 공격
- 암호화: 대칭 키(AES), 비대칭 키(RSA), 해시(SHA-256)
- 인증: 지식/소유/생체 기반, 다중 요소 인증(MFA)
- 방어: 방화벽, IDS/IPS, ASLR, DEP, 스택 카나리, CFI
퀴즈: 보안
Q1. 버퍼 오버플로 공격을 방어하는 기법 3가지를 설명하세요.
A1. (1) ASLR: 메모리 주소를 무작위로 배치하여 공격자가 목표 주소를 예측하기 어렵게 합니다. (2) 스택 카나리: 반환 주소 앞에 감시 값을 두어 오버플로 시 변조를 감지합니다. (3) DEP(Data Execution Prevention): 스택이나 힙 영역에서 코드 실행을 금지하여 주입된 코드가 실행되지 않게 합니다.
Q2. 대칭 키 암호화와 비대칭 키 암호화의 차이점은?
A2. 대칭 키는 하나의 키로 암호화와 복호화를 모두 수행하여 속도가 빠르지만, 키를 안전하게 교환하는 문제가 있습니다. 비대칭 키는 공개 키와 개인 키 쌍을 사용하여 키 교환 문제를 해결하지만, 연산이 느립니다. 실제로는 비대칭 키로 대칭 키를 교환한 후 대칭 키로 데이터를 암호화하는 하이브리드 방식을 사용합니다.
Q3. 비밀번호 저장 시 솔트(salt)를 사용하는 이유는?
A3. 같은 비밀번호라도 사용자마다 다른 솔트를 추가하면 해시값이 달라집니다. 이를 통해 레인보우 테이블(미리 계산된 해시 사전) 공격을 무력화하고, 같은 비밀번호를 사용하는 사용자를 해시값만으로 식별할 수 없게 합니다.