IT/Front-End
데이터(Data) 마스킹(Masking) 처리하기
라임웨일
2022. 8. 2. 10:54
반응형
Api를 통해서 받아온 사용자의 데이터를 노출할 때 정보보호를 위해 특정 데이터는 전체를 보여주지 않고 일부를 가려서(Masking) 보여줘야 하는 경우가 발생합니다.
가장 좋은 방법은 Back-End서버에서 데이터가 가공처리되어 전달하고 Front에서는 전달받은 데이터를 화면에 그대로 노출시켜 주는 게 가장 좋은 방법이지만 상황에 따라서 Front에서 데이터를 가공해야 할 경우도 발생합니다. 이럴 때 공통 마스킹 Function을 만들어서 사용하면 굉장히 유용하게 사용할 수 있습니다.
💡 마스킹 처리 함수
/********************************************
* 공통 마스킹
* checkNull : 데이터 Check => 공백 | undefined | null
*
* ※) 이메일 마스킹
* ex 1) emailEndHide
* 원본 데이터 : abcdefg12345@naver.com, 변경 데이터 : ab**********@naver.com
* ex 2) emailEndShow
* 원본 데이터 : abcdefg12345@naver.com, 변경 데이터 : ab**********@naver.com
*
* ※) 휴대폰 번호 마스킹
* ex1) 원본 데이터 : 01012345678, 변경 데이터 : 010****5678
* ex2) 원본 데이터 : 010-1234-5678, 변경 데이터 : 010-****-5678
* ex3) 원본 데이터 : 0111234567, 변경 데이터 : 011***4567
* ex4) 원본 데이터 : 011-123-4567, 변경 데이터 : 011-***-4567
*
* ※) 주민번호 resident
* ex1) 원본 데이터 : 990101-1234567, 변경 데이터 : 990101-1******
* ex2) 원본 데이터 : 9901011234567, 변경 데이터 : 9901011******
*
* ※) 이름 마스킹
* ex1) 원본 데이터 : 김철수, 변경 데이터 : 김철*
* ex2) 원본 데이터 : 대한민국, 변경 데이터 : 대한**
* ex3) 원본 데이터 : 한국, 변경 데이터 : 한*
*
* * ※) 계좌번호 마스킹
* 자리수에 따라서 마스킹 노출 다름 : substring 변경
*********************************************/
let maskingFunc = {
checkNull: function (str) {
if (typeof str === "undefined" || str === null || str === "") {
return true;
}
else {
return false;
}
},
emailEndHide: function (str) {
let emailStr = str.match(/([a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+)/gi);
if (this.checkNull(str)) {
return str;
}
let strLength = emailStr.toString().split('@')[0].length - 4;
return str.toString().replace(new RegExp('.(?=.{0,' + strLength + '}@)', 'g'), '*').replace(/.{6}$/, "******");
},
emailEndShow: function (str) {
let emailStr = str.match(/([a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+)/gi);
if (this.checkNull(str) == true || this.checkNull(emailStr) == true) {
return str;
}
let strLength = emailStr.toString().split('@')[0].length - 4;
return str.toString().replace(new RegExp('.(?=.{0,' + strLength + '}@)', 'g'), '*');
},
phone: function (str) {
let phoneStr;
let maskingStr;
if (this.checkNull(str)) {
return str;
}
// 1) -가 없는 경우
if (str.toString().split('-').length != 3) {
phoneStr = str.length < 11 ? str.match(/\d{10}/gi) : str.match(/\d{11}/gi);
if (str.length < 11) {
maskingStr = str.toString().replace(phoneStr, phoneStr.toString().replace(/(\d{3})(\d{3})(\d{4})/gi, '$1***$3'));
}
else {
maskingStr = str.toString().replace(phoneStr, phoneStr.toString().replace(/(\d{3})(\d{4})(\d{4})/gi, '$1****$3'));
}
}
// 2) -가 있는 경우
else {
phoneStr = str.match(/\d{2,3}-\d{3,4}-\d{4}/gi);
if (/-[0-9]{3}-/.test(phoneStr)) {
maskingStr = str.toString().replace(phoneStr, phoneStr.toString().replace(/-[0-9]{3}-/g, "-***-"));
} else if (/-[0-9]{4}-/.test(phoneStr)) { // 2.2) 00-0000-0000
maskingStr = str.toString().replace(phoneStr, phoneStr.toString().replace(/-[0-9]{4}-/g, "-****-"));
}
}
return maskingStr;
},
resident: function (str) {
let residentStr;
let maskingStr;
if (this.checkNull(str)) {
return str;
}
// - 이 있는 경우
if (str.length === 14) {
residentStr = str.match(/(?:[0-9]{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[1,2][0-9]|3[0,1]))-[1-4]{1}[0-9]{6}\b/gi);
maskingStr = str.toString().replace(residentStr, residentStr.toString().replace(/(-?)([1-4]{1})([0-9]{6})\b/gi, "$1$2******"));
}
// - 이 없는 경우
if (str.length === 13) {
residentStr = str.match(/\d{13}/gi);
maskingStr = str.toString().replace(residentStr, residentStr.toString().replace(/([0-9]{6})$/gi, "******"));
}
return maskingStr;
},
name: function (str) {
let maskingStr;
if (this.checkNull(str)) {
return str;
}
if (str.length < 3) {
maskingStr = str.replace(/(?<=.{1})./gi, "*");
}
if (str.length === 3) {
maskingStr = str.replace(/(?<=.{2})./gi, "*");
}
if (str.length > 3) {
maskingStr = str.replace(/(?<=.{2})./gi, "*");
}
return maskingStr;
},
account: function (str) {
let maskingStr;
if (this.checkNull(str) == true) {
return str;
}
if (str.length <= 8) {
maskingStr =
str.substring(0, 2) +
str.substring(3, 7).replace(/[0-9a-zA-Z]/g, '*') +
str.substring(6, str.length);
} else if (str.length >= 9 && str.length <= 10) {
maskingStr =
str.substring(0, 2) +
str.substring(3, 8).replace(/[0-9a-zA-Z]/g, '*') +
str.substring(7, str.length);
} else if (str.length > 10) {
maskingStr =
str.substring(0, 3) +
str.substring(3, 8).replace(/[0-9a-zA-Z]/g, '*') +
str.substring(8, str.length);
}
return maskingStr;
},
}
✔ 사용 예시
maskingFunc.emailEndHide("abcdefg12345@naver.com"); // "abc*********@nav******"
maskingFunc.emailEndShow("abcdefg12345@naver.com"); // "abc*********@naver.com"
maskingFunc.phone("0111234567"); // "011***4567"
maskingFunc.phone("011-123-4567"); // "011-***-4567"
maskingFunc.phone("01012345678"); // "010****5678"
maskingFunc.phone("010-1234-5678"); // "010-****-5678"
maskingFunc.resident("9901011234567"); // "9901011******"
maskingFunc.resident("990101-1234567"); // "990101-1******"
maskingFunc.name("한국"); // "한*"
maskingFunc.name("김철수"); // "김철*"
maskingFunc.name("대한민국"); // "대한**"
maskingFunc.account("1233333333333"); // "123*****33333"
✔ 반복문에서 사용 예시
반복문에서도 사용가능하고 React처럼 Render가 이루어지고 화면이 그려지는 경우에도 마스킹 함수를 만들어놓고 아래 예시처럼 사용하면 정상적으로 데이터가 마스킹 처리되어 화면에 보여집니다.
{userData.map((item, idx) => (
<tr>
<td>{item.name}</td>
<td>{maskingFunc.account(item.account)}</td>
</tr>
))}
반응형