SAST 스캔
코드를 작성하면서 보안 취약점을 미리 발견하고 싶으신가요? SAST(Static Application Security Testing)는 소스 코드를 실행하지 않고 정적으로 분석하여 보안 취약점을 탐지하는 기술입니다. 마치 코드 리뷰어가 보안 관점에서 코드를 검토하는 것과 같습니다.
보안 취약점은 개발 초기에 발견할수록 수정 비용이 낮습니다. SAST를 CI/CD 파이프라인에 통합하면 코드가 커밋될 때마다 자동으로 보안 점검이 이루어져, 취약점이 프로덕션까지 도달하는 것을 방지할 수 있습니다.

개요
- 분석 대상: Git 저장소의 소스 코드
- 분석 엔진: Semgrep + OpenGrep (순차 실행, 사용자 선택 UI 없음)
- 결과 통합: 두 도구의 탐지 결과를 합집합으로 통합 제공
- SBOM/라이선스: SAST 부산물이 아닌 독립적으로 생성됩니다 (SBOM 생성 참조)
KIOPS의 SAST는 Semgrep(기본)을 먼저 실행하고, Semgrep이 성공하면 OpenGrep(확장 룰셋 고도화)을 이어서 실행하여 두 도구의 결과를 합집합으로 통합합니다. UI에서 도구를 선택하는 토글은 제공되지 않습니다.
분석 엔진 (참고)
KIOPS는 두 가지 SAST 엔진을 순차적으로 실행합니다.
Semgrep
경량 정적 분석 도구로, 패턴 기반의 빠른 분석을 제공합니다.
- 분석 방식: 패턴 매칭 - 정의된 패턴과 일치하는 코드를 탐지
- 분석 기준: OWASP Top-10 기반 보안 룰셋
- 역할: SAST의 기본 엔진
OpenGrep
확장 룰셋으로 탐지 범위를 넓히는 고도화 엔진입니다.
- 분석 방식: Semgrep 호환 룰 엔진으로 확장 보안 감사 룰셋 적용
- 분석 기준: CWE Top-25 및 보안 감사 룰셋
- 역할: 기본 룰셋이 놓치는 항목을 추가로 탐지
OWASP(Open Web Application Security Project)에서 발표하는 웹 애플리케이션의 10대 보안 취약점 목록입니다. SQL Injection, XSS, 인증 취약점 등 가장 흔하고 위험한 취약점들이 포함되어 있습니다.
Step 1: SAST 스캔 시작하기
- 사이드바의 "보안" 그룹 > [보안 분석] 메뉴를 클릭합니다.
- 페이지 상단의 카드 캐러셀에서 분석할 서비스를 선택합니다.
- SAST 탭을 선택합니다.
- 상단 트리거 바에서 스캔 시작 버튼을 클릭합니다.
/security?id={서비스ID}&area=sast URL로 진입하면 해당 서비스의 SAST 탭이 바로 열립니다.
Step 2: 스캔 입력 항목
SAST 스캔 트리거 바에서는 다음 항목을 사용합니다.
- Git 저장소 URL (필수): 분석할 저장소 URL
- 브랜치 (선택, 기본
main): 분석할 브랜치명 - Git 토큰 (선택, Private Repo용): 저장소 읽기 권한이 있는 토큰
Git URL, 브랜치, 토큰은 설정 탭에서 SAST/IaC/시크릿 공통으로 등록할 수 있습니다. 설정 탭에 등록해두면 SAST 스캔 시 자동으로 사용됩니다.
Git 토큰을 직접 입력하지 않으면, 백엔드는 기관/조직 설정에 저장된 토큰을 자동으로 사용합니다. 별도의 토큰 등록 없이 곧바로 스캔을 시작할 수 있는 경우가 많습니다.
Step 3: 순차 분석 흐름
스캔이 시작되면 Semgrep이 먼저 실행되고, Semgrep이 성공하면 이어서 OpenGrep이 실행됩니다. Semgrep은 기본 OWASP Top-10 룰셋을 적용하고, OpenGrep은 확장 룰셋(Security Audit, CWE Top-25, Secrets)을 적용합니다. 동일한 엔진을 사용하지만 서로 다른 룰셋을 적용하므로 자연스럽게 교차 검증이 이루어집니다. 두 도구 모두 WebSocket을 통해 진행률을 독립적으로 보고하므로 진행 표시는 마치 함께 진행되는 것처럼 보이지만, 실제 실행은 순차적입니다. 두 도구의 결과는 합집합으로 통합되어 하나의 결과 화면에 표시됩니다.
저장소 Clone
│
▼
Semgrep (기본 보안 룰셋)
Rule 로드 → 파일 스캔
│
▼ (Semgrep 성공 시)
OpenGrep (확장 룰셋 고도화)
Rule 로드 → 파일 스캔
│
▼
결과 합집합 통합
분석 상태
- Idle: 분석 대기 중
- Analyzing: 분석 진행 중 (WebSocket 진행률 확인 가능)
- Completed: 분석 완료 (결과 확인 가능)
- Failed: 분석 실패 (오류 메시지 확인 필요)
중요: SBOM과 라이선스는 더 이상 SAST 부산물로 생성되지 않습니다. SBOM / 라이선스 탭의 독립 스캔(Syft + ScanCode)을 통해서만 생성되며, SAST와 무관하게 언제든지 실행할 수 있습니다. 자세한 내용은 SBOM 생성 문서를 참조하세요.
Step 4: 결과 확인
분석이 완료되면 결과 화면에서 발견된 취약점을 확인할 수 있습니다.
4.1 결과 요약
- 총 발견 수: 탐지된 취약점의 총 개수
- 심각도별 분류: Critical/High/Medium/Low로 분류된 취약점 수
- 탐지 도구: 각 항목이 Semgrep, OpenGrep, 또는 두 도구가 함께 탐지(교차검증)했는지 표시
4.2 카테고리별 결과 보기
각 취약점은 다음 상태로 분류 및 처리할 수 있습니다.
- open: 새로 발견된 미처리 항목
- resolved: 수정 완료
- false_positive: 오탐으로 확인됨
- accepted_risk: 위험 수용
각 취약점 항목에는 어떤 도구가 탐지했는지 표시됩니다.
- 교차 검증: Semgrep과 OpenGrep 두 도구가 모두 탐지(신뢰도 높음)
- 단일 도구: 한 도구만 탐지(예: "Semgrep만", "OpenGrep만")
어떤 도구가 각 결과를 찾았는지 항상 확인할 수 있어, 보안 분석 워크플로우에서 출처 추적이 가능합니다.
4.3 취약점 상세
각 취약점을 클릭하면 다음 정보를 확인할 수 있습니다.
- 파일 위치: 취약점이 발견된 파일 경로와 라인 번호
- 취약점 유형: SQL Injection, XSS, Command Injection 등
- 심각도: Critical/High/Medium/Low
- 설명: 이 취약점이 왜 위험한지에 대한 상세 설명
- CWE ID: 표준 취약점 분류 식별자 (예: CWE-89는 SQL Injection)
모든 취약점을 한 번에 수정하기 어렵다면, Critical과 High 심각도부터 수정하세요. 특히 인증/인가 관련 취약점과 인젝션 취약점은 최우선으로 해결해야 합니다.
4.4 스캔 이력 및 버전 추적
스캔 이력 테이블 — 최근 SAST 스캔을 시간순으로 확인할 수 있습니다.
- 스캔 시각: 스캔이 실행된 시점(최신순 정렬)
- 브랜치: 스캔한 브랜치명
- 커밋: 스캔 대상의 Git 커밋 SHA(앞 7자 표시, 마우스를 올리면 전체 SHA 확인)
- 등급: 보안 점수 기반 등급(A~F)
- 심각도별 개수: Critical/High/Medium/Low 취약점 수
- 총 취약점 수: 전체 심각도 합계(이전 스캔 대비 증감 화살표 표시)
- 보는 중: 선택된 행을 강조 표시
행 선택 — 과거 스캔 결과 보기: 스캔 이력 테이블의 행을 클릭하면 아래 결과 영역이 해당 시점의 결과로 전환됩니다. 선택된 행에는 "보는 중" 라벨이 표시됩니다. 과거 스캔을 보고 있을 때는 결과 영역 상단에 "과거 스캔 결과를 보고 있습니다" 배너가 나타나며, 이 배너의 "최신 스캔으로" 버튼을 클릭하면 최신 스캔 결과로 되돌아갑니다. (이력 테이블에는 별도의 돌아가기 버튼이 없습니다.)
배포된 버전 추적(Outdated 신호): 스캔한 커밋이 실제 배포된 버전 커밋과 다르면, 보안 개요 화면의 SAST 항목 이름 옆에 "outdated" 태그가 표시됩니다. 태그에 마우스를 올리면 분석한 커밋과 현재 배포된 커밋이 다르다는 안내가 나타나, 결과가 옛 코드 기준일 수 있음을 경고합니다. 최신 코드 버전으로 스캔하는 것을 권장합니다.
주요 탐지 취약점 유형
SAST가 탐지하는 대표적인 취약점 유형을 알아두면 코드 작성 시 미리 예방할 수 있습니다.
인젝션 (Injection)
외부 입력이 그대로 쿼리나 명령어에 사용되면 발생합니다.
-
SQL Injection (CWE-89): 사용자 입력이 SQL 쿼리에 직접 삽입되는 경우
// 취약한 코드
String query = "SELECT * FROM users WHERE id = " + userId;
// 안전한 코드
PreparedStatement stmt = conn.prepareStatement("SELECT * FROM users WHERE id = ?");
stmt.setString(1, userId); -
Command Injection (CWE-78): 사용자 입력이 OS 명령어에 사용되는 경우
-
LDAP Injection (CWE-90): 사용자 입력이 LDAP 쿼리에 삽입되는 경우
인증/인가 (Auth)
- Broken Authentication (CWE-287): 인증을 우회할 수 있는 결함
- Hardcoded Credentials (CWE-798): 소스 코드에 비밀번호나 API 키가 하드코딩됨
- Insufficient Authorization (CWE-285): 권한 검사가 불충분함
소스 코드에 비밀번호, API 키, 토큰 등을 직접 작성하지 마세요. 환경 변수나 시크릿 관리 도구를 사용하세요. 노출된 자격증명은 시크릿 스캔으로도 탐지할 수 있습니다.
데이터 노출 (Exposure)
- XSS (CWE-79): 웹 페이지에 악성 스크립트가 삽입될 수 있음
- Sensitive Data Exposure (CWE-200): 로그나 에러 메시지에 민감정보 노출
- Path Traversal (CWE-22):
../를 사용해 의도하지 않은 파일에 접근 가능
심각도 분류
SAST는 Semgrep과 OpenGrep의 SARIF 결과에서 다음 순서로 심각도를 결정합니다.
- properties.severity (우선): 탐지 결과에 명시된 심각도(critical/high/medium/low)
- rule.level 폴백 (properties.severity가 없을 때):
error→ Criticalwarning→ Highnote→ Medium- (그 외) → Medium (기본값)
2026-06-01에 일관성 확보를 위해 SAST 심각도 로직이 AST와 통일되었습니다. 이전에는 properties.severity를 무시하고 rule.level만 참조하여, 동일 항목이 AST와 KIOPS에서 서로 다른 심각도로 표시되는 경우가 있었습니다.
문제 해결
분석 실패
분석이 실패했다면 다음을 확인해보세요.
-
지원하지 않는 언어: Semgrep과 OpenGrep은 룰셋이 정의된 언어를 탐지합니다. 특수한 언어나 폐쇄적인 형식의 코드는 결과가 비어 있을 수 있습니다.
-
코드 접근 불가: Git 토큰에 저장소 읽기 권한이 있는지 확인하세요. 토큰을 직접 입력하지 않은 경우 설정 탭이나 기관 설정의 저장된 토큰이 자동으로 사용됩니다. 두 토큰이 모두 만료/없음 상태이면 분석이 실패합니다.
-
타임아웃: 대용량 저장소의 경우 분석 시간이 오래 걸릴 수 있습니다. 분석 범위를 특정 브랜치로 제한하세요.
오탐(False Positive) 처리
SAST는 때때로 실제로는 취약하지 않은 코드를 취약점으로 보고할 수 있습니다. 해당 항목을 false_positive 또는 accepted_risk 상태로 변경하면 이후 스캔에서 동일 항목이 자동 분류됩니다.
오탐이 너무 많으면 개발자들이 SAST 결과를 무시하게 됩니다. 확인된 오탐은 적극적으로 false_positive 처리하여, 진짜 취약점에 집중할 수 있도록 관리하세요.