File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
2025-07-21
package itn.let.uat.uia.web;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Random;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.springframework.stereotype.Component;
import org.springframework.ui.ModelMap;
import org.springframework.web.servlet.FlashMap;
import org.springframework.web.servlet.FlashMapManager;
import org.springframework.web.servlet.support.RequestContextUtils;
import com.icert.comm.secu.IcertSecuManager;
import itn.let.cert.phone.service.CertPhoneService;
import itn.let.cert.phone.service.MberCertPhoneVO;
import itn.let.mjo.pay.service.KmcVO;
import itn.let.uat.uia.service.AuthCertVO;
@Component("KmcCertChecker")
public class KmcCertChecker {
@Resource(name = "CertPhoneService")
private CertPhoneService certPhoneService;
//회원가입 시 인증수단을 휴대폰 본인인증만 했을 경우 사용
public AuthCertVO authCertCheck(
MberCertPhoneVO mberCertPhoneVO
, HttpServletRequest request
) {
//url 세팅
mberCertPhoneVO = setMberCertPhoneVO(request, mberCertPhoneVO);
//kmc step 01 데이터
//reqNum은 최대 40byte 까지 사용 가능
String reqNum = getDay() + getRanNum(); //요청번호
String tr_cert = "";
String cpId = "MJOM1001"; // 회원사ID
String urlCode = mberCertPhoneVO.getUrlCode(); // URL코드
String certNum = reqNum; // 요청번호 ( 본인인증 요청시 중복되지 않게 생성해야함. (예-시퀀스번호) )
String date = getDay(); // 요청일시
String certMet = "M"; // 본인인증방법 - M:휴대폰 본인인증, C:신용카드인증, P:공인인증서 인증
// String name = ""; // 성명
String name = mberCertPhoneVO.getName(); // 성명
String phoneNo = mberCertPhoneVO.getPhoneNo(); // 휴대폰번호
String phoneCorp = mberCertPhoneVO.getPhoneCorp(); // 이동통신사
if(phoneCorp == null) phoneCorp = "";
String birthDay = mberCertPhoneVO.getBirthDay(); // 생년월일
String gender = mberCertPhoneVO.getGender(); // 성별
if(gender == null) gender = "";
String nation = mberCertPhoneVO.getNation(); // 내외국인 구분 - 0:내국인, 1:외국인
String plusInfo = mberCertPhoneVO.getPlusInfo(); // 추가DATA정보
String extendVar = "0000000000000000"; // 확장변수
//End-tr_cert 데이터 변수 선언 ---------------------------------------------------------------
String tr_url = getDomain(request) + mberCertPhoneVO.getTrUrl();// // 본인인증서비스 결과수신 POPUP URL
String tr_add = "N"; // IFrame사용여부
//01. 한국모바일인증(주) 암호화 모듈 선언
// IcertSecuManager seed = new IcertSecuManager();
com.icert.comm.secu.IcertSecuManager seed = new com.icert.comm.secu.IcertSecuManager();
//02. 1차 암호화 (tr_cert 데이터변수 조합 후 암호화)
String enc_tr_cert = "";
// tr_cert = cpId +"/"+ urlCode +"/"+ certNum +"/"+ date +"/"+ certMet +"/"+ birthDay +"/"+ gender +"/"+ name +"/"+ phoneNo +"/"+ phoneCorp +"/"+ nation +"/"+ plusInfo +"/"+ extendVar;
tr_cert = cpId +"/"+ urlCode +"/"+ certNum +"/"+ date +"/"+ certMet +"///////"+ plusInfo +"/"+ extendVar;
enc_tr_cert = seed.getEnc(tr_cert, "");
//03. 1차 암호화 데이터에 대한 위변조 검증값 생성 (HMAC)
String hmacMsg = "";
hmacMsg = seed.getMsg(enc_tr_cert);
//04. 2차 암호화 (1차 암호화 데이터, HMAC 데이터, extendVar 조합 후 암호화)
tr_cert = seed.getEnc(enc_tr_cert + "/" + hmacMsg + "/" + extendVar, "");
AuthCertVO authCertVO = new AuthCertVO();
authCertVO.setTr_cert(tr_cert);
authCertVO.setTr_url(tr_url);
authCertVO.setTr_add(tr_add);
return authCertVO;
}
public KmcVO authCertResult(
HttpServletRequest request
, HttpServletResponse response
, ModelMap model
) throws IOException {
//크롬 SameSite정책 방지 - 도메인이 다른 타사로 이동 시 크롬 정책에 의해 세션 유실이 일어나는 경우가 있는데, 이를 방지하기 위해 samesite 보안을 none처리
response.setHeader("Set-Cookie", "mberSession=mberSession; Secure; SameSite=None");
KmcVO kmcVO = new KmcVO(); //return VO
// 변수 -------------------------------------------------------------------------------------------------------------
String api_token = ""; // 토큰값(암호화)
String api_certNum = ""; // 요청번호(암호화)
String message = ""; // JSON 전문
String result_cd = ""; // JSON 결과코드
String result_msg = ""; // JSON 결과-상세
String strResult = ""; // JSON 결과
String apiRecCert = ""; // JSON 전송 데이터
String apiCertNum = ""; // JSON 전송 데이터
String rec_cert = ""; // 결과수신DATA
String k_certNum = ""; // 파라미터로 수신한 요청번호
String certNum = ""; // 요청번호
String date = ""; // 요청일시
String CI = ""; // 연계정보(CI)
String DI = ""; // 중복가입확인정보(DI)
String phoneNo = ""; // 휴대폰번호
String phoneCorp = ""; // 이동통신사
String birth = ""; // 생년월일
String gender = ""; // 성별
String nation = ""; // 내국인
String name = ""; // 성명
String reserve1 = ""; // 예비필드
String reserve2 = ""; // 예비필드
String reserve3 = ""; // 예비필드
String reserve4 = ""; // 예비필드
String result = ""; // 결과값
String certMet = ""; // 인증방법
String ip = ""; // ip주소
String plusInfo = "";
String encPara = "";
String encMsg1 = "";
String encMsg2 = "";
String msgChk = "";
//-----------------------------------------------------------------------------------------------------------------
try{
// Parameter 수신 --------------------------------------------------------------------
api_token = request.getParameter("apiToken").trim();
api_certNum = request.getParameter("certNum");
// 파라미터 유효성 검증
if( api_token.length() == 0 ){
goErrorPage("토큰값 비정상", request, response);
return kmcVO;
}
if( api_certNum.length() == 0 ){
goErrorPage("요청번호 비정상", request, response);
return kmcVO;
}
//현재시각 세팅(YYYYMMDDHI24MISS)
Calendar today = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
String api_date = sdf.format(today.getTime());
//01. 암호화 모듈 (jar) Loading
com.icert.comm.secu.IcertSecuManager seed = new com.icert.comm.secu.IcertSecuManager();
//api_token, api_certNum 복호화
api_token = seed.getDec(api_token, "");
api_certNum = seed.getDec(api_certNum, "");
// 파라미터 유효성 검증
if( api_token.length() == 0 ){
goErrorPage("토큰값 비정상(복호화 후)", request, response);
return kmcVO;
}
if( api_certNum.length() == 0 ){
goErrorPage("요청번호 비정상(복호화 후)", request, response);
return kmcVO;
}
// 1. URL 설정
String serverURL = "https://www.kmcert.com/kmcis/api/kmcisToken_api.jsp";
// 2. 연결 생성
URL url = new URL(serverURL);
// 3. HttpURLConnection 객체 생성.
HttpURLConnection con = null;
OutputStream wr = null;
BufferedReader bufferedReader = null;
// 4. URL 연결 (웹페이지 URL 연결.)
con = (HttpURLConnection)url.openConnection();
con.setConnectTimeout(20000); // TimeOut 시간 (서버 접속시 연결 시간 - 20초)
con.setReadTimeout(20000); // TimeOut 시간 (Read시 연결 시간 - 20초)
con.setDoOutput(true); // OutputStream으로 POST 데이터를 넘겨주겠다는 옵션.
con.setRequestProperty("Content-Type", "application/json;charset=utf-8"); // 타입설정(application/json) 형식으로 전송 (Request Body 전달시 application/json로 서버에 전달.)
con.setRequestProperty("Accept", "application/json"); // 서버 Response Data를 JSON 형식의 타입으로 요청.
con.setRequestMethod("POST"); // 요청 방식 선택 (POST)
// 5. JSON 전문 구성
JSONObject jsonData = new JSONObject();
jsonData.put("apiToken", api_token);
jsonData.put("apiDate", api_date);
message = jsonData.toString();
// 6. 전송
// Request Body에 Data를 담기위해 OutputStream 객체를 생성.
wr = con.getOutputStream();
// Request Body에 Data 셋팅.(한글깨짐 방지를 위해 utf-8인코딩 처리
wr.write(message.getBytes("utf-8"));
wr.flush();
wr.close();
// 실제 서버로 Request 요청 하는 부분. (응답 코드를 받는다. 200 성공, 나머지 에러)
int responseCode = con.getResponseCode();
// 4. 결과 수신
if(responseCode == 200){
bufferedReader = new BufferedReader(new InputStreamReader(con.getInputStream(), "UTF-8"));
}else{
bufferedReader = new BufferedReader(new InputStreamReader(con.getErrorStream(), "UTF-8"));
}
if(bufferedReader != null){
StringBuilder stringBuilder = new StringBuilder();
String line = "";
while((line = bufferedReader.readLine()) != null){
stringBuilder.append(line);
}
bufferedReader.close();
String stringRet = stringBuilder.toString();
// 5. 넘어온 문자열을 JSON 객체로 변환
JSONParser jsonParser = new JSONParser();
//JSON데이터를 넣어 JSON Object 로 만들어 준다.
JSONObject jsonObj = (JSONObject)jsonParser.parse(stringRet);
// 6. JSON 객체에서 데이터 가져오기
if(jsonObj.get("result_cd") != null){
result_cd = jsonObj.get("result_cd").toString();
if("APR01".equals(result_cd)){
//통신성공
strResult = "Y";
rec_cert = jsonObj.get("apiRecCert").toString();
k_certNum = jsonObj.get("apiCertNum").toString();
}else if("APR02".equals(result_cd)){
//실패 - Token Expire
strResult = "N";
result_msg = "실패 - Token Expire";
}else if("APR03".equals(result_cd)){
//실패 - Token Not Found
strResult = "N";
result_msg = "실패 - Token Not Found";
}else if("APR04".equals(result_cd)){
//실패 - API 요청일시 길이 오류
strResult = "N";
result_msg = "실패 - API 요청일시 길이 오류";
}else if("APR05".equals(result_cd)){
//실패 - API 토큰 길이 오류
strResult = "N";
result_msg = "실패 - API 토큰 길이 오류";
}else if("APR06".equals(result_cd)){
//실패 - 결과전송 재요청(3회 제한)
strResult = "N";
result_msg = "실패 - 결과전송 재요청(3회 제한)";
}
}else{
//JSON 결과코드 에러
strResult = "F";
}
}else{ //timeout except 처리
strResult = "F";
}
// 파라미터 유효성 검증
if(!strResult.equals("Y")){
goErrorPage("결과값 비정상, 결과코드["+result_cd+"], "+"상세내용["+result_msg+"]", request, response);
return kmcVO;
}
//02. 1차 복호화
rec_cert = seed.getDec(rec_cert, k_certNum);
//03. 1차 파싱
int inf1 = rec_cert.indexOf("/",0);
int inf2 = rec_cert.indexOf("/",inf1+1);
encPara = rec_cert.substring(0,inf1); //암호화된 통합 파라미터
encMsg1 = rec_cert.substring(inf1+1,inf2); //암호화된 통합 파라미터의 Hash값
//04. 위변조 검증
encMsg2 = seed.getMsg(encPara);
if(encMsg2.equals(encMsg1)){
msgChk="Y";
}
if(msgChk.equals("N")){
goErrorPage("비정상적인 접근입니다.!!", request, response);
return kmcVO;
}
//05. 2차 복호화
rec_cert = seed.getDec(encPara, "");
//06. 2차 파싱
int info1 = rec_cert.indexOf("/",0);
int info2 = rec_cert.indexOf("/",info1+1);
int info3 = rec_cert.indexOf("/",info2+1);
int info4 = rec_cert.indexOf("/",info3+1);
int info5 = rec_cert.indexOf("/",info4+1);
int info6 = rec_cert.indexOf("/",info5+1);
int info7 = rec_cert.indexOf("/",info6+1);
int info8 = rec_cert.indexOf("/",info7+1);
int info9 = rec_cert.indexOf("/",info8+1);
int info10 = rec_cert.indexOf("/",info9+1);
int info11 = rec_cert.indexOf("/",info10+1);
int info12 = rec_cert.indexOf("/",info11+1);
int info13 = rec_cert.indexOf("/",info12+1);
int info14 = rec_cert.indexOf("/",info13+1);
int info15 = rec_cert.indexOf("/",info14+1);
int info16 = rec_cert.indexOf("/",info15+1);
int info17 = rec_cert.indexOf("/",info16+1);
int info18 = rec_cert.indexOf("/",info17+1);
certNum = rec_cert.substring(0,info1);
date = rec_cert.substring(info1+1,info2);
CI = rec_cert.substring(info2+1,info3);
phoneNo = rec_cert.substring(info3+1,info4);
phoneCorp = rec_cert.substring(info4+1,info5);
birth = rec_cert.substring(info5+1,info6);
gender = rec_cert.substring(info6+1,info7);
nation = rec_cert.substring(info7+1,info8);
name = rec_cert.substring(info8+1,info9);
result = rec_cert.substring(info9+1,info10);
certMet = rec_cert.substring(info10+1,info11);
ip = rec_cert.substring(info11+1,info12);
reserve1 = rec_cert.substring(info12+1,info13);
reserve2 = rec_cert.substring(info13+1,info14);
reserve3 = rec_cert.substring(info14+1,info15);
reserve4 = rec_cert.substring(info15+1,info16);
plusInfo = rec_cert.substring(info16+1,info17);
DI = rec_cert.substring(info17+1,info18);
//07. CI, DI 복호화
CI = seed.getDec(CI, "");
DI = seed.getDec(DI, "");
// ----------------------------------------------------------------------------------
}catch(StringIndexOutOfBoundsException ex){
goErrorPage("StringIndexOutOfBoundsException", request, response);
}catch(NullPointerException ex){
goErrorPage("NullPointerException", request, response);
}catch(NumberFormatException ex){
goErrorPage("NumberFormatException", request, response);
}catch(IllegalStateException ex){
goErrorPage("IllegalStateException", request, response);
}catch(IndexOutOfBoundsException ex){
goErrorPage("IndexOutOfBoundsException", request, response);
} catch (IOException e) {
goErrorPage("IOException", request, response);
} catch (ParseException e) {
goErrorPage("ParseException", request, response);
}
return kmcVO;
}
private String getDomain(HttpServletRequest request) {
String serverNm = request.getScheme() + "://" + request.getServerName();
if(request.getServerPort() != 80
&& request.getServerPort() != 443) {
serverNm += ":" + request.getServerPort();
}
return serverNm;
}
private String getDay() {
Calendar today = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
String day = sdf.format(today.getTime());
return day;
}
private String getRanNum() {
Random ran = new Random();
//랜덤 문자 길이
int numLength = 6;
String randomStr = "";
for (int i = 0; i < numLength; i++) {
//0 ~ 9 랜덤 숫자 생성
randomStr += ran.nextInt(10);
}
return randomStr;
}
private MberCertPhoneVO setMberCertPhoneVO(
HttpServletRequest request
, MberCertPhoneVO mberCertPhoneVO
) {
mberCertPhoneVO.setUrl(mberCertPhoneVO.getTrUrl());
mberCertPhoneVO.setHost(getDomain(request));
MberCertPhoneVO tmpMberCertPhoneVO = new MberCertPhoneVO();
try {
tmpMberCertPhoneVO = certPhoneService.selectCertUrlCode(mberCertPhoneVO);
} catch (Exception e) {
System.out.println(e.getMessage());
}
if(tmpMberCertPhoneVO != null) {
mberCertPhoneVO.setUrl(tmpMberCertPhoneVO.getUrl());
mberCertPhoneVO.setHost(tmpMberCertPhoneVO.getHost());
mberCertPhoneVO.setUrlCode(tmpMberCertPhoneVO.getUrlCode());
}
return mberCertPhoneVO;
}
private void goErrorPage(String msg, HttpServletRequest request, HttpServletResponse response) throws IOException {
FlashMap flashMap = RequestContextUtils.getOutputFlashMap(request);
flashMap.put("msg", msg);
FlashMapManager flashMapManager = RequestContextUtils.getFlashMapManager(request);
flashMapManager.saveOutputFlashMap(flashMap, request, response);
response.sendRedirect("/web/cert/log/kmcErrorPage.do");
}
}