사전 취약점
개념

취약점

gabury1고친 사람 github-actions[bot]

취약점은 공격자가 시스템을 만든 사람의 뜻과 다르게 부릴 수 있게 해 주는 틈입니다. 주소창 숫자 하나로 남의 주문 내역을 열어 주는 화면이 그런 틈입니다. 모든 버그가 취약점은 아닙니다. 공격자가 일부러 밟아서 이득을 보는 버그만 이 이름으로 부릅니다.

쉽고 빠른 이해

취약점은 누가 무엇을 해도 되는지에 대한 약속을 공격자가 어기게 해 주는 결함입니다. 주문 번호만 바꾸면 남의 주문이 보이는 조회 기능이 그 예입니다.

모든 버그가 취약점은 아닙니다. 세 가지가 함께 서야 취약점입니다. 코드에 결함이 있고, 공격자가 그 결함에 닿고, 밟으면 볼·바꿀·쓸 권한이 깨져야 합니다. 하나라도 빠지면 보통 버그로 둡니다.

이름을 따로 두는 까닭은 다루는 법이 달라서입니다. 보통 버그처럼 공개 게시판에 올리면 고치기 전에 공격자가 먼저 읽습니다. 그래서 조용히 고칩니다. 고친 버전과 알림은 함께 내보냅니다.

하나가 생겨서 닫히기까지는 이렇게 흘러갑니다.

  1. 코드나 설정에 틈이 생깁니다
  2. 누군가 찾아내 만든 쪽에 몰래 알립니다
  3. 만든 쪽이 고친 버전을 내고 번호를 붙여 공개합니다
  4. 쓰는 쪽이 고친 버전으로 올립니다

일하면서 만나는 취약점은 대개 경고로 옵니다. 쓰는 라이브러리를 검사하는 도구가 알려진 취약점이 든 버전을 찾아 경고를 쏟아냅니다. 그중 공격자가 닿는 것만 우리 서비스의 취약점입니다. 닿지 않는 것을 가려내는 일은 사람 몫입니다.

상세

사무실 출입문이 사원증을 대야 열린다고 해 봅시다. 그런데 문틈에 종이 한 장을 끼워 두면 걸쇠가 안 걸립니다. 문을 단 사람은 사원증이 있는 사람만 들이려 했습니다. 종이 한 장이면 아무나 들어옵니다.

취약점은 시스템이 지키기로 한 보안 규칙을 공격자가 어길 수 있게 만드는 결함입니다. 보안 규칙은 누가 무엇을 읽고, 바꾸고, 실행해도 되는지에 대한 약속입니다. 「로그인한 사람은 자기 주문만 본다」가 그런 규칙 하나입니다.

이 절은 쇼핑몰의 주문 조회 기능 하나를 예로 씁니다. 버그가 언제 취약점이 되는지, 밟히면 무엇이 깨지는지, 어디서 생기는지를 봅니다. 그다음 취약점 하나가 발견되어 닫히기까지의 흐름과, 백엔드 개발자가 취약점을 만나는 곳을 봅니다.

주문 조회 기능 하나

쇼핑몰 서버에 주문 번호를 받아 그 주문을 돌려주는 API(Application Programming Interface, 다른 프로그램이 부르도록 열어 둔 기능)가 있습니다. 로그인한 사용자가 아래처럼 부릅니다. 오른쪽 주석은 서버가 돌려준 결과입니다.

GET /orders/1042   // 내 주문 → 200
GET /orders/1043   // 남의 주문 → 200

200 은 요청이 성공했다는 응답 번호입니다. 첫 줄은 기대한 대로입니다. 둘째 줄이 문제입니다. 번호를 하나 올렸을 뿐인데 남의 이름과 주소가 담긴 주문이 돌아옵니다.

원인은 서버 코드에서 확인 하나가 빠진 것입니다. 주문을 돌려주기 전에 요청한 사람이 그 주문의 주인인지 봤어야 합니다. 아래가 빠져 있던 확인입니다.

Java
Order o = orders.findById(orderId);
if (!o.ownerId().equals(loginUserId)) {
    throw new ForbiddenException(); // 403
}
return o;

주인이 아니면 403 을 돌려줍니다. 403 은 권한이 없어 거절했다는 응답 번호입니다. 누가 무엇에 손댈 수 있는지를 따지는 이 확인을 접근 제어라고 부릅니다.

버그가 취약점이 되는 세 조건

같은 버그라도 늘 취약점인 것은 아닙니다. 버그가 취약점이 되려면 세 가지가 함께 서야 합니다. 주문 조회에 대 보면 이렇습니다.

조건 주문 조회에서는
결함이 있다 주인 확인이 빠졌다
공격자가 그 결함에 닿는다 로그인만 하면 누구나 부를 수 있다
밟으면 보안 규칙이 깨진다 남의 이름과 주소가 나온다

하나라도 빠지면 버그일 뿐입니다. 같은 확인 누락이 사내망 안에서 운영자만 부르는 기능에 있었다면 바깥 공격자는 닿지 못합니다. 결함이 화면 글자가 조금 어긋나는 것이었다면 밟아도 얻는 것이 없습니다.

둘째 조건은 따로 이름이 있을 만큼 자주 따집니다. 바깥에서 시스템을 건드릴 수 있는 지점을 모두 모은 것을 공격 표면이라고 부릅니다. 결함이 이 표면 안에 있느냐가 둘째 조건입니다.

밟히면 깨지는 것

셋째 조건의 「보안 규칙이 깨진다」는 대개 셋 중 하나를 가리킵니다. 보안이 지키려는 성질 셋입니다.

깨지는 성질 지키려는 것 깨진 예
기밀성 볼 권한이 있는 사람만 본다 남의 주문을 읽는다
무결성 바꿀 권한이 있는 사람만 바꾼다 남의 주문 배송지를 바꾼다
가용성 써야 할 사람이 쓸 수 있다 요청 하나로 서버를 멈춘다

주문 조회의 결함은 첫째 줄을 깹니다. 같은 확인이 주문 수정 기능에서 빠졌다면 둘째 줄까지 깹니다.

무게가 가장 큰 것은 공격자가 보낸 코드를 서버가 실행하는 경우입니다. 이것을 원격 코드 실행이라고 부릅니다. 서버를 공격자 손에 넘기는 것이라 세 성질이 한꺼번에 깨집니다.

취약점이 생기는 세 곳

결함이 어디서 생겼느냐에 따라 고치는 방법이 달라집니다. 흔히 셋으로 나눕니다.

생긴 곳 예 고치는 방법
설계 비밀번호 재설정 링크가 만료되지 않는다 흐름을 다시 짠다
구현 사용자 입력을 데이터베이스 질의문에 이어 붙인다 그 코드를 고친다
설정 관리 화면이 처음 깔린 비밀번호로 열려 있다 설정을 바꾼다

설계에서 생긴 것은 코드를 아무리 꼼꼼히 짜도 남습니다. 흐름 자체가 공격자에게 길을 내주기 때문입니다.

구현 줄의 결함은 이름이 붙어 있습니다. 질의문은 SQL(Structured Query Language, 구조화 질의 언어)로 적습니다. 여기에 입력을 이어 붙이면 입력한 글자가 데이터가 아니라 명령으로 실행됩니다. 이 결함을 SQL 인젝션이라고 부릅니다.

우리가 짠 코드만 따질 일도 아닙니다. 가져다 쓴 라이브러리에 난 취약점은 그 라이브러리를 부르는 우리 서비스의 취약점이 됩니다. 서버 하나가 기대는 라이브러리는 직접 고른 것보다 그것들이 다시 끌어오는 것이 더 많습니다.

약점과 취약점과 익스플로잇

취약점 둘레에는 비슷해 보이는 말이 둘 더 있습니다. 보안 공지와 검사 결과에 나란히 나오므로 먼저 갈라 둡니다.

말 가리키는 것 주문 조회에서는
약점 코드가 잘못 짜이는 꼴 조회 전에 주인 확인을 빠뜨린 코드 꼴
취약점 그 꼴로 짜인 어느 제품의 실물 이 쇼핑몰의 주문 조회 기능
익스플로잇 취약점을 밟는 코드나 절차 번호를 하나씩 올려 가며 부르는 스크립트

약점과 취약점은 번호를 매기는 목록도 따로 있습니다. CWE(Common Weakness Enumeration, 공통 약점 목록)는 약점의 꼴마다 번호를 붙입니다.

CVE(Common Vulnerabilities and Exposures, 공통 취약점 및 노출)는 제품에 난 실물 취약점마다 번호를 붙입니다.

공격 코드가 이미 돌아다니느냐가 급한 정도를 가릅니다. 누구나 돌릴 수 있는 익스플로잇이 퍼져 있으면, 취약점을 이해하지 못한 사람도 공격할 수 있게 됩니다.

발견에서 적용까지

취약점 하나는 몇 단계를 거쳐 닫힙니다. 단계가 넘어갈 때마다 그 취약점을 아는 사람이 달라집니다. 그림의 제로데이는 만든 쪽이 모르는 채로 공격에 쓰이는 취약점입니다.

stateDiagram-v2
    숨어있음: 숨어 있음 · 아무도 모른다
    발견됨: 발견됨 · 찾은 사람과 만든 쪽만 안다
    제로데이: 제로데이 · 공격자가 먼저 쓴다
    고친버전: 고친 버전 · 번호와 공지가 함께 나간다
    적용됨: 적용됨 · 우리 서버가 고친 버전을 쓴다
    [*] --> 숨어있음
    숨어있음 --> 발견됨: 연구자가 찾는다
    숨어있음 --> 제로데이: 공격자가 먼저 찾는다
    발견됨 --> 고친버전: 만든 쪽이 고친다
    제로데이 --> 고친버전: 공격이 드러나 고친다
    고친버전 --> 적용됨: 쓰는 쪽이 올린다

처음에는 숨어 있습니다. 코드가 배포된 날부터 틈은 있었지만 아무도 모르는 상태입니다.

보안 연구자나 사용자가 먼저 찾으면 발견됨으로 넘어갑니다. 찾은 사람은 만든 쪽에만 조용히 알립니다. 고친 버전이 나오기 전에 세상에 알려지면 공격자가 먼저 쓰기 때문입니다. 이 순서를 지키는 관행을 책임 있는 공개라고 부릅니다.

만든 쪽은 고친 버전, 곧 패치를 냅니다. 옛 버전을 쓰던 곳은 패치로 올려야 틈이 닫힙니다.

패치와 함께 보안 공지도 냅니다. 어떤 취약점이 났고 어느 버전이 영향을 받는지 알리는 글이며, CVE 번호가 함께 실립니다. 영향을 받는 버전을 흔히 「걸리는 버전」이라고 줄여 말합니다.

공격자가 먼저 찾으면 제로데이로 길이 갈립니다. 이름은 만든 쪽이 알고 나서 고칠 시간이 0일이었다는 뜻입니다. 이런 취약점은 공격이 드러난 뒤에야 고친 버전이 나옵니다.

그림에서 공격이 몰리는 구간은 고친 버전이 나온 뒤 우리 서버에 적용되기 전입니다. 공지가 나가면 공격자도 어느 버전이 걸리는지 압니다. 고친 코드와 옛 코드를 견주면 틈이 어디 있는지도 드러납니다. 그래서 공지가 나오면 서둘러 올립니다.

급한 정도를 가리는 법

공개된 취약점에는 흔히 CVSS(Common Vulnerability Scoring System, 공통 취약점 점수 체계) 점수가 붙습니다. 공격하기가 얼마나 쉽고 깨지는 것이 얼마나 큰지를 한 숫자로 묶은 값입니다.

이 점수는 취약점 자체의 무게입니다. 우리 서비스에서의 무게는 따로 따집니다. 앞에서 본 세 조건이 그 잣대입니다. 걸리는 버전의 라이브러리를 쓰더라도 틈이 난 기능을 안 부르면 공격자는 닿지 못합니다.

반대 경우도 있습니다. 점수가 낮아도 로그인 없이 바깥에서 닿고 고객 데이터를 내준다면 먼저 고칩니다. 일어날 가능성과 일어났을 때의 피해를 함께 따진 값을 리스크라고 부릅니다. 고칠 순서를 정할 때는 점수와 함께 이 값을 봅니다.

백엔드 개발자가 취약점을 만나는 곳

백엔드 개발자가 취약점을 처음 보는 곳은 대개 경고 한 줄입니다. 경고가 어디서 왔느냐에 따라 할 일이 다릅니다.

경고가 온 곳 알려 주는 것 할 일
의존성 스캔 쓰는 라이브러리 버전에 알려진 취약점이 있다 고친 버전으로 올린다
정적 분석 우리 코드에 약점 꼴이 보인다 그 줄을 고친다
침투 테스트 사람이 뚫어 본 결과가 있다 재현해 보고 고친다
보안 공지 쓰는 제품에 새 취약점이 났다 우리가 쓰는 버전이 걸리는지 본다

표의 첫 줄은 빌드 때 도구가 라이브러리의 이름과 버전을 읽어 알려진 취약점과 맞춰 보는 검사입니다. 가장 자주 만나는 경고가 여기서 옵니다.

둘째 줄의 정적 분석은 코드를 실행하지 않고 읽기만 해서 흔한 약점 꼴을 찾는 도구입니다. 실행하지 않으므로 빌드 때마다 돌릴 수 있습니다.

셋째 줄의 침투 테스트는 허락을 받고 공격자처럼 뚫어 보는 점검입니다. 도구가 짚지 못하는 설계의 틈을 사람이 찾아낸다는 점이 다릅니다.

의존성 스캔이 내는 경고는 많습니다. 경고마다 세 조건을 따져 보면, 우리 코드가 부르지 않는 기능에 난 것이 적지 않습니다. 그걸 가려내는 일은 도구가 대신해 주지 않습니다.

취약점으로 다룰 때 바뀌는 것

어떤 결함을 취약점으로 부르면 다루는 법이 바뀝니다. 보통 버그는 공개 이슈 게시판에 올립니다. 고치는 과정도 누구나 봅니다.

취약점은 고친 버전이 나올 때까지 아는 사람을 좁힙니다. 이슈를 비공개로 돌립니다. 고친 버전과 공지는 같은 날 냅니다.

그래서 세 조건으로 먼저 가립니다. 셋이 다 서면 취약점으로 다룹니다. 하나가 빠지면 보통 버그로 다룹니다. 모든 버그를 취약점처럼 다루면 비공개 이슈가 쌓여 급한 것이 묻힙니다. 반대로 취약점을 보통 버그로 다루면 고치기 전에 틈의 위치가 공개됩니다.

관련 항목

취약점과 헷갈리는 이웃 용어

약점 · 버그 · 결함 · 익스플로잇 · 위협 · 리스크 · 공격 벡터 · 공격 표면

취약점이 깨뜨리는 보안 성질

기밀성 · 무결성 · 가용성 · CIA 3요소 · 부인 방지

취약점의 하위 종류

접근 제어 · SQL 인젝션 · 교차 사이트 스크립팅 · 크로스 사이트 요청 위조 · 서버 사이드 요청 위조 · 버퍼 오버플로 · 사용 후 해제 · 경쟁 상태 · 안전하지 않은 역직렬화 · 경로 조작

취약점을 밟아 공격자가 얻는 결과

권한 상승 · 원격 코드 실행 · 정보 유출 · 서비스 거부 · 계정 탈취

취약점에 번호와 점수를 매기는 목록

CVE · CWE · CVSS · NVD · EPSS · CISA KEV · OWASP Top 10

취약점 목록을 펴내고 알리는 기관

MITRE · CISA · NIST · FIRST · OWASP

취약점을 찾아내는 활동과 도구

의존성 스캔 · 소프트웨어 구성 분석 · 정적 분석 · 동적 분석 · 퍼징 · 침투 테스트 · 버그 바운티 · 취약점 스캐너 · 보안 코드 리뷰

발견된 취약점이 거치는 대응 단계

책임 있는 공개 · 제로데이 · 패치 · 보안 공지 · 패치 관리 · 취약점 관리 · 사고 대응

취약점이 덜 생기게 하는 원칙

위협 모델링 · 입력 검증 · 최소 권한 · 심층 방어 · 시큐어 코딩 · 기본 차단 · 보안 엔지니어링

이름이 붙을 만큼 널리 퍼진 취약점

Log4Shell · Heartbleed · Shellshock · Spectre · Meltdown

다른 이름: vulnerability · 보안 취약점 · 보안 결함