Secure SDLC: 개발 생명주기에 보안을 내재화하는 법
보안을 출시 직전 점검이 아니라 요구사항·설계·구현·테스트·운영 전 단계에 심는 Secure SDLC를 다룹니다. Shift Left의 비용 논리, DevSecOps 파이프라인 구성, 단계별 보안 활동과 도입 전략을 정리합니다.
지난 글에서 의존성과 빌드 파이프라인을 노리는 공급망 공격을 살펴봤다. lockfile 고정, 스크립트 차단, 서명 검증 같은 장치들은 모두 “개발 프로세스 안에” 들어가야 의미가 있다. 그렇다면 보안 활동을 프로세스 어디에, 어떤 형태로 넣어야 할까. 이번 글의 주제인 Secure SDLC(Secure Software Development Life Cycle)가 그 답이다.
왜 “마지막 보안 점검”은 실패하는가
많은 조직이 보안을 이렇게 다룬다. 개발을 다 끝내고, 출시 2주 전에 보안팀이나 외부 업체에 점검을 맡긴다. 결과는 거의 항상 같다. 출시 일정에 쫓겨 심각한 취약점 몇 개만 급하게 고치고, 나머지는 “다음 분기에”라는 백로그로 들어간 채 출시된다.
이 방식이 실패하는 이유는 의지 부족이 아니라 구조 때문이다.
- 설계 결함은 코드 패치로 못 고친다. 인증 아키텍처가 잘못됐거나 신뢰 경계 설정이 틀렸다면, 출시 직전에 발견해도 고치려면 다시 설계부터 해야 한다.
- 비용이 단계마다 뛴다. 설계 단계에서 화이트보드 토론으로 잡을 결함을 프로덕션에서 발견하면, 사고 대응·데이터 유출 통지·신뢰 손실까지 수십 배의 비용을 치른다.
- 점검 주기와 배포 주기가 어긋난다. 연 1회 침투 테스트로는 하루에 수십 번 배포되는 서비스를 커버할 수 없다.
그래서 나온 원칙이 Shift Left — 보안 활동의 시점을 개발 흐름의 왼쪽(앞 단계)으로 당기는 것이다. Secure SDLC는 이 원칙을 단계별 활동으로 구체화한 프레임워크다. Microsoft SDL, OWASP SAMM, NIST SSDF(SP 800-218)가 대표적인 레퍼런스 모델이다.
단계별 보안 활동
1. 요구사항 — 보안도 요구사항이다
기능 요구사항을 정의할 때 보안 요구사항도 함께 정의한다. “로그인 기능”이라는 요구사항에는 “5회 실패 시 점진적 지연”, “비밀번호는 Argon2id로 해싱”, “세션은 30분 유휴 시 만료” 같은 보안 요구사항이 따라붙어야 한다.
이 단계에서 유용한 도구가 악용 사례(Abuse Case) 다. 유저 스토리가 “사용자로서 파일을 업로드하고 싶다”라면, 악용 사례는 “공격자로서 웹쉘을 업로드하고 싶다”가 된다. 기능마다 악용 사례를 한 줄씩만 적어도 설계 방향이 달라진다. 어떤 수준까지 검증할지는 OWASP ASVS 레벨로 정하는데, 이는 다음 글에서 자세히 다룬다.
2. 설계 — 위협 모델링의 자리
앞서 다룬 위협 모델링(STRIDE)이 실제로 수행되는 단계가 여기다. 새 기능의 데이터 흐름도를 그리고, 신뢰 경계를 표시하고, 경계를 넘는 지점마다 “여기서 무엇이 잘못될 수 있나”를 묻는다. 설계 리뷰에 보안 관점 한 명이 들어가는 것만으로도 인증 우회, 권한 상승 같은 구조적 결함 대부분을 미리 잡을 수 있다.
모든 기능에 풀 위협 모델링을 할 필요는 없다. 인증/인가 변경, 새로운 외부 연동, 민감 데이터 처리 — 이런 트리거 조건에 해당할 때만 수행하는 식으로 비용을 조절한다.
3. 구현 — 자동화가 핵심인 단계
구현 단계의 보안 활동은 사람의 기억력에 의존하면 반드시 실패한다. PR(Pull Request) 시점에 자동으로 도는 게이트로 만들어야 한다.
# .github/workflows/security.yml — PR마다 자동 실행되는 보안 게이트
name: security-gate
on: [pull_request]
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Secret scanning # 커밋된 시크릿 탐지
uses: gitleaks/gitleaks-action@v2
- name: SAST # 정적 분석
run: semgrep ci --config p/owasp-top-ten
- name: Dependency audit # 의존성 취약점
run: npm audit --omit=dev --audit-level=high
여기에 시큐어 코딩 표준(파라미터 바인딩 강제, 출력 인코딩 헬퍼 사용 등)과 보안 관점 코드 리뷰 체크리스트가 더해진다. 핵심은 “개발자가 보안 도구를 찾아가는” 구조가 아니라 “보안 도구가 개발자의 기존 워크플로에 들어와 있는” 구조다.
4. 테스트/검증 — 릴리스 게이트
배포 전 검증 단계에서는 실행 중인 애플리케이션을 대상으로 한 동적 점검이 들어간다. DAST 스캔을 스테이징 환경에 돌리고, 파서나 인증처럼 위험도 높은 컴포넌트에는 퍼징을 적용하며, 주요 릴리스나 분기 단위로 침투 테스트를 수행한다. SAST·DAST·IAST의 차이와 선택 기준, 퍼징과 침투 테스트의 실제 진행 방식은 다음 글들에서 하나씩 다룬다.
5. 운영 — 순환의 시작점
배포가 끝이 아니다. 운영 단계에서는 보안 모니터링과 로그 분석으로 공격 시도를 탐지하고, 침해사고 대응 절차를 가동하며, 버그 바운티로 외부 연구자의 눈을 빌린다. 그리고 가장 중요한 것 — 운영에서 발견된 취약점과 사고의 근본 원인을 다시 요구사항·설계 단계의 체크리스트로 환류시킨다. 이 피드백 루프가 없으면 같은 유형의 취약점이 계속 만들어진다.
DevSecOps와의 관계
Secure SDLC가 “무엇을 언제 할 것인가”의 프레임워크라면, DevSecOps는 그것을 CI/CD 파이프라인과 조직 문화에 녹여내는 실행 방식이다. 실무적으로는 다음 원칙으로 수렴한다.
- 보안 게이트는 파이프라인 안에: 별도 프로세스가 아니라 빌드의 한 단계로
- 빠른 피드백: PR에서 5분 안에 결과를 주지 못하는 도구는 무시당한다
- 오탐 관리: false positive가 쌓이면 개발자는 경고 자체를 끄게 된다. 룰 튜닝은 보안팀의 책임
- Security Champion: 각 개발팀에 보안 연락책 한 명을 두어 보안팀과의 병목을 줄인다
작게 시작하는 도입 순서
처음부터 전 단계를 도입하려다 실패하는 조직이 많다. 효과 대비 비용이 낮은 순서로 쌓아가는 것이 현실적이다.
1단계 (1~2주): 시크릿 스캔 + 의존성 audit를 CI에 추가
2단계 (1개월): SAST 도입 + 오탐 튜닝, PR 게이트화
3단계 (분기): 고위험 기능 위협 모델링 절차 수립
4단계 (반기): DAST·침투 테스트 정례화, 보안 요구사항 템플릿
5단계 (연간): SAMM/SSDF 기준 성숙도 측정과 개선 사이클
보안 수준을 어떤 기준으로 측정하고 검증할지가 다음 질문이다. 다음 글에서는 그 기준점 역할을 하는 OWASP ASVS(Application Security Verification Standard)를 다룬다.
지난 글: 공급망 보안: 의존성 하나가 시스템 전체를 위협한다
다음 글: OWASP ASVS: 애플리케이션 보안 검증 표준 활용 가이드
읽어주셔서 감사합니다. 😊