Skip to content

보안 사고와 공격/방어 기초

들어가며

당신의 웹사이트는 안전한가요? 많은 개발자가 "보안은 보안 팀의 일"이라고 생각합니다. 자신의 프로젝트가 공격받고 사용자 데이터가 유출될 때까지 말이죠. 보안은 선택 사항이 아니라 모든 개발자의 기본기입니다.

이 장에서는 보안 사고를 확립하고, 가장 일반적인 웹 보안 위협과 방어 방법을 이해합니다.

이 글에서 무엇을 배울 수 있을까요?

내용핵심 개념
1장보안 사고 모델공격자처럼 생각하기
2장일반적인 웹 공격XSS, SQL 인젝션, CSRF
3장방어 전략입력 검증, 출력 인코딩, 권한 제어
4장보안 체크리스트프로젝트 출시 전 보안 자가점검

이 장을 마치면 기본적인 보안 인식을 갖추고, 가장 일반적인 웹 보안 위협을 식별하고 방어할 수 있게 됩니다.


0. 전경도: 왜 개발자가 보안을 알아야 할까요?

집을 하나 지었다고 상상해 보세요. 기능은 모두 갖추고 인테리어도 예쁘지만, 자물쇠를 설치하는 것을 잊었습니다. 보안 취약점은 코드 세계에서 "잊고 설치하지 않은 자물쇠"와 같습니다.

보안의 핵심 원칙

  • 최소 권한: 필요한 권한만 부여하고, 한 치도 더 주지 않기
  • 심층 방어: 단일 방어선에 의존하지 않고, 여러 겹으로 방어하기
  • 입력은 절대 신뢰하지 않기: 외부에서 들어오는 모든 데이터는 악의적일 수 있음
  • 안전한 기본값: 기본 설정은 편의보다 안전해야 함

1. 일반적인 웹 공격

아래의 인터랙티브 컴포넌트를 통해 세 가지 가장 일반적인 웹 공격 원리를 이해해 보세요 (교육 목적으로만 사용):

Web security vulnerability demo (educational) - click to switch vulnerability type
Attack flow
1Attacker submits malicious script in an input field
2Server stores it without filtering
3Script runs when another user opens the page
4User cookies or data are stolen
❌ Vulnerable code
// Directly inserting user input (dangerous!)
el.innerHTML = userInput
// If userInput = '<scr' + 'ipt>steal(cookie)</scr' + 'ipt>'
// the script will execute!
✅ Fixed code
// Insert safely with textContent
el.textContent = userInput
// Or use framework escaping
// Vue: {{ userInput }}  escaped automatically
// React: {userInput}    escaped automatically
Defense:Never trust user input. Use framework escaping, avoid innerHTML, and encode output.

1.1 XSS (사이트 간 스크립팅 공격)

공격자가 악의적인 스크립트를 웹 페이지에 주입하면, 다른 사용자가 접속할 때 브라우저에서 해당 스크립트가 실행됩니다.

javascript
// 위험: 사용자 입력을 HTML에 직접 삽입
element.innerHTML = userInput
// userInput이 <script>악의적코드</script>라면 실행됨

// 안전: textContent 사용 또는 이스케이프
element.textContent = userInput
// 또는 프레임워크의 자동 이스케이프 사용 (Vue의 {{ }}, React의 JSX)

방어 요점:

  • 출력 시 HTML 특수문자 이스케이프 (<, >, &, ", ')
  • 최신 프레임워크의 자동 이스케이프 메커니즘 사용
  • Content-Security-Policy HTTP 헤더 설정

1.2 SQL 인젝션

공격자가 특수한 입력을 구성하여 SQL 쿼리의 논리를 변조합니다.

javascript
// 위험: 문자열 연결로 SQL 작성
const query = `SELECT * FROM users WHERE name = '${userInput}'`
// userInput이 ' OR '1'='1이면 모든 사용자가 반환됨

// 안전: 매개변수화된 쿼리 사용
const query = 'SELECT * FROM users WHERE name = ?'
db.execute(query, [userInput])

방어 요점:

  • 항상 매개변수화된 쿼리 / 준비된 문장(prepared statement) 사용
  • ORM 프레임워크 사용 (예: Prisma, Sequelize)
  • 데이터베이스 계정 권한 제한

1.3 CSRF (사이트 간 요청 위조)

공격자가 로그인한 사용자를 악의적인 페이지로 유도하여, 사용자의 로그인 상태를 이용해 요청을 보냅니다.

방어 요점:

  • CSRF 토큰 사용
  • Referer / Origin 헤더 확인
  • 중요 작업은 GET이 아닌 POST 사용
  • Cookie에 SameSite 속성 설정

2. 방어 전략

2.1 입력 검증

javascript
// 화이트리스트 검증: 예상되는 형식만 허용
function isValidEmail(email) {
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)
}

// 길이 제한
function isValidUsername(name) {
  return name.length >= 2 && name.length <= 50
}

2.2 민감한 데이터 보호

데이터 유형보호 조치
비밀번호bcrypt/argon2 해시, 평문 저장 절대 금지
API 키환경 변수 사용, 코드 저장소에 커밋 금지
사용자 데이터HTTPS 전송, 암호화 저장
세션 토큰HttpOnly + Secure + SameSite Cookie

2.3 HTTP 보안 헤더

Content-Security-Policy: default-src 'self'
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Strict-Transport-Security: max-age=31536000

3. 보안 체크리스트

아래의 인터랙티브 컴포넌트를 사용하여 프로젝트의 보안 상태를 점검하세요:

Project Security Checklist
Check completed safeguards and view the project security score
Security score
0 pts
Danger
🔍Input validation0/3
Validate all user input on the server
Use allowlists instead of blocklists
Limit uploaded file type and size
🔐Authentication and authorization0/4
🛡️Data protection0/3
🌐Communication security0/3

3.1 개발 단계

  • [ ] 모든 사용자 입력이 검증 및 이스케이프 처리됨
  • [ ] 매개변수화된 쿼리 사용, SQL 연결 없음
  • [ ] 비밀번호는 bcrypt 등의 알고리즘으로 해시 저장
  • [ ] 민감한 설정은 환경 변수로 관리
  • [ ] .env 파일이 .gitignore에 추가됨

3.2 배포 단계

  • [ ] HTTPS 활성화
  • [ ] 보안 HTTP 헤더 구성
  • [ ] 디버그 모드 및 상세 오류 메시지 비활성화
  • [ ] 데이터베이스에 최소 권한 계정 사용
  • [ ] 의존성 정기 업데이트 (npm audit)

4. AI 활용: 대형 언어 모델로 보안 방어 향상

대형 언어 모델은 "보안 고문" 역할을 하여 코드 취약점을 감사하고 보안 방안을 생성하는 데 도움을 줄 수 있습니다.

4.1 코드 보안 감사

프롬프트:

다음 코드에 대해 보안 감사를 수행해 주세요:
- XSS 취약점 (이스케이프되지 않은 사용자 입력)
- SQL 인젝션 (문자열 연결 쿼리)
- CSRF 위험 (토큰 검증 누락)
- 민감한 데이터 유출 (하드코딩된 키, 평문 비밀번호)
각 문제에 대해 위험 등급, 구체적인 위치, 수정 방안을 제시해 주세요.

[코드를 여기에 붙여넣으세요]

4.2 보안 구성 생성

프롬프트:

제 프로젝트는 Express.js + PostgreSQL을 사용하며 곧 배포될 예정입니다.
다음을 포함한 완전한 보안 구성 체크리스트를 생성해 주세요:
- HTTP 보안 헤더 구성 코드
- CORS 구성
- 데이터베이스 연결 보안 설정
- 환경 변수 관리 방안
바로 사용할 수 있는 코드 조각을 제시해 주세요.

4.3 취약점 원리 설명

프롬프트:

구체적인 예를 사용하여 CSRF 공격의 전체 흐름을 설명해 주세요:
1. 공격자가 악의적인 페이지를 어떻게 구성하는지
2. 브라우저가 왜 자동으로 쿠키를 전송하는지
3. 서버가 CSRF 토큰으로 어떻게 방어하는지
코드로 공격과 방어의 전체 과정을 시연해 주세요.

AI 사용 제안

AI의 보안 감사는 전문적인 보안 테스트를 대체할 수 없습니다. 첫 번째 선별 도구로 사용하고, 핵심 시스템은 여전히 전문 보안 팀의 감사가 필요합니다.


5. 요약

  1. 보안 사고: 외부 입력을 절대 신뢰하지 않기, 최소 권한, 심층 방어
  2. 일반적인 공격: XSS, SQL 인젝션, CSRF가 가장 빈번한 웹 보안 위협
  3. 방어 전략: 입력 검증, 출력 인코딩, 매개변수화된 쿼리, 보안 HTTP 헤더
  4. 보안 습관: 출시 전 보안 체크리스트 확인, 의존성 정기 감사

핵심 성찰

보안은 일회성 작업이 아니라 개발 전 과정에 걸친 습관입니다. 자동차를 탈 때 안전벨트를 매는 것과 같습니다 — 사고가 날 것이라 예상해서가 아니라, 기본적인 안전 의식이기 때문입니다. 코드를 작성할 때마다 스스로에게 물어보세요: 이 입력이 악의적이라면 무슨 일이 일어날까?


추가 읽기

  • OWASP Top 10: 웹 애플리케이션 보안 10대 위험 목록으로, 모든 개발자가 알아야 합니다.
  • 실용 도구: npm audit으로 의존성 취약점을 확인하고, ESLint 보안 플러그인으로 코드를 검사하세요.
  • 심화 학습: HTTPS 원리, JWT 보안 실천 방법, OAuth 2.0 보안 고려사항을 이해하세요.
  • 보안 커뮤니티: 보안 공지를 주시하고, 알려진 취약점을 제때 수정하세요.