주식회사 누리아이티

정보자산의 보안강화를 위한 3단계 인증 보안SW(BaroPAM) 전문기업인 누리아이티

▶ BaroSolution/가이드

보안 강화를 위한 중간자 공격, 제한된 시간 및 횟수에 의하여 잠금 기능 및 일회용 인증키 검증하는 프로그래밍 가이드

누리아이티 2020. 5. 4. 14:25

1. 개요

 

WAS(Web Application Server)에서 BaroPAM간 인증 프로그램 가이드는 어플리케이션 로그인/인증 시 비밀번호를 대체/인증하기 위한 중간자 공격(Man-in-the-middle attack, 양자간의 통신에 누군가가 개입하여, 도청이나 변경을 행하는 수법으로 로그 인 계정이나 개인정보의 도난, 스파이 행위, 통신 방해, 데이터 변경 등에 사용됨), 제한된 시간 및 횟수에 의하여 잠금 기능일회용 인증키를 검증하는 기능을 제공한다.

 

 

2. BaroPAM 모듈(barokey.jar)

 

어플리케이션 로그인/인증 시 비밀번호를 대체/인증하기 위한 중간자 공격(Man-in-the-middle attack), 제한된 시간 및 횟수에 의하여 잠금 기능일회용 인증키를 검증하는 API "barokey.jar"로 제공되며, WAS "~/WEB-INF/lib" 디렉토리에 "barokey.jar"를 위치 시켜야 한다.

 

/home/tomcat/webapps/ROOT/WEB-INF/lib > ls -al barokey.jar
-rw-r--r-- 1 root root 6746 12 29 07:43 barokey.jar

 

 

2.1 verifyKEYL 함수

 

- NAME

  verifyKEYL

 

- SYNOPSIS

  boolean bauth_key = barokey.verifyKEYL(String login_id, String phone_no, String cycle_time, String auth_key);

  boolean bauth_key = barokey.verifyKEYL(String login_id, String phone_no, String cycle_time, String key_method, String auth_key);

 

- DESCRIPTION

  어플리케이션 로그인/인증 시 비밀번호를 대체/인증시 일회용 인증키를 검증하는 함수.

  login_id : 로그인-ID를 설정.

  phone_no : 스마트 폰 번호(숫자만 허용)를 설정.

  cycle_time : 일회용 인증키의 생성 주기(3~60)를 설정.

  key_method : 일회용 인증키의 검증 방식(app1, app256, app384, app512: , card1, ard256,

                    card384, card512: 인증카드)을 설정.

  auth_key : 입력한 일회용 인증키를 설정.

 

- RETURN VALUES

  성공 시에는 true을 반환하며, 실패 시는 false을 반환한다.

 

 

2.2 verifyKEYC 함수

 

- NAME

  verifyKEYC

 

- SYNOPSIS

  String login_times = barokey.verifyKEYC(String secure_key, String cycle_time, String login_time, String auth_key);

  String login_times = barokey.verifyKEYC(String secure_key, String cycle_time, String key_method, String login_time, String auth_key);

 

- DESCRIPTION

  다양한 운영체제에서 2차 인증 및 어플리케이션 로그인/인증 시 비밀번호를 대체/인증시

  일회용 인증키를 검증하는 함수.

  secure_key : 벤더에서 제공한 서버별/개인별 Secure key를 설정.

  cycle_time : 일회용 인증키의 생성 주기를 설정. (3~60)

  key_method : 일회용 인증키의 생성 방식(app1, app256, app384, app512: 앱, card1, ard256,

                    card384, card512: 인증카드)을 설정.

  login_time : 로그인 성공한 최종시간을 설정.

  auth_key : 입력한 일회용 인증키를 설정.

 

- RETURN VALUES

  성공 시에는 현재시간을 반환하며, 실패 시는 "fail"를 반환한다.

 

 

2.3 checkRateLimit 함수

 

- NAME

  checkRateLimit

 

- SYNOPSIS

  public static String checkRateLimit(int rate_cnt, String rate_limit, long login_time)

 

- DESCRIPTION

  로그인/인증 시 중간자 공격에 대비하여 제한시간 및 횟수에 의하여 잠금 여부를 확인하는

  함수.

  rate_cnt : 로그인/인증 실패에 대한 제한하는 횟수를 설정.

  rate_limit : 로그인/인증 실패에 대한 시간(제한)을 설정.

  login_time : 로그인/인증을 요청한 시간을 설정.

 

- RETURN VALUES

  성공 시에는 로그인/인증을 요청한 시간을 추가한 제한시간과 잠김여부(Y or N)을 반환하며,

  실패 시는 ""을 반환한다.

 

 

3. 사용법(Java)

3.1 앱 인증인 경우

 

사용자정보 속성 예)

 

인증 프로그램 예)

package com.barokey.key;
 
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Vector;
 
import org.apache.log4j.Logger;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
 
import com.barokey.common.CommonLib;
import com.barokey.common.DBConnection;
import com.barokey.*;
……
/**
     * App 인증.
     *
     * @param auth_type
     * @param auth_use
     * @param user_no
     * @param auth_key
     * @param rate_cnt
     * @param ip_addr
     * @return result
     * @throws Exception
     */
    public String authAPP(String auth_type, String auth_use, String user_no, String auth_key, int rate_cnt, String ip_addr) throws Exception {
        /*--------------------------------------------------------------------*/
        /* 변수선언 및 초기화.                                                */
        /*--------------------------------------------------------------------*/
        int     ii = 0, jj = 0, kk = 0, ll = 0;           // Index
        Logger    logger = Logger.getLogger(this.getClass());
        CommonLib clib   = new CommonLib();               // CommonLib
        CardDAO   cdao   = new CardDAO();                 // CardDAO
        UserDAO   udao   = new UserDAO();                 // UserDAO
        BaroDTO   bdto   = new BaroDTO();                 // BaroDTO
 
        String  corr_time  = "fail";                      // 보정시간
        String  result     = "";                          // Result
        String  values     = "";                          // Return value
        boolean bauth_key  = false;                       // 인증키 검증
 
        String  login_time = "";                                 // 로그인최종시간
        String  rate_limit = "";                          // 제한 시간
        String  lock_yn    = "N";                         // Lock여부
        /*--------------------------------------------------------------------*/
        /* 처리 시작.                                                         */
        /*--------------------------------------------------------------------*/
        try {
            /*----------------------------------------------------------------*/
            /* 사용자정보 조회.                                               */
            /*----------------------------------------------------------------*/
            bdto = udao.read(user_no);
            /*----------------------------------------------------------------*/
            /* 사용자정보가 존재한 경우.                                      */
            /*----------------------------------------------------------------*/
            if (bdto != null) {
                /*------------------------------------------------------------*/
                /* 로그인 최종 시간 Edit.                                     */
                /*------------------------------------------------------------*/
                 login_time = Long.toString(barokey.get_logintime(bdto.getCycle_time()));
                /*------------------------------------------------------------*/
                /* 잠긴계정인 경우.                                           */
                /*------------------------------------------------------------*/
                if ("Y".equals(bdto.getLock_yn())) {
                    result = "10";
                /*------------------------------------------------------------*/
                /* 사용기간(From) 확인.                                       */
                /*------------------------------------------------------------*/
                } else if (Integer.parseInt(bdto.getUse_fr_dttm().replaceAll("-", "")) > Integer.parseInt(clib.nowDate().replaceAll("-", ""))) {
                    result = "03";
                /*------------------------------------------------------------*/
                /* 사용기간(To) 확인.                                         */
                /*------------------------------------------------------------*/
                } else if (Integer.parseInt(bdto.getUse_to_dttm().replaceAll("-", "")) < Integer.parseInt(clib.nowDate().replaceAll("-", ""))) {
                    result = "04";
                /*------------------------------------------------------------*/
                /* 사용하는 사용자인 경우.                                    */
                /*------------------------------------------------------------*/
                } else {
                    /*--------------------------------------------------------*/
                    /* 인증키인 경우.                                         */
                    /*--------------------------------------------------------*/
                    if (auth_key.length() == 6) {
                        logger.debug("barokey.verifyKEYL = [" + bdto.getUser_email() + "," + bdto.getUser_phone().replace("-", "") + "," + bdto.getCycle_time() + ",0," + bdto.getCreate_algorism() + "," + auth_key + "]");
                        /*----------------------------------------------------*/
                        /* 인증키 검증.                                       */
                        /*----------------------------------------------------*/
                        bauth_key = barokey.verifyKEYL(bdto.getUser_email(), bdto.getUser_phone().replace("-", ""), bdto.getCycle_time(), bdto.getCreate_algorism(), auth_key);
                        logger.debug("barokey.verifyKEYL = [" + bdto.getUser_email() + "," + bdto.getUser_phone().replace("-", "") + "," + bdto.getCycle_time() + bdto.getCreate_algorism() + "," + auth_key + "," + bauth_key + "]");
                    /*--------------------------------------------------------*/
                    /* PIN번호인 경우.                                        */
                    /*--------------------------------------------------------*/
                    } else {
                        /*----------------------------------------------------*/
                        /* PIN번호가 동일한 경우.                             */
                        /*----------------------------------------------------*/
                        if (auth_key.equals(bdto.getPin_no())) {
                            bauth_key = true;
                        /*----------------------------------------------------*/
                        /* Pin번호가 틀린한 경우.                             */
                        /*----------------------------------------------------*/
                        } else {
                            bauth_key = false;
                        }
                    }
                    /*--------------------------------------------------------*/
                    /* 인증키 검증(성공).                                     */
                    /*--------------------------------------------------------*/
                    if (bauth_key == true) {
                        /*----------------------------------------------------*/
                        /* 생성주기 내에 기인증 성공인 경우.                  */
                        /*----------------------------------------------------*/
                        if (Long.parseLong(login_time) <= Long.parseLong(bdto.getLogin_time())) {
                            result = "12";
                        /*----------------------------------------------------*/
                        /* 인증 성공인 경우.                                  */
                        /*----------------------------------------------------*/
                        } else {
                            result = "00";
                            /*------------------------------------------------*/
                            /* 로그인 최종 시간을 Update.                     */
                            /*------------------------------------------------*/
                            udao.updateLoginTime(user_no, Long.toString(login_time), user_no);
                        }
                    /*--------------------------------------------------------*/
                    /* 인증키 검증(실패).                                     */
                    /*--------------------------------------------------------*/
                    } else {
                        result = "99";
                    }
                }
                /*------------------------------------------------------------*/
                /* 인증키 검증(실패).                                         */
                /*------------------------------------------------------------*/
                if (!"00".equals(result) && !"Y".equals(bdto.getLock_yn())) {
                    /*--------------------------------------------------------*/
                    /* 제한시간이 존재한 경우.                                */
                    /*--------------------------------------------------------*/
                    if (bdto.getRate_limit().trim().length() > 0) {
                        /*----------------------------------------------------*/
                        /* 제한회수 적용 Check.                               */
                        /*----------------------------------------------------*/
                        values = barokey.checkRateLimit(rate_cnt, bdto.getRate_limit().trim(), login_time);
                        /*----------------------------------------------------*/
                        /* 제한시간 확인하기 위해 대상 데이터를 분할.         */
                        /*----------------------------------------------------*/
                        String[] value = values.split(",");
 
                        if (value.length == 2) {
                            rate_limit = value[0];
                            lock_yn    = value[1];
                        }
                        logger.debug("rate_limit = [" + rate_limit + "," + lock_yn + "]");
                    /*--------------------------------------------------------*/
                    /* 제한시간이 존재하지 않은 경우.                         */
                    /*--------------------------------------------------------*/
                    } else {
                        rate_limit = Long.toString(login_time);
                        lock_yn    = "N";
                    }
                    logger.debug("rate_limit = [" + rate_limit + "," + lock_yn + "]");
                    /*--------------------------------------------------------*/
                    /* 제한 시간을 Update.                                    */
                    /*--------------------------------------------------------*/
                    udao.updateRateLimit(user_no, rate_limit, lock_yn, user_no);
                }
            /*----------------------------------------------------------------*/
            /* 사용자정보가 존재하지 않는 경우.                               */
            /*----------------------------------------------------------------*/
            } else {
                result = "01";
            }
            /*----------------------------------------------------------------*/
            /* 인증로그 정보를 insert.                                        */
            /*----------------------------------------------------------------*/
            createApp(user_no, auth_type, ip_addr, bdto.getUser_email(), bdto.getUser_phone(), bdto.getCycle_time(), auth_use, result);
        /*--------------------------------------------------------------------*/
        /* 예외사항 처리(Exception).                                          */
        /*--------------------------------------------------------------------*/
        } catch(Exception e) {
            logger.info("Exception = [" + e + "]");
            /*----------------------------------------------------------------*/
            /* 오류 메시지 StackTrace.                                        */
            /*----------------------------------------------------------------*/
            e.printStackTrace();
        /*--------------------------------------------------------------------*/
        /* 처리 종료.                                                         */
        /*--------------------------------------------------------------------*/
        } finally {
        }
        return result;
    }

 

 

3.2 카드인 경우

카드정보 속성 예)

인증 프로그램 예)

package com.barokey.key;
 
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Vector;
 
import org.apache.log4j.Logger;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
 
import com.barokey.common.CommonLib;
import com.barokey.common.DBConnection;
import com.barokey.*;
……
/**
     * 인증카드 인증.
     *
     * @param auth_type
     * @param auth_use
     * @param user_no
     * @param auth_key
     * @param rate_cnt
     * @param ip_addr
     * @return result
     * @throws Exception
     */
    public String authCARDS(String auth_type, String auth_use, String user_no, String auth_key, int rate_cnt, String ip_addr) throws Exception {
        /*--------------------------------------------------------------------*/
        /* 변수선언 및 초기화.                                                */
        /*--------------------------------------------------------------------*/
        int     ii = 0, jj = 0, kk = 0, ll = 0;           // Index
        Logger    logger = Logger.getLogger(this.getClass());
        CommonLib clib   = new CommonLib();               // CommonLib
        CardDAO   cdao   = new CardDAO();                 // CardDAO
        UserDAO   udao   = new UserDAO();                 // UserDAO
        BaroDTO   bdto   = new BaroDTO();                 // BaroDTO
 
        String  corr_time  = "fail";                      // 보정시간
        String  result     = "";                          // Result
        String  values     = "";                          // Return value
        boolean bauth_key  = false;                       // 인증키 검증
 
        String  login_time = "";                                 // 로그인최종시간
        String  rate_limit = "";                          // 제한 시간
        String  lock_yn    = "N";                         // Lock여부
        /*--------------------------------------------------------------------*/
        /* 처리 시작.                                                         */
        /*--------------------------------------------------------------------*/
        try {
            /*----------------------------------------------------------------*/
            /* 인증카드 정보 조회.                                            */
            /*----------------------------------------------------------------*/
            bdto = cdao.reads(user_no);
            /*----------------------------------------------------------------*/
            /* 인증카드 정보가 존재한 경우.                                   */
            /*----------------------------------------------------------------*/
            if (bdto != null) {
                /*------------------------------------------------------------*/
                /* 잠긴계정인 경우.                                           */
                /*------------------------------------------------------------*/
                if ("Y".equals(bdto.getLock_yn())) {
                    result = "10";
                /*------------------------------------------------------------*/
                /* 사용기간(From) 확인.                                       */
                /*------------------------------------------------------------*/
                } else if (Integer.parseInt(bdto.getUse_fr_dttm().replaceAll("-", "")) > Integer.parseInt(clib.nowDate().replaceAll("-", ""))) {
                    result = "03";
                /*------------------------------------------------------------*/
                /* 사용기간(To) 확인.                                         */
                /*------------------------------------------------------------*/
                } else if (Integer.parseInt(bdto.getUse_to_dttm().replaceAll("-", "")) < Integer.parseInt(clib.nowDate().replaceAll("-", ""))) {
                    result = "04";
                /*------------------------------------------------------------*/
                /* 카드상태가 미발급인 경우.                                  */
                /*------------------------------------------------------------*/
                } else if ("01".equals(bdto.getCard_status())) {
                    result = "11";
                /*------------------------------------------------------------*/
                /* 카드상태가 폐기인 경우.                                    */
                /*------------------------------------------------------------*/
                } else if ("03".equals(bdto.getCard_status())) {
                    result = "06";
                /*------------------------------------------------------------*/
                /* 분실카드인 경우.                                           */
                /*------------------------------------------------------------*/
                } else if ("02".equals(bdto.getAccident_yn())) {
                    result = "07";
                /*------------------------------------------------------------*/
                /* 보증기간(From) 확인.                                       */
                /*------------------------------------------------------------*/
                } else if (Integer.parseInt(bdto.getWarranty_fr_dttm().replaceAll("-", "")) > Integer.parseInt(clib.nowDate().replaceAll("-", ""))) {
                    result = "08";
                /*------------------------------------------------------------*/
                /* 보증기간(To) 확인.                                         */
                /*------------------------------------------------------------*/
                } else if (Integer.parseInt(bdto.getWarranty_to_dttm().replaceAll("-", "")) < Integer.parseInt(clib.nowDate().replaceAll("-", ""))) {
                    result = "09";
                /*------------------------------------------------------------*/
                /* 알고리즘인 hmac-sha2 base인 경우.                          */
                /*------------------------------------------------------------*/
                } else {
                    /*--------------------------------------------------------*/
                    /* 인증키 검증.                                           */
                    /*--------------------------------------------------------*/
                    login_time = barokey.verifyKEYC(bdto.getSecure_key(), bdto.getCycle_time(), bdto.getCreate_algorism(), bdto.getLogin_time(), auth_key);
                    logger.debug("barokey.verifyKEYC = [" + user_no + "," + bdto.getSecure_key() + "," + bdto.getCycle_time() + "," + bdto.getCreate_algorism() + "," + auth_key + "," + login_time + "]");
                }
                /*------------------------------------------------------------*/
                /* 인증키 검증(성공).                                         */
                /*------------------------------------------------------------*/
                if (!"fail".equals(login_time)) {
                    /*--------------------------------------------------------*/
                    /* 생성주기 내에 기인증 성공인 경우.                      */
                    /*--------------------------------------------------------*/
                    if (Long.toString(login_time).equals(bdto.getLogin_time())) {
                        result = "12";
                    /*--------------------------------------------------------*/
                    /* 인증 성공인 경우.                                      */
                    /*--------------------------------------------------------*/
                    } else {
                        result = "00";
                        /*----------------------------------------------------*/
                        /* 로그인 최종 시간을 Update.                         */
                        /*----------------------------------------------------*/
                        udao.updateLoginTime(user_no, Long.toString(login_time), user_no);
                    }
                /*------------------------------------------------------------*/
                /* 인증키 검증(실패).                                         */
                /*------------------------------------------------------------*/
                } else {
                        result = "99";
                }
                /*------------------------------------------------------------*/
                /* 인증키 검증(실패).                                         */
                /*------------------------------------------------------------*/
                if (!"00".equals(result) && !"Y".equals(bdto.getLock_yn())) {
                    /*--------------------------------------------------------*/
                    /* 제한시간이 존재한 경우.                                */
                    /*--------------------------------------------------------*/
                    if (bdto.getRate_limit().trim().length() > 0) {
                        /*----------------------------------------------------*/
                        /* 제한회수 적용 Check.                               */
                        /*----------------------------------------------------*/
                        values = barokey.checkRateLimit(rate_cnt, bdto.getRate_limit().trim(), login_time);
                        /*----------------------------------------------------*/
                        /* 제한시간 확인하기 위해 대상 데이터 분할.           */
                        /*----------------------------------------------------*/
                        String[] value = values.split(",");
 
                        if (value.length == 2) {
                            rate_limit = value[0];
                            lock_yn    = value[1];
                        }
                        logger.debug("rate_limit = [" + rate_limit + "]");
                    /*--------------------------------------------------------*/
                    /* 제한시간이 존재하지 않은 경우.                         */
                    /*--------------------------------------------------------*/
                    } else {
                        rate_limit = Long.toString(login_time);
                        lock_yn    = "N";
                    }
                    logger.debug("rate_limit = [" + rate_limit + "]");
                    /*--------------------------------------------------------*/
                    /* 제한 시간을 Update.                                    */
                    /*--------------------------------------------------------*/
                    udao.updateRateLimit(user_no, rate_limit, lock_yn, user_no);
                }
            /*----------------------------------------------------------------*/
            /* 인증카드 정보가 존재하지 않는 경우.                            */
            /*----------------------------------------------------------------*/
            } else {
                result = "03";
            }
            /*----------------------------------------------------------------*/
            /* 인증로그 정보를 insert.                                        */
            /*----------------------------------------------------------------*/
            createCard(user_no, auth_type, ip_addr, bdto.getCard_no(), bdto.getCycle_time(), auth_use, result);
        /*--------------------------------------------------------------------*/
        /* 예외사항 처리(Exception).                                          */
        /*--------------------------------------------------------------------*/
        } catch(Exception e) {
            logger.info("Exception = [" + e + "]");
            /*----------------------------------------------------------------*/
            /* 오류 메시지 StackTrace.                                        */
            /*----------------------------------------------------------------*/
            e.printStackTrace();
        /*--------------------------------------------------------------------*/
        /* 처리 종료.                                                         */
        /*--------------------------------------------------------------------*/
        } finally {
        }
        return result;
    }

 

 

3.3 인증결과

 

인증한 결과 다음과 같은 코드를 반환한다.