Java/Short 개발

[Java/Short] 마스킹(Masking) 적용 방법 : 이름, 휴대폰 번호, 이메일, 계좌번호, 주소

adjh54 2024. 7. 26. 23:35
반응형
해당 글에서는 파라미터로 전달 받은 데이터를 마스킹 처리하여 반환하는 방법에 대해 알아봅니다.


 

1) 마스킹(Masking)


💡 마스킹(Masking)

- 민감한 정보를 보호하기 위해 데이터를 숨기거나 부분적으로 가리는 기술입니다. 이는 개인 식별 정보(PII)와 같은 민감한 데이터를 안전하게 유지하는 데 사용됩니다.

- 예를 들어, 클라이언트가 사용자 정보를 서버로 요청하였을때, 응답값으로 노출이 될 수 있기에 클라이언트에게 전달을 할때 서버내에서 마스킹처리를 하여서 클라이언트로 사용자 정보를 반환해줍니다.

 
 
 

💡 [참고] 아래의 구성사항은..

- 해당 마스킹을 적용한 경우는 클라이언트로부터 어느정도 정재된 상태에 Java 서버로 전달된다는 가정하에 구성을 해보았습니다.
- 또한 '정규식'으로 마스킹 처리가 가능하지만 실제로 로직적으로 어떻게 처리되는지에 대해 확인해보기 위해 직접 코드로 구성하였습니다.

 

2) 이름 마스킹


💡 이름 마스킹

- 이름의 형태가 2자리, 3자리, 4자리, 5자리 이상의 문자열 형태를 가진다는 가정하에 이에 대한 마스킹을 수행합니다.
이름 길이마스킹 방법예시
2자리첫 번째 문자를 “*”로 마스킹이슬 → *슬
3자리두 번째 문자를 “*”로 마스킹홍길동 → 홍*동
4자리가운데 두 문자를 “*”로 마스킹독고재형 → 독**형
5자리 이상첫 번째, 마지막 문자를 제외하고 “*”로 마스킹크리스티나 → 크***나
@NoArgsConstructor
public class MaskingUtil {

    /**
     * 이름에 대한 마스킹을 수행합니다.
     *
     * @param name {String} : 마스킹 이전 이름
     * @return {String} 마스킹 이후 이름
     */
    public static String maskName(String name) {

        // 기본 형식에 맞지 않는 이름의 경우, 파라미터 값을 그대로 반환합니다.
        if (name == null || name.length() < 2) {
            return name;
        }

        int length = name.length();
        StringBuilder maskedName = new StringBuilder(name);

        // [CASE1] 이름이 2자리 인 경우 => 첫 번째 문자에 대해 마스킹
        if (length == 2) {
            maskedName.setCharAt(0, '*');
        }
        // [CASE2] 이름이 3자리 인 경우 => 두 번째 문자에 대해 마스킹
        else if (length == 3) {
            maskedName.setCharAt(1, '*');
        }
        // [CASE3] 이름이 4자리 인 경우 => 두 번째, 세 번째 문자에 대해 마스킹
        else if (length == 4) {
            maskedName.setCharAt(1, '*');
            maskedName.setCharAt(2, '*');
        }
        // [CASE4] 이름이 5자리 이상인 경우 => 첫 번째와 마지막 문자를 제외한 모든 문자에 대해 마스킹
        else if (length == 5) {
            maskedName.setCharAt(1, '*');
            maskedName.setCharAt(2, '*');
            maskedName.setCharAt(3, '*');
        }
        // [CASE5] 이름이 5자리 이상인 경우 => 첫 번째와 마지막 문자를 제외한 모든 문자에 대해 마스킹
        else {
            for (int i = 1; i < length - 1; i++) {
                maskedName.setCharAt(i, '*');
            }
        }

        return maskedName.toString();
    }

    public static void main(String[] args) {
        // 테스트 케이스
        System.out.println(maskName("이슬")); // *슬
        System.out.println(maskName("홍길동")); // 홍*동
        System.out.println(maskName("독고재형")); // 독**형
        System.out.println(maskName("홍길동김")); // 홍***김
        System.out.println(maskName("김철수박")); // 김***박
    }
}

 
 

3) 휴대폰 번호 마스킹


💡 휴대폰 번호 마스킹

- 하이픈이 포함되지 않은 휴대폰 번호의 경우 10자리 혹은 11자리를 가집니다. 이 중에서 가운데 3자리 혹은 4자리에 대해 마스킹 처리를 합니다.
- 하이픈이 포함된 경우는 휴대폰 번호의 경우에는 가운데 3자리 혹은 4자리에 대해 마스킹 처리를 합니다.
휴대번호 길이마스킹 방법예시
10자리가운데 3자리를 마스킹 처리합니다0101231234 → 010***1234
11자리가운데 4자리를 마스킹 처리합니다01012341234 → 010****1234
10자리에 하이픈 포함가운데 3자리를 마스킹 처리합니다.010-123-5678 → 010-***-5678
11자리에 하이픈 포함가운데 4자리를 마스킹 처리합니다.010-9876-5432 → 010-****-5432
@NoArgsConstructor
public class MaskingUtil {

    /**
     * 휴대폰 번호에 대한 마스킹을 수행합니다.
     *
     * @param phoneNumber {String}  마스킹 이전 휴대폰 번호
     * @return {String} 마스킹 된 휴대폰 번호
     */
    public static String maskPhoneNumber(String phoneNumber) {

        // 기본 형식에 맞지 않는 핸드폰 번호의 경우, 파라미터 값을 그대로 반환합니다.
        if (phoneNumber == null || phoneNumber.length() < 10) {
            return phoneNumber;
        }

        StringBuilder maskedPhoneNumber = new StringBuilder(phoneNumber);
        int length = phoneNumber.length();

        // [CASE1] 핸드폰 번호의 하이픈이 포함된 경우
        if (phoneNumber.contains("-")) {
            String[] parts = phoneNumber.split("-");
            if (parts.length == 3) {

                // [CASE2-1] 가운데 번호가 3자리인 경우
                if (parts[1].length() == 3) {
                    maskedPhoneNumber.replace(4, 7, "***");     // 가운데 3자리를 마스킹
                }
                // [CASE2-2] 가운데 번호가 4자리인 경우
                else if (parts[1].length() == 4) {
                    maskedPhoneNumber.replace(4, 8, "****");    // 가운데 4자리를 마스킹
                }
            }

        }
        // [CASE2] 핸드폰 번호의 하이픈이 포함되지 않은 경우
        else {
            // [CASE2-1] 가운데 번호가 3자리인 경우
            if (length == 10) {
                maskedPhoneNumber.replace(3, 6, "***");     // 가운데 3자리를 마스킹
            }
            // [CASE2-2] 가운데 번호가 4자리인 경우
            else if (length == 11) {
                maskedPhoneNumber.replace(3, 7, "****");    // 가운데 4자리를 마스킹
            }
        }
        return maskedPhoneNumber.toString();
    }

    public static void main(String[] args) {
        // 테스트 케이스
        System.out.println(maskPhoneNumber("0101231234")); // 010***1234
        System.out.println(maskPhoneNumber("01012341234")); // 010****1234
        System.out.println(maskPhoneNumber("010-123-5678")); // 010-***-5678
        System.out.println(maskPhoneNumber("010-9876-5432")); // 010-****-5432
    }
}

 
 
 

4) 이메일 마스킹


💡 이메일 마스킹

- 이메일의 아이디는 일반적으로 4자리 이상을 사용하기를 권장하기에 해당 기준에 맞추어서 마스킹을 진행합니다.
- 아이디가 3자리 이하인 경우는 그대로 반환하고, 4자리 이상인 경우는 아이디의 앞의 3자리를 제외하고 모두 마스킹 처리를 합니다.
이메일 마스킹이메일 마스킹 방법예시
3자리 이하그대로 출력을 합니다man@naver.com → man@naver.com
4자리 이상아이디의 앞의 3자리를 제외하고 모두 마스킹 처리를 합니다.adjh54@naver.com → adj***@naver.com
import lombok.NoArgsConstructor;

@NoArgsConstructor
public class MaskingUtil {

    /**
     * 이메일 주소에 대한 마스킹을 수행합니다.
     *
     * @param email {String} : 마스킹 이전 이메일 주소
     * @return {String} 마스킹 된 이메일 주소
     */
    public static String maskEmail(String email) {

        // 기본 형식에 맞지 않는 이메일 주소의 경우, 파라미터 값을 그대로 반환합니다.
        if (email == null || !email.contains("@")) {
            return email;
        }

        String[] parts = email.split("@");
        String idPart = parts[0];           // 아이디
        String domainPart = parts[1];       // 이메일 도메인

        // 기본 형식에 맞지 않는 이메일 주소의 경우, 파라미터 값을 그대로 반환합니다.
        if (idPart.length() <= 3) {
            return email;
        }

        StringBuilder maskedEmail = new StringBuilder();
        maskedEmail.append(idPart.substring(0, 3));
        for (int i = 3; i < idPart.length(); i++) {
            maskedEmail.append('*');
        }
        maskedEmail.append('@').append(domainPart);

        return maskedEmail.toString();
    }

    public static void main(String[] args) {
        // 테스트 케이스
        System.out.println(maskEmail("test@example.com")); // tes****@example.com
        System.out.println(maskEmail("myemail@domain.com")); // mye*****@domain.com
        System.out.println(maskEmail("abc@xyz.com")); // abc@xyz.com
    }
}

 
 
 

5) 계좌번호 마스킹


💡 계좌번호 마스킹

- 계좌번호 마스킹의 경우 정해진 계좌번호의 길이는 없지만, 앞 뒤 3자리씩 남겨두고 중간에 숫자를 마스킹 처리를 합니다.
계좌번호 길이계좌번호 마스킹 방법예시
3자리3자리 계좌번호는 존재하지 않기에 그대로 반환합니다.123 → 123
4자리 이상앞의 자리 3글자와 뒤에 3글자를 제외하고 모두 “*”으로 마스킹1234567890 → 123****890
import lombok.NoArgsConstructor;

@NoArgsConstructor
public class MaskingUtil {

    /**
     * 계좌번호에 대한 마스킹을 수행합니다.
     *
     * @param accountNumber {String} : 마스킹 이전 계좌번호
     * @return {String} 마스킹 된 계좌번호
     */
    public static String maskAccountNumber(String accountNumber) {

        // 기본 형식에 맞지 않는 계좌번호의 경우, 파라미터 값을 그대로 반환합니다.
        if (accountNumber == null || accountNumber.length() < 7) {
            return accountNumber;
        }

        int length = accountNumber.length();
        StringBuilder maskedAccount = new StringBuilder(accountNumber);

        // 계좌번호의 앞 3자리와 마지막 3자리를 제외한 부분을 마스킹
        for (int i = 3; i < length - 3; i++) {
            maskedAccount.setCharAt(i, '*');
        }

        return maskedAccount.toString();
    }

    public static void main(String[] args) {
        // 테스트 케이스
        System.out.println(maskAccountNumber("1234567890")); // 123****890
        System.out.println(maskAccountNumber("987654321")); // 987**321
        System.out.println(maskAccountNumber("1234567")); // 123*567
    }
}

 
 
 

6) 주소 마스킹


 💡 주소 마스킹

- 주소 마스킹의 경우, 상세 주소를 제외한 나머지 주소를 마스킹 처리합니다.
- 예를 들어, 도로명이나 건물번호는 그대로 두고, 상세 주소는 마스킹합니다. 
주소 마스킹 길이주소 마스킹 방법예시
상세 주소 포함도로명/건물번호를 제외하고 상세 주소를 마스킹서울특별시 강남구 테헤란로 123 ABC빌딩 101호 → 서울특별시 강남구 테헤란로 123 ABC빌딩 ***호
import lombok.NoArgsConstructor;

@NoArgsConstructor
public class MaskingUtil {

    /**
     * 주소에 대한 마스킹을 수행합니다.
     *
     * @param address {String} : 마스킹 이전 주소
     * @return {String} 마스킹 된 주소
     */
    public static String maskAddress(String address) {

        // 기본 형식에 맞지 않는 주소의 경우, 파라미터 값을 그대로 반환합니다.
        if (address == null || address.length() < 10) {
            return address;
        }

        // 주소를 공백 기준으로 나눔
        String[] parts = address.split(" ");

        // 상세 주소를 마스킹
        StringBuilder maskedAddress = new StringBuilder();
        for (int i = 0; i < parts.length - 1; i++) {
            maskedAddress.append(parts[i]).append(" ");
        }
        maskedAddress.append("***");

        return maskedAddress.toString();
    }

    public static void main(String[] args) {
        // 테스트 케이스
        System.out.println(maskAddress("서울특별시 강남구 테헤란로 123 ABC빌딩 101호")); // 서울특별시 강남구 테헤란로 123 ABC빌딩 ***호
        System.out.println(maskAddress("부산광역시 해운대구 해운대로 456 XYZ아파트 202호")); // 부산광역시 해운대구 해운대로 456 XYZ아파트 ***호
    }
}

 
 
 

💡 [참고] 해당 전체 내용은 아래의 Github Repository 내에서 확인이 가능합니다.

blog-codes/spring-boot-common/src/main/java/com/adjh/springbootcommon/commons/utils/MaskingUtils.java at main · adjh54ir/blog-c

Contributor9 티스토리 블로그 내에서 활용한 내용들을 담은 레포지토리입니다. Contribute to adjh54ir/blog-codes development by creating an account on GitHub.

github.com

 
 
 
오늘도 감사합니다. 😀
 
 
 
 

반응형