본문 바로가기
프로그래밍/JAVA

Spring Boot 텍스트 Captcha 적용 방법

by yun5o 2024. 8. 16.

* Captcha 란?

Captcha는 웹사이트와 온라인 서비스의 안전성을 유지하기 위해 필수적인 도구입니다. 사용자가 실제 사람인지 확인함으로써 여러 문제를 예방하고 해결하는 데 중요한 역할을 합니다.

Captcha의 주요 목적은 스팸 봇이나 자동화된 프로그램이 무분별하게 접근하지 못하도록 차단하거나 로그인 등의 중요한 작업에서 악용을 막아 보안을 강화합니다.

 

* Captcha 종류

Captcha는 크게 3가지 종류로 나뉩니다.

  • 텍스트 Captcha: 왜곡된 글자나 숫자를 사용자에게 보여주고, 이를 입력하게 합니다.
  • 이미지 Captcha: 여러 개의 이미지 중 특정 조건에 맞는 이미지를 선택하게 합니다. 예) "모든 자전거를 선택하세요."
  • reCaptcha: 구글이 개발한 Captcha로, 단순히 텍스트를 입력하는 것 외에도 이미지를 선택하거나 간단한 확인 버튼을 누르는 형태로 제공됩니다.

 

* 텍스트 Captcha 사용 방법

1. Controller에서 호출해서 쓸 CaptchaUtil.java를 만들어 줍니다. 이때, Captcha 이미지의 폰트와 색상 및 다양한 설정을 지정할 수 있습니다.

private static int width = 150;	// 보안문자 이미지 가로
private static int height = 50; // 보안문자 이미지 세로

public void getImgCaptCha(HttpServletRequest req, HttpServletResponse res) {
    // 폰트 및 컬러
    List<Font> fontList = new ArrayList<Font>();
    fontList.add(new Font("", Font.HANGING_BASELINE, 40));
    fontList.add(new Font("Courier", Font.ITALIC, 40));
    fontList.add(new Font("", Font.PLAIN, 40));
    List<Color> colorList = new ArrayList<Color>();
    colorList.add(Color.BLACK);

    Captcha captcha = new Captcha.Builder(width,  height)
            // .addText() 또는 아래와 같이 정의 : 6자리 숫자와 폰트 및 컬러 설정
            .addText(new NumbersAnswerProducer(6), new DefaultWordRenderer(colorList, fontList))
            .addNoise().addBorder()
            .addBackground(new GradiatedBackgroundProducer())
            .build();

    // JSP에서 Captcha 객체에 접근할 수 있도록 session에 저장
    req.getSession().setAttribute(Captcha.NAME, captcha);
    CaptchaServletUtil.writeImage(res, captcha.getImage());
}

 

시각장애인을 위해 이미지 뿐만 아니라 오디오로 들을 수 있는 Captcha도 만들어 줍니다.

public void getAudioCaptCha(HttpServletRequest req, HttpServletResponse res, String answer) throws IOException {
    HttpSession session = req.getSession();

    Captcha captcha = (Captcha) session.getAttribute(Captcha.NAME);
    String getAnswer = answer;

    if(getAnswer == null || getAnswer.equals("")) getAnswer = captcha.getAnswer();

    AudioCaptcha audiocaptcha = new AudioCaptcha.Builder()
            .addAnswer(new SetTextProducer(getAnswer))
            .addNoise()	// 잡음 추가
            .build();

    CaptchaServletUtil.writeAudio(res, audiocaptcha.getChallenge());
}

 

2. SetTextProducer class 생성해서 getAudioCaptcha에서 사용할 수 있도록 합니다.

public class SetTextProducer implements TextProducer {
	private final String str;
	
	public SetTextProducer(String getAnswer) {
		this.str = getAnswer;
	}

	@Override
	public String getText() {
		return this.str;
	}
	
}

 

3. JSP 에서 이미지를 불러오고 음성을 들을 수 있는 버튼을 만들어 줍니다.

<div class="row">
    <label>자동 등록 방지</label>
    <div>
        <img title="캡차이미지" src="<c:url value='/captchaImg.do'/>" alt="캡차이미지"/>
        <button type="button" onclick="getImage()">새로고침</i></button>
        <button type="button" onclick="getAudio()">음성듣기</i></button>
        <div id="ccaudio" style="display:none"></div>
    </div>
    <div>	
        <input id="answer" type="text">
    </div>
</div>

 

function getImage(){
    $("#captchaDiv img").attr('src', "/captchaImg.do");
}

function getAudio(){
    var uAgent = navigator.userAgent;
    var soundUrl = "/captchaAudio.do";
    if(uAgent.indexOf('Trident') > -1 || uAgent.indexOf('MISE') > -1){	// IE
        $("#ccaudio").html('<bgsoun src="' +soundUrl +'">');
    }else if(!!document.createElement('audio').canPlayType){ // Chrome
        try {
            new Audio(soundUrl).play();
        } catch (e) {
            $("#ccaudio").html('<bgsoun src="' +soundUrl +'">');
        }
    }else{
        window.open(soundUrl,'','width=1,height=1');
    }
}

 

4. Controller 에서 호출할 메서드를 추가해 줍니다.

// captcha 이미지 가져오기
@RequestMapping("/captchaImg.do")
public @ResponseBody void captchaImg(HttpServletRequest req, HttpServletResponse res) throws Exception{
    new CaptchaUtil().getImgCaptCha(req, res);
}

// 전달받은 문자열로 음성 가져오기
@RequestMapping("/captchaAudio.do")
public @ResponseBody void captchaAudio(HttpServletRequest req, HttpServletResponse res) throws Exception{
    Captcha captcha = (Captcha) req.getSession().getAttribute(Captcha.NAME);
    String getAnswer = captcha.getAnswer();
    new CaptchaUtil().getAudioCaptCha(req, res, getAnswer);
}

 

5. 기존에 처리하던 로직에 Captcha 확인하는 로직을 추가해 줍니다.

// captcha check
Captcha captcha = (Captcha) session.getAttribute(Captcha.NAME);
if(inquire.getAnswer() != null && !"".equals(inquire.getAnswer())) {
    if(captcha.isCorrect(inquire.getAnswer())) {
        session.removeAttribute(Captcha.NAME);

        // 기존로직
        
        //--

    }else {
        return "captchaDiff";
    }
}else {
    return "captchaNo";
}

 

* 실행화면

 

댓글