코드 안전성·인증·인가·세션 통제
경계·정수·널 참조·해제 후 사용·자원 누수와 경쟁 상태의 차이를 정리한다. 인증·인가·MFA를 구분하고 서버의 객체별 권한 검사, 세션 고정·탈취 방어, 갱신·만료·무효화의 원리를 이해한다.
핵심 요약
코드 안전성은 입력뿐 아니라 메모리 경계·계산·객체 수명·자원·동시 실행을 올바르게 다루는 문제다. 인증은 주체가 누구인지 확인하고, 인가는 그 주체가 무엇을 할 수 있는지 결정한다. 세션은 인증 이후의 요청을 사용자 상태와 연결하므로 생성·사용·변경·종료를 안전하게 관리해야 한다.
1. 경계와 정수 계산 오류
버퍼 오버플로는 허용된 저장 영역을 넘어 데이터를 기록하는 문제다. 인접 데이터 손상, 프로그램 중단, 보안 통제 우회 등으로 이어질 수 있다. 경계 밖 읽기는 메모리의 민감한 내용을 노출할 수 있다.
배열의 유효 인덱스, 입력 길이와 버퍼 용량, 문자열 종료 문자에 필요한 공간을 확인한다. 오프바이원(Off-by-one)은 반복이나 경계 조건이 한 칸 어긋나는 오류다. 길이가 n인 배열의 인덱스가 0부터 시작한다면 마지막 유효 인덱스는 n−1이다.
정수 오버플로·언더플로는 계산 결과가 표현 범위를 벗어나는 문제다. 특히 요소 개수 × 요소 크기로 메모리 크기를 구할 때 계산이 넘치면 실제 필요한 크기보다 작은 공간을 할당할 수 있다. 계산 이후 값만 확인하는 것보다 계산 전 허용 범위와 자료형을 확인해야 한다.
부호 있는 값과 없는 값을 섞어 비교하거나 더 작은 자료형으로 변환할 때도 의미가 달라질 수 있다. 언어·자료형에 따라 오류 처리와 결과가 다르므로 모든 오버플로가 같은 방식으로 순환한다고 단정하지 않는다.
2. 객체 수명과 자원 관리
| 약점 | 원인·의미 | 기본 대응 |
|---|---|---|
| 널 포인터 역참조 | 유효 객체가 없는 참조 사용 | 반환·초기화 상태 확인 |
| 초기화되지 않은 값 사용 | 정의되지 않은 상태에 의존 | 사용 전 명확한 초기화 |
| 해제 후 사용(UAF) | 수명이 끝난 메모리·객체를 다시 사용 | 소유권·수명 관리 |
| 이중 해제 | 같은 자원을 중복 해제 | 해제 책임과 경로 일관화 |
| 메모리·자원 누수 | 더 이상 필요 없는 자원을 반환하지 않음 | 정상·오류 경로 모두에서 정리 |
메모리뿐 아니라 파일, 소켓, DB 연결, 잠금도 자원이다. 반복 요청에서 연결을 반환하지 않으면 정상 사용자도 서비스를 사용할 수 없게 된다.
오류 발생 시 정리 코드가 생략되지 않도록 언어가 제공하는 안전한 자원 관리 기능을 사용한다. 메모리 관리가 자동인 언어에서도 파일·연결·공유 상태 등의 오류가 사라지는 것은 아니다.
3. 시간·상태와 경쟁 상태
경쟁 상태(Race Condition)는 여러 작업의 실행 순서나 시점에 따라 결과가 달라지는 문제다. TOCTOU는 검사한 시점과 실제 사용하는 시점 사이에 상태가 바뀌는 경쟁 상태다.
예를 들어 두 요청이 동시에 잔여 좌석 1개를 확인한 뒤 각각 예약하면 모두 성공하여 초과 예약이 발생할 수 있다. 검사와 상태 변경이 필요한 범위에서 원자적으로 이루어지도록 잠금·원자 연산·트랜잭션 등을 사용해야 한다.
| 개념 | 특징 |
|---|---|
| 경쟁 상태 | 실행 순서에 따라 결과가 달라짐 |
| TOCTOU | 검사한 상태가 사용 시점에 바뀜 |
| 교착 상태 | 서로 필요한 자원을 기다리며 진행하지 못함 |
| 라이브락 | 상태 변화·재시도는 있지만 유효한 진행이 없음 |
잠금을 추가하면 모든 동시성 문제가 해결되는 것도 아니다. 잠금 순서와 해제 경로가 잘못되면 교착과 서비스 지연을 만들 수 있다.

4. 식별·인증·인가
| 개념 | 질문 | 예 |
|---|---|---|
| 식별 | 누구라고 주장하는가? | 사용자 ID 제시 |
| 인증 | 주장한 주체가 맞는가? | 비밀번호·보안키 검증 |
| 인가 | 해당 행위를 허용할 것인가? | 본인 지원서만 수정 허용 |
| 책임추적 | 누가 무엇을 했는지 확인할 수 있는가? | 중요 변경의 감사 로그 |
인증 요소는 지식(비밀번호), 소지(보안키·등록된 장치 등), 생체(지문 등)로 구분한다. 서로 다른 유형을 결합하는 것이 다중 요소 인증(MFA)의 핵심이다. 비밀번호와 보안 질문은 둘 다 지식 요소이므로 절차가 두 번이라는 이유만으로 MFA가 되지 않는다.
무차별 대입은 다양한 후보를 반복 시도하고, 자격 증명 대입(Credential Stuffing)은 유출된 ID·비밀번호 조합을 다른 서비스에 재사용하며, 비밀번호 스프레이는 소수의 흔한 비밀번호를 여러 계정에 시도한다.
시도 제한, 안전한 비밀번호 검증, MFA, 이상 징후 감시를 결합한다. 계정 복구나 인증수단 변경이 원래 인증보다 훨씬 약하면 그 절차가 우회 경로가 될 수 있다.
5. 서버 측 인가
인가는 화면에서 메뉴를 숨기는 것만으로 구현하지 않는다. 요청을 처리하는 서버가 매번 해당 사용자·행위·대상의 허용 조건을 확인해야 한다.
| 구분 | 의미 | 예 |
|---|---|---|
| 기능 수준 인가 | 특정 기능을 실행할 수 있는지 | 일반 사용자의 관리자 기능 호출 거부 |
| 객체 수준 인가 | 특정 데이터에 접근할 수 있는지 | 다른 사람의 지원서 조회 거부 |
| 필드 수준 인가 | 특정 속성을 읽거나 변경할 수 있는지 | 일반 사용자의 권한 등급 수정 거부 |
같은 역할의 다른 사용자 자료에 접근하는 것은 수평적 권한 상승, 일반 사용자가 관리자 권한을 얻는 것은 수직적 권한 상승과 연결된다. 순번 대신 UUID를 사용하더라도 ID를 알아낸 요청자의 권한 검사는 필요하다.
기본 거부, 최소 권한, 요청마다 권한 확인을 적용한다. 허용 규칙이 없거나 필요한 검증에 실패했는데도 권한을 부여하는 동작은 피한다.
6. 세션 공격과 통제
세션은 여러 요청을 같은 인증 상태와 연결하는 수단이다. 세션 ID는 충분히 예측하기 어렵게 생성하고 외부 노출을 줄여야 한다.
| 공격·문제 | 핵심 내용 | 대표 대응 |
|---|---|---|
| 세션 예측 | 생성 규칙을 추측해 유효 값을 찾음 | 안전한 난수 기반 식별자 |
| 세션 고정 | 공격자가 아는 세션 ID를 사용자가 인증 후에도 사용 | 로그인·권한 상승 시 ID 재발급 |
| 세션 탈취 | 다른 사용자의 유효 세션 값을 얻어 사용 | 전송 보호·노출 방지·XSS 방어 |
| 세션 재사용 | 종료·만료되어야 할 값을 계속 사용 | 서버 측 만료·무효화 |
| 사용자 상태 혼동 | 여러 사용자의 상태가 잘못 공유 | 사용자별 상태 분리 |
쿠키의 Secure는 HTTPS 연결에서의 전송 제한, HttpOnly는 스크립트의 직접 읽기 제한, SameSite는 사이트 간 쿠키 전송 조건과 관련된다. 이름이 서로 다른 목적을 나타내므로 ‘어떤 속성 하나면 모든 세션 공격 차단’으로 외우지 않는다.
로그인·권한 상승 때 세션 ID를 재발급하고, 로그아웃·만료·계정 비활성화 등에는 관련 세션을 무효화한다. 브라우저에서 쿠키를 지웠다고 서버의 기존 세션도 반드시 무효가 되는 것은 아니다.
유휴 만료는 일정 시간 활동이 없을 때, 절대 만료는 활동 여부와 관계없이 정해진 최대 기간이 지나면 종료하는 조건이다. 토큰 기반 구조도 서명 검증·만료·철회와 권한 변경 반영을 검토해야 한다. 토큰을 쓴다고 세션 수명 관리가 없어지는 것은 아니다.

메모리·동시성·인증에서 빠지기 쉬운 조건
동적 메모리를 해제한 뒤 읽거나 쓰면 해제 후 사용(Use-after-free), 같은 블록을 다시 해제하면 이중 해제(Double Free)다. 소유권과 자원 해제 책임을 명확히 하고 성공·실패 경로 모두에서 일관되게 관리한다. C의 널 종료 문자열은 데이터 문자 외에 종료 문자 공간도 필요하다. ASCII N개를 각 1바이트로 저장한다면 최소 N+1바이트이며, 이 규칙을 모든 다국어 인코딩의 문자 수에 그대로 적용하지 않는다.
정수 연산에서는 자료형의 범위와 언어의 규칙을 확인한다. 문제에서 8비트 부호 없는 연산을 256에 대한 나머지로 저장한다고 명시했다면 0−1은 255로 저장된다. 언어가 명시되지 않은 모든 정수의 오버플로 결과를 동일하다고 가정해서는 안 된다.
갱신 손실과 교착
공유 변수 증가가 읽기→계산→쓰기의 분리된 연산이라면 두 작업이 같은 이전 값을 읽을 수 있다. 둘 다 이전 값+1을 저장하면 증가 하나의 효과가 소실된다. 잠금 또는 적절한 원자 연산으로 필요한 구간을 보호한다. 검사를 했다는 사실만으로 검사와 실제 사용 사이 상태 변경(TOCTOU)이 배제되지는 않는다.
A는 L1을 가진 채 L2를 기다리고 B는 L2를 가진 채 L1을 기다린다면 순환 대기로 진행하지 못할 수 있다. 공통 잠금 획득 순서는 이런 순환을 예방하는 방법이다. 대기만 하는 교착과, 상태를 바꾸고 재시도하지만 유효한 진행이 없는 라이브락을 구분한다.
인증 요소와 세션 식별자
지식 요소는 비밀번호·PIN, 소지 요소는 보안키·인증 장치, 생체 요소는 지문 등이다. 비밀번호와 다른 PIN을 함께 물어도 둘 다 지식 요소라면 서로 다른 유형의 MFA가 아니다. 유출된 계정·비밀번호 쌍의 재사용은 Credential Stuffing, 소수의 흔한 비밀번호를 많은 계정에 나누어 시도하는 것은 Password Spraying이다.
세션 ID의 길이는 실제 예측 불가능성과 다르다. 시각+일련번호를 길게 표현하거나 Base64로 바꾸어도 생성 규칙이 예측 가능하면 안전한 난수를 대신하지 못한다. 인증·권한 상승 시 세션 재발급, 서버 측 만료·폐기, 안전한 쿠키 설정과 자원별 인가를 함께 적용한다. 비밀 문자열을 클라이언트에 넣었다는 이유로 영구 권한을 부여하지 않는다.