본문 바로가기

웹개발/Java

[Java] 보안 문자 생성 자바 라이브러리 - Simplecaptcha



SimpleCaptcha


소개 및 도입 준비


여러 사이트에서 로그인을 하다보면 디도스 공격 외 다른 부정적인 행동들을 막기 위의 밑의 이미지처럼 자동 로그인 방지 하는 액션들을 취해 놓습니다. (ex : SimpleCaptcha, reCaptcha 등)

이중 오늘은 SimpleCaptcha-1.2.1.jar 를 이용하여 자동 로그인 방지를 구현해보려고 합니다.

그림으로 자동로그인을 방지하는 reCaptcha는 상대적으로 더 간단하기에 다음에 소개하도록 하겠습니다.




SimpleCaptcha
https://sourceforge.net/projects/simplecaptcha/?source=typ_redirect


우선 SimpleCaptcha-1.2.1.jar 를 다운받습니다 

위의 링크 타고 가면 DOWNLOAD 버튼 통해서 다운받을 수 있습니다.




자신의 프로젝트 lib폴더에 다운받은 jar파일을 추가합니다.




프로젝트 오른쪽 클릭 > Build Path > Configure Build Path > Add External JARs 를 선택한 뒤,



아까 lib 폴더에 복사한 경로로 들어가서 SimpleCaptcha-1.2.1.jar 를 선택해줍니다.

JSP단 (css, script 분리는 자유)

login.jsp

 

<style>

   .captcha{
     overflow: hidden;
   }
   .captcha_child{
     float: left;
   }
   .captcha_child_two{
      float: right;
   }
   .refreshBtn:hover{
      background-color: #a8a8a8;
      color: white;
      border : 1px solid #a6a6a6;
   }
   .refreshBtn{
      color: black;
      border : 1px solid #888;
      width: 110px;
      border-radius: 5px;
      height: 25px;
      display: block;
      padding : 2px 15px;
      margin: 5px 0px;
   }
</style>
<!-- 로그인 화면 밑에 추가 (새로고침, 음성듣기버튼) -->
<div class="form-group">
   <label for="captcha" style="display:block">자동 로그인 방지</label>
   <div class="captcha">
     <div class="captcha_child">
        <img id ="captchaImg" title ="캡차 이미지" src="captchaImg.do" alt="캡차 이미지"/>
        <div id ="captchaAudio" style="display:none"></div>
     </div>
     <div class="captcha_child_two">
        <a onclick="javaScript:refreshBtn()" class="refreshBtn">
          <i class="fa fa-refresh" aria-hidden="true"></i> 새로고침
        </a>
        <a onclick="javaScript:audio()" class="refreshBtn">
          <i class="fa fa-volum-up" aria-hidden="true"></i> 음성듣기
        </a>
    </div>
   </div>
</div>
<script>
    // 새로고침시 이미지 변경되고, 음성듣기 클릭시 음성이 들리는 기능 구현
    function audio(){
      var rand = Math.random();

      var url = 'captchaAudio.do'
      $.ajax({
         url : url,
         type : 'POST',
         dataType : 'text',
         data : 'rand=' + rand,
         async : false,
         success : function(resp){
           var uAgent = navigator.userAgent;
           var soundUrl = 'captchaAudio.do?rand=' + rand;
           // 브라우저별 오디오 처리
           if (uAgent.indexOf('Trident') > -1 || uAgent.indexOf('MSIE') > -1) {    //IE인 경우
             winPlayer(soundUrl);
           } else if (!!document.createElement('audio').canPlayType){
             try {
               new Audio(soundUrl).play();
             } catch (e) {
               winPlayer(soundUrl);
             }
           } else {
               window.open(soundUrl, '', 'width=1,height=1');
           }
        }
      });
    }
    function refreshBtn(type){
      var rand = Math.random();
      var url = 'captchaImg.do?rand=' + rand;

      $('#captchaImg').attr("src", url);
    }
    function winPlayer(objUrl){
      $("#captchaAudio").html(' <bgsoun src="' + objUrl + '">');       //bgsound 배경음악 제어
    }
</script>


Java단 (css, script 분리는 자유)

LoginController.java

스크립트에서 캡챠 컨트롤러를 호출하면, 해당 컨트롤러에 CaptchaUtil의 메소드를 호출하게 됩니다.


 

/**

  * 이미지 자동방지
  */
 @RequestMapping(value = "captchaImg.do")
 public void captchaImg(HttpServletRequest request, HttpServletResponse response) throws Exception{
   new CaptchaUtil().capthcaImg(request,response);
 }
 /**
  * 소리 자동방지
  */
 @RequestMapping(value = "captchaAudio.do")
 public void captchaAudio(HttpServletRequest request, HttpServletResponse response) throws Exception{
   new CaptchaUtil().captchaAudio(request,response);
 }

       

CaptchaUtil.java

common 폴더에 CaptchaUtil을 만들어줍니다.
캡챠 build하는 부분은 커스텀할 수 있습니다! 아래 링크를 참고해주세요.

전 음성듣기 영어로 들리지만, 한글음성 파일이 있으면, 한글음성으로 설정할 수 도 있습니다.

 

public class CaptchaUtil {
       
       public CaptchaUtil() {
              
       }
       public void capthcaImg(HttpServletRequest request, HttpServletResponse response) {
         CaptcCha captcha = new Capthca.Builder(200,60)  // 이미지 크기  200 x 60
                .addText(new NumbersAnswerProducer(6))   // 6자리 숫자
                .addNoise().addNoise().addNoise() // 방해선
                .addBackground(new GradiatedBackgroundProducer()) // 배경색
                .addBorder()  // 테두리
                .build();
       
         response.setHeader("Cache-Control", "no-cache");
         response.setDateHeader("Expires", 0);
         response.setHeader("Pragma", "no-cache");
         response.setDateHeader("Max-Age", 0);
       
       }
       public void captchaAudio(HttpServletRequest request, HttpServletResponse response) {
         String getAnswer = (String) request.getSession().getAttribute("captcha");
       
         AudioCaptcha ac = new AudioCaptcha.Builder()
                .addAnswer(new SetTextProducer(getAnswer)) // 문자열 전달
                .addVoice()
                .addNoise()   //노이즈
                .build();
       
         response.setHeader("Cache-Control", "no-cache");
         response.setDateHeader("Expires", 0);
         response.setHeader("Pragma", "no-cache");
         response.setDateHeader("Max-Age", 0);
       
         CaptchaServletUtil.writeAudio(response, ac.getChallenge());   // 오디오를 write 한다.
       
         request.getSession().setAttribute("captcha", ac.getAnswer()); // 값 저장
      }
       

}

[SetTextProducer.java]

TextProducer 인터페이스를 상속받는 클래스를 만들어줘야합니다.
오디오 캡챠가 전달받은 문자열을 사용할 수 있게 해주는 클래스입니다.


 public class SetTextProducer implements TextProducer{

  private final String _getAnswer;
  public SetTextProducer(String getAnswer){
    _getAnswer = getAnswer;
  }
  @Override
  public String getText(){
    return _getAnswer;
  }
}


LoginController.java 


마지막으로 로그인 처리할때, 각자에 맞는 로그인 처리단계 URL에서 자동로그인방지 입력받은 문자열값과 캡챠 세션값 비교해서 처리하면 캡차 작업은 완료 되었습니다.
ex) actionLogin.do