본문으로 건너뛰기
중급약 20분

SonarQube — 코드를 실행하지 않고 취약점 찾기

모듈 16 레슨 12의 ZAP·Burp Suite가 실행 중인 앱을 밖에서 공격했다면, SonarQube는 소스 코드를 읽어서 배포 전에 문제를 찾는다. Quality Gate로 머지를 막는 흐름과, QA가 그 결과를 테스트 우선순위에 쓰는 법을 익힌다.

  • #SonarQube
  • #SAST
  • #정적분석
  • #QualityGate
  • #코드품질

개념

실행하지 않는다 — 그게 가장 큰 차이다

모듈 16 레슨 12에서 OWASP ZAP과 Burp Suite로 DAST를 실행해봤다. 그 도구들은 애플리케이션을 켜놓고, 밖에서 요청을 보내며 응답을 보고 취약점을 추측했다. 서버가 떠 있어야 하고, URL이 있어야 하고, 공격이 실제로 통해야 발견된다.

SonarQube 는 정반대 방향에서 접근한다. 애플리케이션을 실행하지 않는다. 서버도 URL도 필요 없다. 대신 소스 코드 파일 자체를 읽어서 문법 구조를 분석하고, 위험한 패턴이 있는지 검사한다. 모듈 16 레슨 6에서 개념으로 배운 SAST(Static Application Security Testing)가 이것이다.

DAST (ZAP·Burp, 모듈 16 레슨 12)
  앱 실행 필요 → 밖에서 요청 전송 → 응답으로 추측
  "이 로그인 폼에 ' OR '1'='1 을 넣으니 에러가 났다"
 
SAST (SonarQube, 이 레슨)
  앱 실행 불필요 → 소스 파일을 파싱 → 코드 패턴으로 판단
  "이 파일 42번째 줄에서 사용자 입력이 SQL 문자열에
   그대로 붙고 있다"

가장 실무적인 차이는 시점 이다. 모듈 16 레슨 13의 SQLmap은 이미 배포된 서비스를 공격해서 SQL Injection을 찾아낸다 — 즉 취약한 코드가 이미 세상에 나가 있다. SonarQube는 그 코드가 머지되기도 전에 같은 문제를 잡는다. 늦게 발견할수록 수정 비용이 커진다는 원칙(모듈 1)이 여기서 그대로 적용된다.

실제로 무엇을 잡아내는가

SonarQube가 보고하는 항목은 크게 세 종류로 나뉜다.

분류뜻예시
버그(Bug)지금 당장 오작동할 수 있는 코드null 검사 없이 객체 참조, 닫히지 않는 파일 핸들
취약점(Vulnerability)보안 사고로 이어질 수 있는 코드SQL 문자열 직접 조합, 하드코딩된 비밀번호·API 키
코드 스멜(Code Smell)지금은 동작하지만 유지보수를 어렵게 하는 코드사용하지 않는 변수, 중복 코드, 지나치게 복잡한 함수

특히 QA가 눈여겨볼 항목이 두 가지 있다.

하드코딩된 비밀 — 소스에 API 키나 DB 비밀번호가 문자열로 박혀 있으면 SonarQube가 잡아낸다. 이건 DAST로는 거의 발견할 수 없는 종류다. 밖에서 요청을 보내는 것만으로는 소스에 무엇이 적혀 있는지 알 수 없기 때문이다.

함수 복잡도 — 모듈 3 레슨 10에서 배운 순환 복잡도 를 SonarQube가 함수마다 자동으로 계산해준다. "이 함수는 복잡도 24, 독립 경로가 24개"라는 숫자가 그대로 화면에 나온다. 그때는 손으로 제어 흐름 그래프를 그려 세었지만, 실무에서는 도구가 전 파일에 대해 한 번에 계산해준다.

Quality Gate — 기준 미달이면 머지를 막는다

SonarQube의 진짜 힘은 리포트가 아니라 Quality Gate 에 있다. "이 조건을 만족하지 못하면 통과시키지 않는다"는 규칙을 미리 정의해두는 장치다.

Quality Gate 예시 (새로 추가·수정된 코드 기준)
  - 신규 코드의 취약점: 0건
  - 신규 코드의 버그: 0건
  - 신규 코드 테스트 커버리지: 80% 이상
  - 중복 코드 비율: 3% 이하
→ 하나라도 어기면 PR 체크가 빨간불, 머지 버튼이 막힌다

이 흐름은 모듈 14 레슨 4에서 배운 품질 게이트 설계 와 정확히 같은 사고방식이다. CI 파이프라인이 PR마다 SonarQube 분석을 자동 실행하고, 결과가 PR 화면에 코멘트로 붙는다. 사람이 코드 리뷰를 시작하기 전에, 기계가 걸러낼 수 있는 것은 이미 걸러진 상태 가 된다. 리뷰어는 "변수명이 이상하다" 대신 설계와 로직에 집중할 수 있다.

여기서 중요한 설정이 "신규 코드 기준(New Code)"이다. 레거시가 쌓인 프로젝트에 전체 기준을 적용하면 첫날부터 수천 건이 뜨고, 팀은 곧 결과를 무시하게 된다. "기존 빚은 그대로 두되, 새로 쓰는 코드는 깨끗하게" 라는 접근이 현실적으로 정착한다.

QA가 이 결과를 왜 봐야 하는가

SonarQube는 흔히 개발자 도구로 취급되지만, QA에게는 테스트 우선순위를 정하는 지도 로 쓸모가 있다. 모듈 4 레슨 2에서 배운 리스크 기반 테스트는 "어디를 더 집중적으로 볼 것인가"를 정하는 일이었는데, SonarQube 대시보드가 그 판단 근거를 숫자로 준다.

대시보드에서 읽는 신호
  복잡도 높음 + 커버리지 낮음 → 최우선 탐색적 테스트 대상
  복잡도 높음 + 커버리지 높음 → 상대적으로 안전
  최근 변경 많음 + 이슈 다수  → 회귀 테스트 강화 구간

단, 모듈 10 레슨 5에서 배웠듯 커버리지 숫자는 품질의 증명이 아니다 . 커버리지 90%가 곧 안전을 뜻하지 않는다. 반대로 "복잡도 30인 함수의 커버리지가 12%"라는 조합은 위험 신호로 읽을 근거가 충분하다.

오픈소스 표준, 그리고 유료 확장

SonarQube는 오픈소스 정적 분석 진영의 사실상 표준이다. 무료 Community Edition 으로 시작할 수 있고, 자바스크립트·파이썬· 자바 등 주요 언어를 지원한다. 조직이 커지면 유료 에디션(Developer, Enterprise)으로 올라가면서 브랜치·PR 분석 강화, 더 깊은 보안 규칙, 포트폴리오 단위 관리가 붙는다. 모듈 16 레슨 12의 ZAP(무료) 대 Burp Suite(유료판이 실무 표준) 구도와 비슷하게, 무료로 시작해 필요할 때 확장하는 구조다.

실무에서 왜 필요한가

배포 후에 발견된 SQL Injection 한 건을 고치는 비용과, 머지 전 PR 체크에서 같은 패턴을 걸러내는 비용은 비교가 되지 않는다. SonarQube가 CI에 붙어 있으면 그 차이가 매일 자동으로 발생한다. QA 입장에서는 두 가지를 동시에 얻는다 — 명백한 코드 수준 결함이 테스트 단계에 도달하기 전에 걸러지고, 남은 코드 중 어디가 위험한지에 대한 객관적 지표가 생긴다. 감으로 "이 기능이 불안한 것 같다"고 말하는 대신 "이 모듈은 복잡도 상위 3개 함수가 몰려 있고 커버리지가 20%"라고 말할 수 있게 된다.

실습 과제

과제 1 — SAST와 DAST를 나눠 배치하기 (10분)

다음 다섯 가지 문제를 SonarQube(SAST)로 잡을 수 있는지, ZAP·SQLmap(DAST)으로 잡을 수 있는지, 아니면 둘 다인지 분류한다.

  1. 소스 코드에 운영 DB 비밀번호가 문자열로 적혀 있다
  2. 로그인 폼에서 SQL Injection이 실제로 성공한다
  3. HTTPS 대신 HTTP로 응답이 나간다
  4. 사용하지 않는 변수가 30개 있다
  5. 세션 토큰이 로그아웃 후에도 유효하다
해설 보기
  • 1번 — SAST만. 소스에 적힌 문자열은 코드를 읽어야 보인다. 외부 요청으로는 알 수 없다.
  • 2번 — 주로 DAST, 부분적으로 SAST. SonarQube는 "입력이 SQL에 그대로 붙는 패턴"을 지적할 수 있지만, 실제로 공격이 통하는지는 실행해봐야 확정된다. 그래서 SQLmap의 재현이 여전히 필요하다.
  • 3번 — DAST만. 실제 통신 프로토콜은 앱이 떠 있어야 관찰된다.
  • 4번 — SAST만. 실행 중 동작에는 영향이 없어 밖에서는 보이지 않는 코드 스멜이다.
  • 5번 — DAST만. 세션 수명은 런타임 상태라 코드 구조만으로는 판단하기 어렵다.

핵심은 두 도구가 겹치는 영역보다 겹치지 않는 영역이 훨씬 넓다 는 것이다. 하나로 다른 하나를 대체할 수 없다.

과제 2 — Quality Gate 조건 정하기 (12분)

레거시 코드가 5년치 쌓인 프로젝트에 SonarQube를 처음 도입한다. 전체 코드 기준으로 "취약점 0건"을 걸면 어떤 일이 벌어질지 적고, 그 대신 어떤 Quality Gate 조건을 제안할지 3~4개 항목으로 쓴다. 각 항목에 "왜 이 수치인가"를 한 줄씩 붙인다.

과제 3 — 대시보드로 테스트 우선순위 정하기 (10분)

아래 SonarQube 요약을 보고, 탐색적 테스트를 어느 순서로 배치할지 정하고 근거를 적는다.

모듈최고 순환 복잡도커버리지최근 30일 변경
결제3118%많음
알림876%적음
회원2271%많음

자가 체크리스트

  • SonarQube가 SAST이고 ZAP·Burp가 DAST라는 차이를 "코드를 실행하는가"로 설명할 수 있다
  • SQLmap이 배포 후 공격으로 찾는 문제를 SonarQube가 배포 전에 찾는다는 시점 차이를 설명할 수 있다
  • 버그·취약점·코드 스멜 세 분류의 차이를 예시와 함께 말할 수 있다
  • Quality Gate가 무엇이고, PR 체크에서 어떻게 머지를 막는지 설명할 수 있다
  • 레거시 프로젝트에 "신규 코드 기준"을 적용하는 이유를 설명할 수 있다
  • 복잡도와 커버리지 조합을 리스크 기반 테스트 우선순위로 번역할 수 있다

흔한 실수

  • SonarQube를 돌렸으니 보안 점검이 끝났다고 여긴다. 정적 분석은 런타임 문제(세션 관리, 인증 우회, 설정 오류)를 거의 보지 못한다. 모듈 16 레슨 12의 DAST와 반드시 함께 써야 한다.
  • 모든 경고를 실제 결함으로 단정한다. SAST도 오탐이 난다. 레슨 12에서 스캐너 결과를 검증 없이 전달하지 말라고 배운 원칙이 여기서도 같다 — 코드 맥락을 보고 판단해야 한다.
  • 첫 도입부터 전체 코드에 엄격한 기준을 건다. 수천 건이 한꺼번에 뜨면 팀 전체가 결과를 무시하게 되고, 도구는 곧 꺼진다.
  • 커버리지 숫자만 보고 안심한다. 모듈 10 레슨 5의 함정 그대로다. 커버리지는 "실행된 줄의 비율"일 뿐 검증의 질을 뜻하지 않는다.
  • QA가 "개발자 도구"라며 대시보드를 아예 안 본다. 테스트 우선순위 판단에 쓸 수 있는 가장 값싼 객관적 지표를 버리는 셈이다.

참고 자료

낯선 말 풀이

이 레슨에 나온 약어입니다. 본문에서도 처음 나올 때 점선으로 표시해 두었습니다 (제목과 링크 글자는 그대로 둡니다).

OWASP — 오왁스프
웹과 앱 보안 자료를 공개로 만드는 비영리 단체. 취약점 목록과 점검 기준이 유명하다.
ZAP — 제드 어택 프록시
웹 취약점을 자동으로 훑어 주는 공개 도구.
DAST — 동적 보안 분석
실제로 돌아가는 서비스에 요청을 보내 보며 취약점을 찾는 검사.
URL — 인터넷 주소
웹에서 무언가의 위치를 가리키는 주소 한 줄.
SAST — 정적 보안 분석
프로그램을 돌리지 않고 코드 자체를 읽어 위험한 부분을 찾는 검사.
SQL — 구조화 질의 언어
저장소에 "이런 조건인 줄을 보여 달라"고 묻는 말. 영어 문장에 가까워서 읽기가 비교적 쉽다.
API — 응용 프로그램 인터페이스
프로그램끼리 주고받는 창구. 사람이 화면 버튼을 누르는 대신, 프로그램이 정해진 주소로 요청을 보내 답을 받는다.
QA — 품질보증
만든 것이 쓸 만한지 확인하고, 애초에 덜 망가지게 만드는 방법을 정하는 일. "테스트"는 그 일의 일부다.
DB — 데이터베이스
데이터를 넣어 두고 꺼내 쓰는 저장소. 보통 표 여러 개가 서로 연결된 형태다.
CI — 지속적 통합
코드를 올릴 때마다 자동으로 합쳐서 빌드하고 시험까지 돌리는 방식.
PR — 풀 리퀘스트
"내가 고친 코드를 본체에 합쳐 달라"고 올리는 요청. 합치기 전에 사람들이 보고 의견을 단다.
HTTPS — 암호화된 웹 전송
웹 통신을 암호로 감싼 것. 중간에서 누가 들여다봐도 내용을 못 읽는다.

이 레슨에 나온 나머지 1개를 포함해 용어집 전체 보기

이 레슨의 실습

실습은 별도 저장소에서 진행합니다. 새 탭으로 열립니다.