Skip to content

필사 모드: [운영체제] 16. 보안: 위협과 방어

한국어
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.
원문 렌더가 준비되기 전까지 텍스트 가이드로 표시합니다.

보안: 위협과 방어

운영체제 보안은 시스템의 자원을 무단 접근, 악의적 수정, 파괴로부터 보호하는 것을 목표로 합니다.

이 글에서는 보안 위협의 종류, 공격 기법, 암호화 기초, 인증 방법,

그리고 시스템 수준의 방어 메커니즘을 살펴봅니다.

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.** 같은 비밀번호라도 사용자마다 다른 솔트를 추가하면 해시값이 달라집니다.

이를 통해 레인보우 테이블(미리 계산된 해시 사전) 공격을 무력화하고,

같은 비밀번호를 사용하는 사용자를 해시값만으로 식별할 수 없게 합니다.

현재 단락 (1/307)

운영체제 보안은 시스템의 자원을 무단 접근, 악의적 수정, 파괴로부터 보호하는 것을 목표로 합니다.

작성 글자: 0원문 글자: 6,814작성 단락: 0/307