DJBank 암복호화필터 설계

- 기관별 InCryptoFilter를 상속한 필터 설계
- 기관별 OutCryptoFilter를 상송한 필터 설계
- 대상 기관 : 카카오뱅크, 카카오페이, 네이버Fn, 토스뱅크, 제주은행, DJErp
This commit is contained in:
curry772
2026-05-26 09:51:53 +09:00
parent 13608ebc8e
commit 1f285c3bfd
15 changed files with 321 additions and 403 deletions
@@ -0,0 +1,53 @@
package com.eactive.eai.custom.adapter.http.client.impl.filter;
import java.util.Properties;
import com.eactive.eai.adapter.http.client.impl.filter.HttpClientAdapterFilter;
import com.eactive.eai.adapter.http.client.impl.filter.OutCryptoFilter;
import com.eactive.eai.common.security.keyderiv.KeyDerivationStrategy;
/**
* DJBank 더존 연동 암복호화 필터
* 전문에서 groupSeq, empSeq를 추출한다.
* 암복호화 키 생성에 HSM에서 master key를 가져오고, groupSeq를 조합
* empSeq는 AES GCM의 AAD로 사용(PROP_AAD_HEADER prop 세팅)
*
*/
public class DJBErpEncFieldOutCryptoFilter implements HttpClientAdapterFilter {
private final OutCryptoFilter filter = new OutCryptoFilter();
@Override
public Object doPreFilter(String adptGrpName, String adptName, Properties prop, Object message, Properties tempProp)
throws Exception {
setContext(tempProp);
return filter.doPreFilter(adptGrpName, adptName, prop, message, setProp(tempProp));
}
@Override
public Object doPostFilter(String adptGrpName, String adptName, Properties prop, Object message,
Properties tempProp) throws Exception {
setContext(tempProp);
return filter.doPostFilter(adptGrpName, adptName, prop, message, setProp(tempProp));
}
private void setContext(Properties tempProp) {
String empSeq = "";
//TODO : empSeq 추출
tempProp.setProperty(OutCryptoFilter.PROP_AAD_HEADER, empSeq);
String groupSeq = "";
//TODO : groupSeq 추출
tempProp.setProperty(KeyDerivationStrategy.PARAM_CONTEXT_KEY, groupSeq);
}
private Properties setProp(Properties p) {
p.setProperty(OutCryptoFilter.PROP_DEC_FROM_PATH, "/encryptedData");
p.setProperty(OutCryptoFilter.PROP_ENC_TO_PATH, "/encryptedData");
return p;
}
}
@@ -0,0 +1,31 @@
package com.eactive.eai.custom.adapter.http.client.impl.filter;
import java.util.Properties;
import com.eactive.eai.adapter.http.client.impl.filter.HttpClientAdapterFilter;
import com.eactive.eai.adapter.http.client.impl.filter.OutCryptoFilter;
/**
* 제주은행 Open API 기본 암복호화 필더
*/
public class EncFieldOutCryptoFilter implements HttpClientAdapterFilter {
private final OutCryptoFilter filter = new OutCryptoFilter();
protected Properties setProp(Properties p) {
p.setProperty(OutCryptoFilter.PROP_DEC_FROM_PATH, "/encryptedData");
p.setProperty(OutCryptoFilter.PROP_ENC_TO_PATH, "/encryptedData");
return p;
}
@Override
public Object doPreFilter(String adptGrpName, String adptName, Properties prop, Object message, Properties tempProp)
throws Exception {
return filter.doPreFilter(adptGrpName, adptName, prop, message, setProp(tempProp));
}
@Override
public Object doPostFilter(String adptGrpName, String adptName, Properties prop, Object message,
Properties tempProp) throws Exception {
return filter.doPostFilter(adptGrpName, adptName, prop, message, setProp(tempProp));
}
}
@@ -0,0 +1,17 @@
package com.eactive.eai.custom.adapter.http.client.impl.filter;
import java.util.Properties;
import com.eactive.eai.adapter.http.client.impl.filter.OutCryptoFilter;
/**
* TODO : 업체 암복호화에 맟추어 커스텀 필요
*/
public class JejubankEncFieldOutCryptoFilter extends EncFieldOutCryptoFilter {
protected Properties setProp(Properties p) {
p.setProperty(OutCryptoFilter.PROP_DEC_FROM_PATH, "/encrypted_data");
p.setProperty(OutCryptoFilter.PROP_ENC_TO_PATH, "/encrypted_data");
return p;
}
}
@@ -0,0 +1,18 @@
package com.eactive.eai.custom.adapter.http.client.impl.filter;
import java.util.Properties;
import com.eactive.eai.adapter.http.client.impl.filter.OutCryptoFilter;
/**
* TODO : 업체 암복호화에 맟추어 커스텀 필요
*/
public class KakaobankEncFieldOutCryptoFilter extends EncFieldOutCryptoFilter {
protected Properties setProp(Properties p) {
p.setProperty(OutCryptoFilter.PROP_DEC_FROM_PATH, "/encrypted_data");
p.setProperty(OutCryptoFilter.PROP_ENC_TO_PATH, "/encrypted_data");
return p;
}
}
@@ -0,0 +1,17 @@
package com.eactive.eai.custom.adapter.http.client.impl.filter;
import java.util.Properties;
import com.eactive.eai.adapter.http.client.impl.filter.OutCryptoFilter;
/**
* TODO : 업체 암복호화에 맟추어 커스텀 필요
*/
public class KakaopayEncFieldOutCryptoFilter extends EncFieldOutCryptoFilter {
protected Properties setProp(Properties p) {
p.setProperty(OutCryptoFilter.PROP_DEC_FROM_PATH, "/encryptedData");
p.setProperty(OutCryptoFilter.PROP_ENC_TO_PATH, "/encryptedData");
return p;
}
}
@@ -0,0 +1,18 @@
package com.eactive.eai.custom.adapter.http.client.impl.filter;
import java.util.Properties;
import com.eactive.eai.adapter.http.client.impl.filter.OutCryptoFilter;
/**
* TODO : 업체 암복호화에 맟추어 커스텀 필요
*/
public class NaverfincorpEncFieldOutCryptoFilter extends EncFieldOutCryptoFilter {
protected Properties setProp(Properties p) {
p.setProperty(OutCryptoFilter.PROP_DEC_FROM_PATH, "/encryptedData");
p.setProperty(OutCryptoFilter.PROP_ENC_TO_PATH, "/encryptedData");
return p;
}
}
@@ -0,0 +1,17 @@
package com.eactive.eai.custom.adapter.http.client.impl.filter;
import java.util.Properties;
import com.eactive.eai.adapter.http.client.impl.filter.OutCryptoFilter;
/**
* TODO : 업체 암복호화에 맟추어 커스텀 필요
*/
public class TossbankEncFieldOutCryptoFilter extends EncFieldOutCryptoFilter {
protected Properties setProp(Properties p) {
p.setProperty(OutCryptoFilter.PROP_DEC_FROM_PATH, "/encryptedData");
p.setProperty(OutCryptoFilter.PROP_ENC_TO_PATH, "/encryptedData");
return p;
}
}
@@ -1,82 +0,0 @@
package com.eactive.eai.custom.adapter.http.dynamic.filter;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import com.eactive.eai.adapter.http.dynamic.filter.InCryptoFilter;
import com.eactive.eai.util.JsonPathUtil;
/**
* DJB ERP 연동용 암복호화 필터.
*
* DYNAMIC 키 컨텍스트 추출 규칙:
* HTTP 헤더 {@code httpHeaderGroup}의 값은 JSON 객체이며,
* 그 중 {@code x-emp-nm} 필드 값을 {@code groupSeq}로
* runtimeContext에 담아 키 도출 전략에 전달한다.
*
* 어댑터 프로퍼티 (부모 클래스 공통 설정 외 추가 키):
* crypto.context.key runtimeContext에 넣을 키 이름 (기본: groupSeq)
* crypto.context.header 컨텍스트 JSON이 담긴 HTTP 헤더명 (기본: httpHeaderGroup)
* crypto.context.header.field 헤더 JSON에서 추출할 필드명 (기본: x-emp-nm)
*
* 어댑터 프로퍼티 설정 예:
* crypto.module.name = AES_GCM_NoPadding_DYNAMIC_sample
* crypto.scope = FIELD
* crypto.dec.enabled = Y
* crypto.enc.enabled = N
* crypto.dec.from.path = /encryptedData
* crypto.dec.to.path = /
* crypto.context.key = groupSeq
* crypto.context.header = httpHeaderGroup
* crypto.context.header.field = x-emp-nm
*
* 필터 타입 등록 (FQCN):
* com.eactive.eai.custom.adapter.http.dynamic.filter.DJBErpCryptoFilter
*/
public class DJBErpCryptoFilter extends InCryptoFilter {
public static final String PROP_CONTEXT_KEY = "crypto.context.key";
public static final String PROP_CONTEXT_HEADER = "crypto.context.header";
public static final String PROP_CONTEXT_HEADER_FIELD = "crypto.context.header.field";
private static final String DEFAULT_CONTEXT_KEY = "groupSeq";
private static final String DEFAULT_CONTEXT_HEADER = "httpHeaderGroup";
private static final String DEFAULT_CONTEXT_HEADER_FIELD = "x-emp-nm";
/**
* httpHeaderGroup 헤더(JSON)에서 x-emp-nm 값을 추출하여 groupSeq로 매핑한다.
* 헤더가 없거나 필드를 찾을 수 없으면 빈 Map을 반환한다.
*/
@Override
protected Map<String, String> buildRuntimeContext(Properties prop, HttpServletRequest request) {
Map<String, String> ctx = new HashMap<>();
String contextKey = prop.getProperty(PROP_CONTEXT_KEY, DEFAULT_CONTEXT_KEY);
String contextHeaderName = prop.getProperty(PROP_CONTEXT_HEADER, DEFAULT_CONTEXT_HEADER);
String contextHeaderField = prop.getProperty(PROP_CONTEXT_HEADER_FIELD, DEFAULT_CONTEXT_HEADER_FIELD);
String headerJson = request.getHeader(contextHeaderName);
if (StringUtils.isBlank(headerJson)) {
logger.warn("DJBErpCryptoFilter] 컨텍스트 헤더 없음: " + contextHeaderName);
return ctx;
}
String value = JsonPathUtil.getValueAtPath(headerJson, "/" + contextHeaderField);
if (value == null) {
logger.warn("DJBErpCryptoFilter] 헤더 JSON에서 필드 추출 실패: header="
+ contextHeaderName + ", field=" + contextHeaderField);
return ctx;
}
// x-emp-nm 값은 "groupSeq|empNo" 형태 — '|' 앞부분만 groupSeq로 사용
String groupSeq = value.contains("|") ? value.substring(0, value.indexOf('|')) : value;
ctx.put(contextKey, groupSeq);
return ctx;
}
}
@@ -0,0 +1,74 @@
package com.eactive.eai.custom.adapter.http.dynamic.filter;
import java.util.Properties;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.eactive.eai.adapter.http.client.impl.filter.OutCryptoFilter;
import com.eactive.eai.adapter.http.dynamic.filter.HttpAdapterFilter;
import com.eactive.eai.adapter.http.dynamic.filter.InCryptoFilter;
import com.eactive.eai.common.security.keyderiv.KeyDerivationStrategy;
/**
* DJB ERP 연동용 암복호화 필터.
*
* DYNAMIC 키 컨텍스트 추출 규칙:
* HTTP 헤더 {@code httpHeaderGroup}의 값은 JSON 객체이며,
* 그 중 {@code x-emp-nm} 필드 값을 {@code groupSeq}로
* runtimeContext에 담아 키 도출 전략에 전달한다.
*
* 어댑터 프로퍼티 (부모 클래스 공통 설정 외 추가 키):
* crypto.context.key runtimeContext에 넣을 키 이름 (기본: groupSeq)
* crypto.context.header 컨텍스트 JSON이 담긴 HTTP 헤더명 (기본: httpHeaderGroup)
* crypto.context.header.field 헤더 JSON에서 추출할 필드명 (기본: x-emp-nm)
*
* 어댑터 프로퍼티 설정 예:
* crypto.module.name = AES_GCM_NoPadding_DYNAMIC_sample
* crypto.scope = FIELD
* crypto.dec.enabled = Y
* crypto.enc.enabled = N
* crypto.dec.from.path = /encryptedData
* crypto.dec.to.path = /
* crypto.context.key = groupSeq
* crypto.context.header = httpHeaderGroup
* crypto.context.header.field = x-emp-nm
*
* 필터 타입 등록 (FQCN):
* com.eactive.eai.custom.adapter.http.dynamic.filter.DJBErpCryptoFilter
*/
public class DJBErpEncFieldInCryptoFilter implements HttpAdapterFilter {
private final InCryptoFilter filter = new InCryptoFilter();
protected Properties setProp(Properties p) {
p.setProperty(InCryptoFilter.PROP_DEC_FROM_PATH, "/encryptedData");
p.setProperty(InCryptoFilter.PROP_ENC_TO_PATH, "/encryptedData");
return p;
}
private void setContext(Properties tempProp) {
String empSeq = "";
// TODO : empSeq 추출
tempProp.setProperty(InCryptoFilter.PROP_AAD_HEADER, empSeq);
String groupSeq = "";
// TODO : groupSeq 추출
tempProp.setProperty(KeyDerivationStrategy.PARAM_CONTEXT_KEY, groupSeq);
}
@Override
public Object doPreFilter(String adptGrpName, String adptName, Object message, Properties prop,
HttpServletRequest request, HttpServletResponse response) throws Exception {
setContext(prop);
return filter.doPreFilter(adptGrpName, adptName, message, setProp(prop), request, response);
}
@Override
public Object doPostFilter(String adptGrpName, String adptName, Object resultMessage, Properties prop,
HttpServletRequest request, HttpServletResponse response) throws Exception {
setContext(prop);
return filter.doPostFilter(adptGrpName, adptName, resultMessage, setProp(prop), request, response);
}
}
@@ -9,12 +9,12 @@ import com.eactive.eai.adapter.http.dynamic.filter.InCryptoFilter;
import com.eactive.eai.adapter.http.dynamic.filter.HttpAdapterFilter;
/**
* CryptoFilter 프로퍼티 멤버변수로 관리하는 HttpAdapterFilter 구현체.
* InCryptoFilter 멤버변수로 관리하는 HttpAdapterFilter 구현체.
*
* 멤버변수에 세팅된 값을 Properties로 변환하여 {@link InCryptoFilter} 위임한다.
* 값이 blank인 멤버변수는 Properties에 포함하지 않으며, CryptoFilter의 기본값이 적용된다.
* 값이 blank인 멤버변수는 Properties에 포함하지 않으며, InCryptoFilter의 기본값이 적용된다.
*/
public class EncFieldCryptoFilter implements HttpAdapterFilter {
public class EncFieldInCryptoFilter implements HttpAdapterFilter {
private final InCryptoFilter filter = new InCryptoFilter();
@@ -30,7 +30,7 @@ public class EncFieldCryptoFilter implements HttpAdapterFilter {
return filter.doPostFilter(adptGrpName, adptName, resultMessage, setProp(prop), request, response);
}
private Properties setProp(Properties p) {
protected Properties setProp(Properties p) {
p.setProperty(InCryptoFilter.PROP_DEC_FROM_PATH, "/encryptedData");
p.setProperty(InCryptoFilter.PROP_ENC_TO_PATH, "/encryptedData");
return p;
@@ -0,0 +1,18 @@
package com.eactive.eai.custom.adapter.http.dynamic.filter;
import java.util.Properties;
import com.eactive.eai.adapter.http.dynamic.filter.InCryptoFilter;
/**
* TODO : 업체 암복호화에 맟추어 커스텀 필요
*/
public class KakaobankEncFieldInCryptoFilter extends EncFieldInCryptoFilter {
protected Properties setProp(Properties p) {
p.setProperty(InCryptoFilter.PROP_DEC_FROM_PATH, "/encrypted_data");
p.setProperty(InCryptoFilter.PROP_ENC_TO_PATH, "/encrypted_data");
return p;
}
}
@@ -0,0 +1,18 @@
package com.eactive.eai.custom.adapter.http.dynamic.filter;
import java.util.Properties;
import com.eactive.eai.adapter.http.dynamic.filter.InCryptoFilter;
/**
* TODO : 업체 암복호화에 맟추어 커스텀 필요
*/
public class KakaopayEncFieldInCryptoFilter extends EncFieldInCryptoFilter {
protected Properties setProp(Properties p) {
p.setProperty(InCryptoFilter.PROP_DEC_FROM_PATH, "/encrypted_data");
p.setProperty(InCryptoFilter.PROP_ENC_TO_PATH, "/encrypted_data");
return p;
}
}
@@ -0,0 +1,18 @@
package com.eactive.eai.custom.adapter.http.dynamic.filter;
import java.util.Properties;
import com.eactive.eai.adapter.http.dynamic.filter.InCryptoFilter;
/**
* TODO : 업체 암복호화에 맟추어 커스텀 필요
*/
public class NaverfincorpEncFieldInCryptoFilter extends EncFieldInCryptoFilter {
protected Properties setProp(Properties p) {
p.setProperty(InCryptoFilter.PROP_DEC_FROM_PATH, "/encryptedData");
p.setProperty(InCryptoFilter.PROP_ENC_TO_PATH, "/encryptedData");
return p;
}
}
@@ -0,0 +1,18 @@
package com.eactive.eai.custom.adapter.http.dynamic.filter;
import java.util.Properties;
import com.eactive.eai.adapter.http.dynamic.filter.InCryptoFilter;
/**
* TODO : 업체 암복호화에 맟추어 커스텀 필요
*/
public class TossbankEncFieldInCryptoFilter extends EncFieldInCryptoFilter {
protected Properties setProp(Properties p) {
p.setProperty(InCryptoFilter.PROP_DEC_FROM_PATH, "/encryptedData");
p.setProperty(InCryptoFilter.PROP_ENC_TO_PATH, "/encryptedData");
return p;
}
}