본문 바로가기

IT정리/보안 기초

2-1. 비즈니스 로직 보안 - 액션 토큰에 대해서

액션 토큰은 특정 요청이 정상적인 화면 흐름을 따라 이루어졌는지 검증하기 위해 사용된다.

일반적으로 화면에서 토큰을 발급하고, 이후 요청에서 동일한 값을 전달해야만 처리가 가능한 형태로 구현된다.

하지만 실제 서비스에서는 사용자가 해당 화면을 열지 않았음에도 자동화 프로그램이 요청을 성공시키는 사례가 자주 발생한다.

이는 구조적으로 액션 토큰만으로는 자동화 공격을 막을 수 없기 때문이다.

다음은 그 개념적 이유와 이해를 돕기 위한 예시들이다.

1.액션 토큰의 한계

1.1.화면 접근 여부만으로 토큰 발급을 통제할 수 없다

자동화 프로그램은 화면을 직접 보지 않아도 백그라운드 요청을 통해 토큰 발급 경로에 접근할 수 있다.

사람이 화면을 열었는지 여부는 서버에서 구분할 수 없고 자동화 프로그램은 단순히 GET 요청을 통해서 단순 HTTP 요청으로 호출이 가능하다.

// 자동화 코드에서 화면 렌더 없이 토큰 발급 경로 호출
GET /apply-form?item=123
Cookie: JSESSIONID=abc

// 서버는 이를 정상적인 화면 접근으로 판단

 

1장에서 말했다시피 모든 HTTP통신은 문자열로 이뤄진다.

HTML 또한 문자열로 응답이 나오기 때문에 액션 토큰이 들어간 name="action_token" 부분을 찾아서 토큰 값만 뽑을 수 있다.

이 토큰값은 매크로 프로그램에서 사용이 가능하다.

 

1.2. 발급 정보가 없는 단순 문자열 토큰은 재사용을 막을 수 없다

토큰에 다음 정보가 없다면

  • 발급 시각(iat)
  • 만료 시간(exp)
  • 대상 자원(resourceId)
  • 사용자 식별(userId)

서버는 이 값이 언제, 누구에게, 어떤 목적을 위해 발급된 것인지 알 수 없다.

이 경우 사용자가 화면에 접근하지 않아도 자동화 프로그램은 저장된 토큰만 알고 있으면 요청이 가능하다.

// 서버가 세션에 저장한 값
session["action_token"] = "XYZ123"

// 자동화 프로그램이 언제든지 재사용
POST /submit
token=XYZ123

단순 문자열 기반 구조에서는 이 값이 언제, 어떤 목적, 어떤 자원에 대해 발급된 것인지 알 수 없으므로 재사용을 막을 수 없다.

 

1.3.  토큰 검증이 느슨하면 토큰이 없어도 요청이 성공한다

일부 시스템에서는 구버전 호환 또는 이전 코드의 영향으로 토큰 검증 실패 시 경고만 남기고 요청 자체는 처리해 버리는 경우가 있다.

이 경우 자동화 프로그램은 이를 이용해 토큰 없이도 요청을 보내 성공시킬 수 있다.

if (token == null || !token.equals(sessionToken)) {
    log("token invalid");
    // 요청은 계속 진행됨 (취소되지 않음)
}

이 경우 자동화 프로그램은 토큰 없이 요청을 보내도 성공할 수 있다.

즉, 검증 실패 = 요청 실패가 아닌 구조는 반드시 보안 문제가 된다.

 

1.4. 토큰이 특정 자원(resource)과 결합되어 있지 않으면 오용이 가능하다

단순 문자열 값만 있는 경우 서버는 이 토큰이 특정 데이터(예: 특정 자원 ID)에 대해 발급된 것인지 알 수 없다.

이 경우 자동화 프로그램은 한 번 확보한 값을 다른 요청에도 그대로 적용할 수 있다.

// A 작업용으로 발급된 토큰
token = ABC999

// B 작업에도 사용 가능
POST /submit-other
token=ABC999

관계가 없는 요청에 토큰이 재사용될 수 있기 때문에 반드시 토큰 ↔ 자원 바인딩이 필요하다.

 

1.5. 시간 개념이 없는 토큰은 오래된 값도 재사용된다

발급 시각과 만료 시간이 없다면 오래전에 발급된 토큰이 계속 살아 있게 되고 자동화 프로그램은 이 값을 수동으로 입력하거나 저장 후 재사용할 수 있다.

토큰을 재사용 하게 되면 사람은 불가능한 속도의 동작을 자동화 프로그램은 매우 쉽게 동작할 수 있다.

// 3일 전 발급된 토큰도
session["action_token"] = "OLD888"

// 여전히 유효하다고 처리됨
POST /submit
token=OLD888

 

 

1.6. 사용자 세션은 자동화 프로그램이 그대로 사용할 수 있다

로그인한 후 발급된 세션 쿠키를 자동화 프로그램이 읽어와 자신이 보내는 HTTP 요청에 그대로 적용하면 서버는 이 요청이 사용자 브라우저에서 온 것인지 자동화 프로그램에서 온 것인지 알 수 없다.

이 경우 토큰 발급 경로에 접근할 때도 정상 사용자처럼 행동할 수 있다.

// 브라우저에서 가져온 사용자 세션 쿠키
Cookie: JSESSIONID=user123

// 자동화 프로그램이 이 쿠키를 그대로 사용
GET /apply-form

이 때문에 세션이 있다고 해서 정상 사용자 흐름이라고 볼 수 없다.

 

1.7. 화면 안의 숨겨진 값은 보호 수단이 아니다.

HTML에 포함된 데이터는 모두 텍스트로 응답을 받는다.

때문에 화면에서 내려준 HTML의 숨겨진 값은 자동화 프로그램이 쉽게 파싱하거나 DOM을 통해 읽을 수 있다.

즉, 화면을 실제로 열지 않아도 자동화 프로그램은 필요한 값을 그대로 수집할 수 있다.

<input type="hidden" name="action_token" value="HIDE777">

자동화 프로그램은 화면 렌더 없이 HTML 텍스트만 읽어도 이 값을 쉽게 얻는다.

 

이렇게 액션 토큰 만으로는 확실한 보안 효과를 볼 수 없기 때문에 여러가지 추가적인 보안적 요소를 넣는다.

대표적으로:

  • 토큰 + 맥락 바인딩
  • 흐름 검증
  • 상태 전이 검증
  • 서버 단 비즈니스 규칙 재검증

등이 있으면 다음 포스팅 예정이다.