버짓핸들러 연동 가이드
  • 💳버짓핸들러 연동 안내
    • 🎁버짓핸들러 서비스 소개
    • 🪧버짓핸들러 기본 정책
    • 🖥️연동 준비하기
  • 📒버짓핸들러 관리자 설정하기
  • 🕹️버짓핸들러 인증결제 호출
    • 🪧인증결제 정의
    • 💡1. 차이포트 라이브러리 추가
    • 📀2. 객체 초기화 하기
    • 💸3. 결제 요청하기
    • 🔖4. 결제결과 처리하기
      • 📺iframe 결제창 결과처리
      • 🌠redirect 결제창 결과처리
    • 🔦5. 결제정보 검증하기
    • 🧹6. 결제완료 처리하기
  • 💳버짓핸들러 비인증 결제 호출
    • 🖱️비인증 결제란?
    • 🚜빌링키 획득하기
      • ⌨️REST API 이용하기
      • 🛡️PG결제창 이용하기
    • 📞비인증 결제 요청하기
  • 🖥️버짓핸들러 API
    • ⌨️프로모션 정보획득 API
    • ⌨️프로모션 적용금액 획득 API
Powered by GitBook
On this page
  • STEP 01 결제결과 서버 수신
  • STEP 02 결제내역 단건 조회
  • STEP 03 결제정보 검증
  1. 버짓핸들러 인증결제 호출

5. 결제정보 검증하기

결제결과를 검증하여 안정적인 결제서비스 구축에 관한 가이드 입니다.

Previousredirect 결제창 결과처리Next6. 결제완료 처리하기

Last updated 3 years ago

운영중인 서버에서 클라이언트로 부터 전달 받은 결제 결과 데이터를 바탕으로 결제금액 위변조 여부를 검증하고 필요시 데이터베이스에 저장합니다. 결제 정보를 검증하는 과정은 크게 아래와 같은 단계로 진행합니다.

  • 아임포트 결제고유번호(imp_uid), 주문번호(merchant_uid)를 서버단에서 수신

  • 결제 상세내역 조회를 위해 아임포트 요청

  • 응답받은 내용을 바탕으로 실 결제 금액과 결제요청금액(가맹점 자체 데이터베이스)을 비교

STEP 01 결제결과 서버 수신

결제정보를 받은 가맹점 endpoint URL 에 대한 POST 요청을 수신하는 예제

server-side
app.use(bodyParser.json());
  // "{서버의 결제 정보를 받는 가맹점 endpoint}" POST 요청 수신부
  app.post("/payments/complete", async (req, res) => {
    try {
      // req의 body에서 imp_uid, merchant_uid 추출
      const { imp_uid, merchant_uid } = req.body; 
    } catch (e) {
      res.status(400).send(e);
    }
  });

STEP 02 결제내역 단건 조회

수신받은 아임포트 결제고유번호(imp_uid)로 API 를 호출하여 결제정보 획득 예제

server-side
app.use(bodyParser.json());
    ...
    app.post("/payments/complete", async (req, res) => {
      try {
        // req의 body에서 imp_uid, merchant_uid 추출
        const { imp_uid, merchant_uid } = req.body; 
        ...
        // 액세스 토큰(access token) 발급 받기
        const getToken = await axios({
          url: "https://api.iamport.kr/users/getToken",
          method: "post", // POST method
          headers: { "Content-Type": "application/json" }, 
          data: {
            imp_key: "imp_apikey", // REST API 키
            imp_secret: "ekKoeW8RyKuT0zgaZsUtXXTLQ4AhPFW3ZGseDA6bkA5lamv9OqDMnxyeB9wqOsuO9W3Mx9YSJ4dTqJ3f" // REST API Secret
          }
        });
        const { access_token } = getToken.data.response; // 인증 토큰
        ...
        // imp_uid로 아임포트 서버에서 결제 정보 조회
        const getPaymentData = await axios({
          // imp_uid 전달
          url: \`https://api.iamport.kr/payments/\${imp_uid}\`, 
          // GET method
          method: "get", 
          // 인증 토큰 Authorization header에 추가
          headers: { "Authorization": access_token } 
        });
        const paymentData = getPaymentData.data.response; // 조회한 결제 정보
        ...
      } catch (e) {
        res.status(400).send(e);
      }
    });

STEP 03 결제정보 검증

결제금액의 위변조 검증 이유

결제 요청은 클라이언트 환경에서 이루어지기 때문에 클라이언트 스크립트를 조작해 금액을 위 변조하여 결제를 요청할 수 있습니다. 따라서 결제완료 후 처음 요청했던 금액과 실제로 결제된 금액을 반드시 비교해야 합니다.

예를 들어 100,000원짜리 상품을 결제할 때에는 amount: 100000으로 결제요청을 하게 되는데, 공격자가 스크립트를 조작하여 해당 속성을 실제 금액보다 낮은 값으로 변조할 수 있습니다.

클라이언트에서의 스크립트 조작은 원천적으로 막을 수 없는 기술적 특징이 있기 때문에 결제 후 서버에서 결제금액의 위변조 여부를 반드시 검증해야 합니다.

결제된 실 금액과 요청 금액을 비교하여 결제금액 위변조여부 검증 및 DB저장 예시

server-side
app.use(bodyParser.json());
  ...
  app.post("/payments/complete", async (req, res) => {
    try {
      // req의 body에서 imp_uid, merchant_uid 추출
      const { imp_uid, merchant_uid } = req.body; 
      // 액세스 토큰(access token) 발급 받기
      /* ...중략... */
      // imp_uid로 아임포트 서버에서 결제 정보 조회
      /* ...중략... */
      const paymentData = getPaymentData.data.response; // 조회한 결제 정보
      ...
      // DB에서 결제되어야 하는 금액 조회
      const order = await Orders.findById(paymentData.merchant_uid);
      const amountToBePaid = order.amount; // 결제 되어야 하는 금액
      ...
      // 결제 검증하기
      const { amount, status } = paymentData;
      // 결제금액 일치. 결제 된 금액 === 결제 되어야 하는 금액
      if (amount === amountToBePaid) { 
        await Orders.findByIdAndUpdate(merchant_uid, { $set: paymentData }); // DB에 결제 정보 저장
        ...
        switch (status) {
          case "ready": // 가상계좌 발급
            // DB에 가상계좌 발급 정보 저장
            const { vbank_num, vbank_date, vbank_name } = paymentData;
            await Users.findByIdAndUpdate("/* 고객 id */", { $set: { vbank_num, vbank_date, vbank_name }});
            // 가상계좌 발급 안내 문자메시지 발송
            SMS.send({ text: \`가상계좌 발급이 성공되었습니다. 계좌 정보 \${vbank_num} \${vbank_date} \${vbank_name}\`});
            res.send({ status: "vbankIssued", message: "가상계좌 발급 성공" });
            break;
          case "paid": // 결제 완료
            res.send({ status: "success", message: "일반 결제 성공" });
            break;
        }
      } else { // 결제금액 불일치. 위/변조 된 결제
        throw { status: "forgery", message: "위조된 결제시도" };
      }
    } catch (e) {
      res.status(400).send(e);
    }
  });

처음 요청한 금액은 merchant_uid 로 데이터베이스에서 조회하고 실제 결제금액은 imp_uid로 아임포트 서버에서 조회하여 두 값을 비교합니다. 검증이 성공하면 결제 정보를 데이터베이스에 저장한 뒤 결제 상태(status)에 따라 알맞은 응답을 반환하고 실패 시 에러 메세지를 출력합니다.

결제결과 DB 처리는 웹훅(Webhook)을 연동하여 수신되는 데이터를 기준으로 처리하셔야 결제결과 누락없이 안정적인 결과처리를 완료하실 수 있습니다.

🕹️
🔦
결제 단건 조회 API
결제단건조회