보안 사고와 공격/방어 기초
들어가며
당신의 웹사이트는 안전한가요? 많은 개발자가 "보안은 보안 팀의 일"이라고 생각합니다. 자신의 프로젝트가 공격받고 사용자 데이터가 유출될 때까지 말이죠. 보안은 선택 사항이 아니라 모든 개발자의 기본기입니다.
이 장에서는 보안 사고를 확립하고, 가장 일반적인 웹 보안 위협과 방어 방법을 이해합니다.
이 글에서 무엇을 배울 수 있을까요?
| 장 | 내용 | 핵심 개념 |
|---|---|---|
| 1장 | 보안 사고 모델 | 공격자처럼 생각하기 |
| 2장 | 일반적인 웹 공격 | XSS, SQL 인젝션, CSRF |
| 3장 | 방어 전략 | 입력 검증, 출력 인코딩, 권한 제어 |
| 4장 | 보안 체크리스트 | 프로젝트 출시 전 보안 자가점검 |
이 장을 마치면 기본적인 보안 인식을 갖추고, 가장 일반적인 웹 보안 위협을 식별하고 방어할 수 있게 됩니다.
0. 전경도: 왜 개발자가 보안을 알아야 할까요?
집을 하나 지었다고 상상해 보세요. 기능은 모두 갖추고 인테리어도 예쁘지만, 자물쇠를 설치하는 것을 잊었습니다. 보안 취약점은 코드 세계에서 "잊고 설치하지 않은 자물쇠"와 같습니다.
보안의 핵심 원칙
- 최소 권한: 필요한 권한만 부여하고, 한 치도 더 주지 않기
- 심층 방어: 단일 방어선에 의존하지 않고, 여러 겹으로 방어하기
- 입력은 절대 신뢰하지 않기: 외부에서 들어오는 모든 데이터는 악의적일 수 있음
- 안전한 기본값: 기본 설정은 편의보다 안전해야 함
1. 일반적인 웹 공격
아래의 인터랙티브 컴포넌트를 통해 세 가지 가장 일반적인 웹 공격 원리를 이해해 보세요 (교육 목적으로만 사용):
// Directly inserting user input (dangerous!)
el.innerHTML = userInput
// If userInput = '<scr' + 'ipt>steal(cookie)</scr' + 'ipt>'
// the script will execute!// Insert safely with textContent
el.textContent = userInput
// Or use framework escaping
// Vue: {{ userInput }} escaped automatically
// React: {userInput} escaped automatically1.1 XSS (사이트 간 스크립팅 공격)
공격자가 악의적인 스크립트를 웹 페이지에 주입하면, 다른 사용자가 접속할 때 브라우저에서 해당 스크립트가 실행됩니다.
// 위험: 사용자 입력을 HTML에 직접 삽입
element.innerHTML = userInput
// userInput이 <script>악의적코드</script>라면 실행됨
// 안전: textContent 사용 또는 이스케이프
element.textContent = userInput
// 또는 프레임워크의 자동 이스케이프 사용 (Vue의 {{ }}, React의 JSX)방어 요점:
- 출력 시 HTML 특수문자 이스케이프 (
<,>,&,",') - 최신 프레임워크의 자동 이스케이프 메커니즘 사용
Content-Security-PolicyHTTP 헤더 설정
1.2 SQL 인젝션
공격자가 특수한 입력을 구성하여 SQL 쿼리의 논리를 변조합니다.
// 위험: 문자열 연결로 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 입력 검증
// 화이트리스트 검증: 예상되는 형식만 허용
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=315360003. 보안 체크리스트
아래의 인터랙티브 컴포넌트를 사용하여 프로젝트의 보안 상태를 점검하세요:
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. 요약
- 보안 사고: 외부 입력을 절대 신뢰하지 않기, 최소 권한, 심층 방어
- 일반적인 공격: XSS, SQL 인젝션, CSRF가 가장 빈번한 웹 보안 위협
- 방어 전략: 입력 검증, 출력 인코딩, 매개변수화된 쿼리, 보안 HTTP 헤더
- 보안 습관: 출시 전 보안 체크리스트 확인, 의존성 정기 감사
핵심 성찰
보안은 일회성 작업이 아니라 개발 전 과정에 걸친 습관입니다. 자동차를 탈 때 안전벨트를 매는 것과 같습니다 — 사고가 날 것이라 예상해서가 아니라, 기본적인 안전 의식이기 때문입니다. 코드를 작성할 때마다 스스로에게 물어보세요: 이 입력이 악의적이라면 무슨 일이 일어날까?
추가 읽기
- OWASP Top 10: 웹 애플리케이션 보안 10대 위험 목록으로, 모든 개발자가 알아야 합니다.
- 실용 도구:
npm audit으로 의존성 취약점을 확인하고, ESLint 보안 플러그인으로 코드를 검사하세요. - 심화 학습: HTTPS 원리, JWT 보안 실천 방법, OAuth 2.0 보안 고려사항을 이해하세요.
- 보안 커뮤니티: 보안 공지를 주시하고, 알려진 취약점을 제때 수정하세요.