본문 바로가기

개발자로써./개발 하면서 했던 고민

결제 시스템 개선기

취치

  • 기존 결제 시스템을 이용해 개발하면서, 결제 화면과 BackEnd API를 구성하면서 항상 이것이 맞는것인가라고 의문을 가지면서 개발을 진행하였다.
  • 기존에 구축되었던 시스템일지라도 Why라는 의문과 취약점을 개선해야 한다고 생각하였고 그러한 의문으로부터 발견한 의문점 개선기를 기록하기 위해 작성해야겠다는 생각을 했다.
  • 기록을 하여야 실수를 방지할수 있다라고 생각하기 때문이다. 

기존 결제 시스템의 프로세스

4가지의 의문점

  • 세션에 결제 가격을 저장하고, 이후 검증 도구로 사용하는 것이 옳은 방식인가?
  • 브라우저단에서 바로 PG사에 Form Action을 통해 전송하는것이 맞는가?
  • PG사에서 전송해준 데이터에 대한 로그를 전달받은 특정 URI에서 하지 않고 비즈니스단에서 처리하는것이 옳은 방식인가?
  • 가상계좌시 입금 여부를 어떻게 파악할것인가?

세션에 결제 가격을 저장하고, 이후 검증 도구로 사용하는 것이 옳은 방식인가?

1차적으로 세션에 결제정보를 저장하고, 이후 결제 하기전이나 후에 세션에 존재하는 결제정보를 통해 검증하는 방식으로 이루어졌는데 이 방식이 옳은가 생각하며 장,단점을 생각하게 되었다.

 

장점

  • 세션에 저장된 값이므로 Memory에 저장된 정보이다. 검증시 Memory에서 꺼내면 되므로, 빠른 처리를 할수 있다.
  • 세션에 넣고, 세션에서 빼고 하는 작업이므로, 휘발성 메모리이고 그러므로 부가적인 관리 비용이 발생하지 않는다.

단점

  • 대규모 트랜잭션 환경에서, 수 많은 유저가 급작스럽게 결제를 하려는 상황에서 세션 메모리가 순간적으로 차올라서 서버에 무리를 줄수 있다.
  • 탈취의 위험성이 존재한다.

다른 방안은 ?

  • 다시 Table에서 결제 정보를 조회한다.
  • 부담을 전가하자. Redis와 같은 In-Memory DB를 활용하자.

다른 방안의 장단점을 찾자.

1) 다시 Table에서 결제 정보를 조회한다. 

 

장점

  • 세션에서 발생하는 Memory 이슈나, 초기화 Issue에서 벗어날수 있다.
  • 탈취의 위험성에서 벗어날수 있다.

단점

  • 다시 DB를 조회해야 하므로 속도면에서 불리하고, 예약 같은 경우 여러 부가적인 Table을 같이 조회해야 하는 상황이 존재하는 다시 조회하기 위해서는 조회를 위한 Parameter, 조회해야 하는 Service를 결제 단계 전에 저장해야 한다.
  • 어디에 저장해야 하는가? 역시 세션이나 In Memory DB에 저장할수밖에 없다. 이건 전과 다르지 않은 환경이다.

2) 부담을 전가하자. Redis와 같은 In-Memory DB를 활용하자.

 

장점

  • 세션에서 발생하는 Memory 이슈나, 초기화 Issue에서 벗어날수 있다.
  • 탈취의 위험성에서 벗어날수 있다.

단점

  • 초기 세팅 비용이 필요하고, Redis에 대한 관리 포인트, 관리 비용까지 증가한다. 

결론은?

팀 내에서 많은 논의가 이루어졌고, 결론은 Session 사용에 대한 보안을 강화하고 주기적인 모니터링을 하자 고 협의하였다.

why?

  • 그룹사의 OutSourcing을 통해 개발시스템을 관리하고 있는데, 그룹사가 잘 돌아가고 있는 현상황에서 추가적인 비용을 감내하지 못하는 점
  • 현 상황에서 개발하고 있는 프로젝트가 여럿 존재하였고, 추가적인 개발자를 할당하기 어려운점
  • 긴급하지 않은 사안이고, 추가적인 조치를 통해서도 해결할수 있는점

how 어떻게 수정하였을까?

일단 발생할수 있는 문제점은 크게 3가지이다.

1) 트래픽이 몰릴시 Session사용으로 발생할수 있는 Memory Issue

2) Session을 탈취하여, 발생할수 있는 악용

 

1) 주기적인 Monitoring을 지속한다. 현재 트래픽으로 Session Memory로 발생하는 Issue는 없었으며, 발생할수 있는 가능성도 무척 낮다. 

이후 발생할수 있는 환경하에서, 다시 System에 대한 개편이 이루어져야 하다.

2) Session은 위변조는 불가능하지만, 탈취를 통해 악용은 이루어질수 있다. 그러므로, Session에 가격을 저장할때 그 유저를 특정할수 있는 정보도 추가적으로 저장하여 탈취되는 경우를 가정한 검증을 시도한다.

라우저단에서 바로 PG사에 Form Action을 통해 전송하는것이 맞는가?

브라우저단에서 바로 PG사에 데이터를 전송하면, 탈취를 가능성이 존재한다.

중간에 탈취를 하여 가격을 변경하여 PG사에 보내고, PG사에서 보내는 특정 URI를 파악하여 변경한 가격이 아닌 다시 원래의 가격의 패킷을 전송한다.

이럴 경우, 100원으로도 결제를 진행할수 있고 결제를 할수가 있다.

그래서, 검증하는것이 무조건적으로 필요하다고 생각하였다.

how 어떻게 수정하였을까?

1) Include 된 브라우저단 iframe에서 보내기 때문에, 보내는 과정은 막을수가 없다. 받는 과정에서 검증을 추가하자.

2) 받는 URI에서 무조건 전달받은 패킷을 탈취된 패킷이라고 가정하자. 전달받은 데이터는 가맹점 정보, 거래 정보, 가격등이다.

3) 받는 상품정보, 수량등을 다시 DB에 조회해서 전달받은 가격정보와 비교하자.

조회 후 가격과 전달받은 가격을 비교하여, 일치하지 않는다면 탈취받은 패킷이라고 가정하고, Exception을 내서 거래 취소 API를 호출한다.

PG사에서 전송해준 데이터에 대한 로그를 전달받은 특정 URI에서 하지 않고 비즈니스단에서 처리하는것이 옳은 방식인가?

해당 결제 시스템을 통해 화면결제와 Backend Process를 만들면서 들은 의문이다. 

PG사에서 결제 정보를 특정 URI로 전달하는데, 그 특정 URI에서 결제정보 로그를 등록하지 않고, 이후 비즈니스로직단에서 결제정보를 등록하는 것이였다.

이 방식은 다음과 같은 단점이 존재한다.

  • 비즈니스 로직이 실행되지 않으면, 결제 정보가 저장되지 않는다.
  • 비즈니스 로직 트랜잭션이 실패하게 될시, 결제 정보가 저장되지 않을 가능성도 존재한다.
  • 비즈니스 로직을 짜다가, 실수로 PaymentModule을 생성하여 결제 정보를 저장하는 함수를 호출하지 않으면 결제정보는 저장되지 않는다.

불편함과 더불어 치명적이라고 생각했고, 다음과 같은 수정을 하였다.

1) PG사에서 결제 정보를 특정 URI로 전달할때, 특정 URI Method에서 결제 정보에 대한 Log를 저장한다.

2) 비즈니스단에서는 결제 로그 정보 저장에 대한 로직을 지우고, 해야할 비즈니스 역할에만 집중할수 있도록 한다.

가상계좌시 입금 여부를 어떻게 파악할것인가?

가상계좌시 입금 여부는 Notification Data를 전달받고 그 전달받은 데이터를 통해 내부 데이터를 수정한다.

하지만 개발환경에서 전달받은 가맹점용 테스트 브라우저에서 아무리 입금을 해도 데이터가 오지 않았다.

매번 TImeoutException이 떨어졌고, 2가지 경우가 존재한다고 생각했다.

  • 우리쪽 방화벽에 막혀서 들어오지 못하는 경우
  • KICC쪽 방화벽이나 Port가 막혀있어서 데이터가 들어오지 못하는 경우

처음에는 KICC쪽을 의심했고 담당자와 전화통화를 하였는데, 그쪽은 막혀있지 않다는 답변을 들었다.이후 우리쪽일거라 생각하였고, 인프라팀에 문의하여 KICC쪽 IP로 전달받은 Data를 확인하였는데, 없다는 대답을 들었다.

 

무언가 있다... 라는 생각이 들었고 다시 KICC쪽에 전화하여 상황을 전달하며 다시 한번 확인해줄것을 요구하였다.

결국, KICC쪽에 방화벽이 막혀있다는 답변을 들었다.... 그 기분은 허무했다.

 

이후 의사소통 방식을 바꿨는데, 항상 뭔가를 요청할때, 내가 파악할수 있는 여건들은 다 파악하여 상황 전달하려는 노력을 하게 변하시켜준 계기가 되었다.