icon

안동민 개발노트

12장 : 보호와 보안

보안 위협과 방어


보호 메커니즘이 완벽하더라도 공격자는 소프트웨어의 취약점을 파고듭니다. OS 수준의 보안 위협과 방어 기법을 이해하면, 안전한 코드를 작성하고 시스템을 견고하게 구성하는 능력이 생깁니다. 보안은 단일 기술이 아니라 계층적 방어(Defense in Depth)입니다.


버퍼 오버플로우

버퍼 오버플로우(Buffer Overflow)는 가장 오래되고 가장 위험한 취약점 중 하나입니다. 1988년 모리스 웜부터 현재까지 계속 발견됩니다.

배열의 범위를 넘어서 데이터를 쓰면, 인접한 메모리 영역(리턴 주소, 함수 포인터 등)을 덮어쓸 수 있습니다.

vulnerable_code.c
#include <string.h>
#include <stdio.h>

/* 취약한 코드 — 절대 이렇게 작성하지 마세요 */
void vulnerable(char *input) {
    char buffer[64];
    strcpy(buffer, input);  /* 입력이 64바이트를 초과하면 오버플로우! */
    printf("Buffer: %s\n", buffer);
}

/* 안전한 코드 */
void safe(const char *input) {
    char buffer[64];
    strncpy(buffer, input, sizeof(buffer) - 1);
    buffer[sizeof(buffer) - 1] = '\0';  /* 널 종단 보장 */
    printf("Buffer: %s\n", buffer);
}

스택 스매싱 공격

메모리 레이아웃 (높은 주소 → 낮은 주소)
┌──────────────────┐
│ 리턴 주소        │ ← 공격자가 이걸 덮어씀
├──────────────────┤
│ 저장된 EBP       │
├──────────────────┤
│ buffer[63]       │ ← 오버플로우 방향 (↑)
│ ...              │
│ buffer[0]        │ ← 버퍼 시작
└──────────────────┘

공격자가 리턴 주소를 자신의 코드 주소로 덮어쓰면, 함수 반환 시 공격자의 코드(shellcode)가 실행됩니다.

다계층 방어

defense_demo.c
#include <stdio.h>
#include <stdlib.h>

int main() {
    /* 1. 안전한 함수 사용 */
    char buf[32];
    /* strcpy → strncpy, sprintf → snprintf, gets → fgets */
    if (fgets(buf, sizeof(buf), stdin) == NULL) return 1;

    /* 2. 컴파일러 방어 (-fstack-protector) */
    /* 스택 카나리: 리턴 주소 앞에 랜덤 값 삽입 */
    /* 함수 반환 시 카나리가 변조되었으면 __stack_chk_fail() 호출 */

    /* 3. OS 방어 (ASLR) */
    printf("스택 변수 주소: %p\n", (void *)buf);
    printf("힙 주소:       %p\n", (void *)malloc(1));
    /* 매 실행마다 주소가 달라짐 → 공격자가 주소 예측 불가 */

    return 0;
}
security_compile.sh
# 모든 보안 옵션을 켜고 컴파일
gcc -fstack-protector-all \
    -D_FORTIFY_SOURCE=2 \
    -Wformat -Wformat-security \
    -pie -fPIE \
    -Wl,-z,relro,-z,now \
    -o program program.c

# -fstack-protector-all:  모든 함수에 스택 카나리
# -D_FORTIFY_SOURCE=2:    버퍼 크기 검사 강화
# -pie -fPIE:             위치 독립 실행 파일 (ASLR 효과 극대화)
# -Wl,-z,relro,-z,now:    GOT 보호 (Full RELRO)
방어 기법대상동작
스택 카나리스택 오버플로우리턴 주소 변조 탐지
ASLR주소 예측메모리 레이아웃 무작위화
DEP/NX코드 주입데이터 영역 실행 금지
PIE코드 영역 예측코드 섹션도 무작위 배치
RELROGOT 변조GOT 영역 읽기 전용화
CFI간접 호출 변조제어 흐름 무결성 검증

악성 코드 분류

유형전파 방식특징예시
바이러스숙주 프로그램에 삽입실행 시 활성화, 자기 복제CIH, Melissa
네트워크 자동 전파독립 실행, 취약점 이용Morris, WannaCry
트로이 목마유용한 프로그램 위장백도어 설치Zeus, Emotet
랜섬웨어다양 (이메일, 웹)파일 암호화 후 몸값 요구WannaCry, Ryuk
루트킷기존 침입 후 설치커널 수준 은닉Sony Rootkit
키로거트로이 목마/물리적키 입력 기록 전송-

실무 방어

integrity_check.py
import hashlib
import os

def file_hash(path):
    """파일의 SHA-256 해시 계산"""
    h = hashlib.sha256()
    with open(path, "rb") as f:
        for chunk in iter(lambda: f.read(8192), b""):
            h.update(chunk)
    return h.hexdigest()

# 중요 시스템 파일의 해시를 저장하고 주기적으로 비교
critical_files = ["/usr/bin/sudo", "/usr/bin/ssh", "/usr/sbin/sshd"]
for f in critical_files:
    if os.path.exists(f):
        print(f"{f}: {file_hash(f)}")

# 해시가 변경되었으면 → 파일이 변조된 것 (루트킷 의심)
# 실무에서는 AIDE, Tripwire, OSSEC 같은 무결성 검사 도구 사용

강제 접근 제어 (MAC)

일반적인 Unix 권한(DAC, Discretionary Access Control)은 파일 소유자가 권한을 마음대로 설정할 수 있습니다. root가 탈취되면 모든 보호가 무력화됩니다.

MAC(Mandatory Access Control)은 시스템 관리자가 정의한 정책에 따라 접근을 제어합니다. root조차 정책을 우회할 수 없습니다.

SELinux

NSA가 개발한 MAC 구현입니다. 프로세스마다 보안 컨텍스트(타입)를 부여하고, 정책에 명시적으로 허용된 접근만 가능합니다.

selinux_demo.sh
# SELinux 상태 확인
getenforce          # Enforcing, Permissive, Disabled
sestatus            # 상세 상태

# 파일의 보안 컨텍스트 확인
ls -Z /var/www/html/index.html
# -rw-r--r--. root root system_u:object_r:httpd_sys_content_t:s0

# httpd 프로세스는 httpd_sys_content_t 타입의 파일만 읽을 수 있음
# /home/user/ 디렉토리는 user_home_t → httpd가 접근 불가

# 컨텍스트 복원
restorecon -Rv /var/www/html/

웹 서버가 해킹되어 root 셸을 획득해도, SELinux 정책에 의해 /etc/shadow 읽기, 네트워크 포트 변경 등이 차단됩니다.

AppArmor

프로그램별로 접근 가능한 파일, 네트워크, 커패빌리티를 프로파일로 정의합니다. SELinux보다 설정이 간단합니다.

apparmor_profile.sh
# /etc/apparmor.d/usr.sbin.nginx 프로파일 예시
# /usr/sbin/nginx {
#   /var/www/** r,          # 웹 콘텐츠 읽기만
#   /var/log/nginx/** w,    # 로그 쓰기만
#   /run/nginx.pid rw,      # PID 파일
#   network inet tcp,       # TCP 네트워크 허용
#   deny /etc/shadow r,     # shadow 파일 읽기 명시적 거부
# }

# AppArmor 상태 확인
aa-status

# 프로파일을 enforce 모드로 설정
aa-enforce /etc/apparmor.d/usr.sbin.nginx

네트워크 보안 기초

방화벽 (iptables/nftables)

firewall_basics.sh
# iptables 기본 규칙: 필요한 것만 허용, 나머지 차단
iptables -P INPUT DROP           # 기본 정책: 모든 입력 차단
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT        # 나가는 트래픽은 허용

# 기존 연결 유지
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# SSH (포트 22) 허용
iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# HTTP/HTTPS 허용
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# 로컬 루프백 허용
iptables -A INPUT -i lo -j ACCEPT

보안 모니터링

security_monitoring.sh
# 실패한 로그인 시도 확인
grep "Failed password" /var/log/auth.log | tail -20

# 현재 열린 포트 확인
ss -tlnp

# 최근 sudo 사용 기록
grep sudo /var/log/auth.log | tail -10

# 비정상 프로세스 확인
ps aux --sort=-pcpu | head -20

보안 계층 정리

계층방어 수단
네트워크방화벽, IDS/IPS, VPN
운영체제MAC(SELinux/AppArmor), 패치 관리, 로깅
애플리케이션입력 검증, 안전한 함수, 코드 분석
데이터암호화, 해싱, 백업
물리잠금장치, BIOS 패스워드, TPM

보안은 OS의 한 기능이 아니라, 물리적 접근부터 애플리케이션 코드까지 전 계층에 걸친 노력입니다. 다음 장에서는 현대 인프라의 핵심인 가상화와 컨테이너를 다루겠습니다.

목차