Skip to Content
Backend상품명에 큰따옴표가 들어가면 결제가 실패한 이유
💻 Backend2023년 11월 14일

상품명에 큰따옴표가 들어가면 결제가 실패한 이유

#e-commerce#payment-expansion#backend#bugfix
Payment Expansion · Series 3 · Rebuild & Quality10 / 14Backend
상품명의 큰따옴표 때문에 발생한 결제 API 파싱 오류와 대응을 정리합니다.

특정 상품을 주문할 때만 결제가 실패하는 문제가 있었습니다. 로그를 따라가 보니 상품명에 들어간 큰따옴표가 원인이었습니다. 같은 결제 API를 호출해도 어떤 문자열을 전달하느냐에 따라 결과가 달라졌습니다.

상품명 처리를 수정한 뒤에는 아이템명에서도 같은 문제가 발생했습니다. 한 필드를 고쳤다고 다른 필드의 요청 구성까지 바뀌는 것은 아니었습니다.

큰따옴표와 JSON 파싱 오류

JSON은 큰따옴표로 문자열의 시작과 끝을 구분합니다. 문자열 안에 큰따옴표를 넣으려면 이스케이프 처리가 필요합니다. 예를 들어 A "Limited" Shoe라는 이름은 JSON에서 다음처럼 표현해야 합니다.

json
{"itemName": "A \"Limited\" Shoe"}

이 처리가 빠지면 파서는 이름 중간의 큰따옴표를 문자열의 끝으로 해석합니다. 결제 요청에 필요한 나머지 값이 정상이어도 JSON을 읽는 단계에서 실패합니다.

앱에서 웹뷰로 값을 넘기는 과정도 함께 살펴봐야 했습니다. 객체를 직렬화해서 전달하는 구간과 문자열을 조합하는 구간이 섞여 있으면, 앞 단계에서 정상인 값도 다음 단계에서 다시 깨질 수 있습니다. 최종 요청뿐 아니라 중간에 문자열이 어떻게 바뀌는지 확인하는 이유입니다.

상품명 수정 이후의 재발

첫 문제는 2023년 9월에 발견했습니다. 특정 주문의 실패 로그에서 JSON 파싱 오류를 확인했고, 상품명에 포함된 큰따옴표를 처리하도록 수정했습니다.

이후 아이템명에서도 같은 유형의 오류가 발생했습니다. 상품명과 아이템명의 요청 구성 코드가 서로 다른 곳에 있어 앞선 수정이 적용되지 않았습니다. 두 문제는 별도 필드에서 발생했지만, 문자열을 JSON으로 만드는 과정에서 필요한 처리가 빠졌다는 원인은 같았습니다.

요청을 만드는 지점 확인

이런 오류를 확인할 때는 필드 이름으로만 코드를 찾으면 놓치는 부분이 생깁니다. 상품명이 어디서 들어오는지, 웹뷰를 거치며 다시 조합되는지, 최종 JSON은 누가 만드는지까지 따라가야 합니다. 큰따옴표뿐 아니라 역슬래시나 줄바꿈이 들어간 값도 함께 확인할 필요가 있습니다.

다음은 Jackson으로 요청을 만드는 예시입니다. 당시 수정 코드를 옮긴 것은 아닙니다. 문자열 이스케이프를 직접 조합하지 않고 직렬화 라이브러리에 맡기는 방법을 보여줍니다.

java
sample/json-payload-example.java
public String buildPayload(String itemName) throws JsonProcessingException { ObjectNode root = mapper.createObjectNode(); root.put("itemName", itemName); return mapper.writeValueAsString(root); }

테스트에서는 JSON 문자열에 특정 패턴이 있는지만 보기보다, 다시 읽은 값이 원래 입력과 같은지도 확인할 수 있습니다.

java
sample/json-payload-example-test.java
@Test void preservesQuotesInItemName() throws JsonProcessingException { String itemName = "A \"Limited\" Shoe"; String json = buildPayload(itemName); assertThat(mapper.readTree(json).get("itemName").asText()) .isEqualTo(itemName); }

상품명 처리를 수정한 뒤에도 아이템명에서 같은 오류가 다시 발생했습니다. 두 필드의 요청 구성 코드가 따로 있었기 때문에 한쪽 수정만으로는 끝나지 않았습니다. 이 사례에서는 큰따옴표를 처리하는 코드뿐 아니라, 문자열을 받아 최종 JSON으로 만드는 경로까지 함께 확인해야 했습니다.

위 예시는 직렬화를 라이브러리에 맡기는 방법이며 당시 수정 코드를 그대로 옮긴 것은 아닙니다. 이미 직렬화된 값에 이스케이프를 한 번 더 적용하지 않는지와, 다시 읽은 값이 원래 입력과 같은지도 확인할 항목으로 남겼습니다.

다음 글에서는 서비스마다 흩어져 있던 결제 연동 코드를 공통 클라이언트 라이브러리로 묶은 과정을 다룹니다.

Last updated on