| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 |
- CS
- UaExpert다운로드
- C#이론
- prosys opc-ua
- cs기술면접
- java란?
- 서버저장방식
- Blazor WebAssembly
- jvm구성요소
- 스프링부트 장점
- 스프링부트의 장단점
- C# Blazor
- opc-ua 다운로드
- UaExpert download
- REST API
- java란 무엇인가
- 스프링부트 단점
- 프론트엔드
- nosql
- Blazor Web App
- OPC-UA Download
- Service Worker
- OPC-UA
- Redundant Array of Independent
- C# CS
- 컴퓨터과학
- Prosys Opc-ua 다운로드
- spring spring boot 차이점 공통점
- 스프링 스프링부트 차이점 공통점
- 기술면접
- Today
- Total
담비의 개발블로그
[Spring Boot]구글 리캡차 사용법 본문
CAPTCHA란?
CAPTCHA란 Completely Automated Public Turing test to tell Computers and Humans Apart(컴퓨터와 인간을 구분하기 위한 완전 자동화된 공공 튜링 테스트)의 줄임말로 일반적으로 게시글 및 댓글을 작성하거나 온라인 투표 등의 상황에서 프로그램을 통해 참여 숫자를 조작하는 것을 방지하기 위해 개발되었다.
reCAPTCHA(리캡차)는 구글에서 개발한 자동화된 프로그램이나 봇으로부터 웹사이트를 보호하기 위한 보안 기술 중 하나. 주로 웹 양식의 자동 제출을 방지하고, 스팸 댓글을 막는 등의 목적으로 사용된다. 즉, 사용자가 사람인지 봇인지를 판별해준다.
리캡차 개발 가이드
https://developers.google.com/recaptcha/intro?hl=ko
1.1. 사이트 접속
아래의 사이트에 접속해 내용을 작성한다. 라벨은 본인이 임의로 지정해서 쓰면 된다. 원하는 reCAPTCHA유형에 체크하고, 도메인을 입력한다. 프로젝트 이름을 등록한다. 필자는 v2를 사용할 예정이다.
https://www.google.com/recaptcha/admin/create?hl=ko
로그인 - Google 계정
이메일 또는 휴대전화
accounts.google.com

reCAPTCHA v3
사용자의 움직임을 감지해 비정상적인 감지가 일어나는지 아닌지를 체크한다.
reCAPTCHA v2 ('로봇이 아닙니다' 체크박스)
'로봇이 아닙니다' 체크박스를 선택하면 사용자가 로봇이 아님을 나타내는 체크박스를 클릭하는 것이다.

1-2. 로컬호스트 테스트 방법
혹시라도 localhost에서 테스트 하고싶다면 아래와 같이 입력한다.
127.0.0.1
localhost

2. 사이트키
아래의 사이트 키를 사용해 리캡차를 이용할 수 있으니 참고하면 된다. 혹시라도 까먹는다면 관리탭에서 볼 수 있다.
관리탭 들어가는 사이트 : https://www.google.com/recaptcha/admin
로그인 - Google 계정
이메일 또는 휴대전화
accounts.google.com

3. application.properties에 키 등록하기
발급받았던 사이트 키를 입력해준다. 직접 사이트키를 html안에 삽입해서 쓰지 않는 이유는 보안상의 이유이기 때문에 이 작업은 필수로 하고 가야했던 부분이다.
google.recaptcha.key.site='your-site-key'
google.recaptcha.key.secret='your-secret-key'
4. 의존성 추가
build.gradle에 아래 내용을 추가해준다.
dependencies {
// 리캡차
implementation 'net.tanesha.recaptcha4j:recaptcha4j:0.0.7'
// 리캡차 사용을 위한 json
implementation 'javax.json:javax.json-api:1.1.2'
implementation 'org.glassfish:javax.json:1.1'
implementation 'org.json:json:20230618'
// 리캡차 사용을 위한 lombok
compileOnly 'org.projectlombok:lombok:1.18.28'
annotationProcessor 'org.projectlombok:lombok:1.18.28'
}
Maven이라면 아래처럼 추가해준다. (Maven은 사용까진 안해봐서 참고용으로 쓰면 좋을 것 같다.)
<dependency>
<groupId>net.tanesha.recaptcha4j</groupId>
<artifactId>recaptcha4j</artifactId>
<version>0.0.7</version>
</dependency>
<dependency>
<groupId>javax.json</groupId>
<artifactId>javax.json-api</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20230618</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.28</version>
<scope>provided</scope>
</dependency>
5. @Configuration어노테이션을 사용한 빈을 만들기
사이트 키를 사용하기 위해 @Configuration어노테이션을 사용한 빈을 만든다.
사이트 키를 가져오기 편하게 하기 위해 Getter와 Setter도 사용했다.
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import lombok.Getter;
import lombok.Setter;
@Configuration
@ConfigurationProperties(prefix = "google.recaptcha.key")
@Getter
@Setter
public class CaptchaSettings {
private String site;
private String secret;
}
6. VerifyRecaptcha 클래스 작성하기
VerifyRecaptcha 클래스를 작성한다.
package com.test.config;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.net.URL;
import javax.json.Json;
import javax.json.JsonObject;
import javax.json.JsonReader;
import javax.net.ssl.HttpsURLConnection;
import org.springframework.context.annotation.Configuration;
@Configuration
public class VerifyRecaptcha {
// 구글 리캡차 서버의 검증 URL
public static final String url = "https://www.google.com/recaptcha/api/siteverify";
// 사용자 에이전트 정보 (브라우저 정보 모방)
private final static String USER_AGENT = "Mozilla/5.0";
// 리캡차 비밀 키
private static String secret;
// 비밀 키 설정 메서드
public static void setSecretKey(String key) {
secret = key;
}
// 리캡차 응답 검증 메서드
public static boolean verify(String gRecaptchaResponse) {
// 응답이 없거나 비어있을 경우 검증 실패 처리
if (gRecaptchaResponse == null || "".equals(gRecaptchaResponse)) {
return false;
}
try {
// URL 객체 생성
URL obj = new URL(url);
// HTTPS 연결 설정
HttpsURLConnection con = (HttpsURLConnection) obj.openConnection();
// HTTP 요청 메서드 설정 (POST 방식)
con.setRequestMethod("POST");
// 요청 헤더 설정
con.setRequestProperty("User-Agent", USER_AGENT);
con.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
// POST 파라미터 설정 (비밀 키와 리캡차 응답 토큰)
String postParams = "secret=" + secret + "&response=" + gRecaptchaResponse;
// POST 요청 전송
con.setDoOutput(true);
DataOutputStream wr = new DataOutputStream(con.getOutputStream());
wr.writeBytes(postParams);
wr.flush();
wr.close();
// 서버로부터 응답 코드 확인
int responseCode = con.getResponseCode();
System.out.println("\nSending 'POST' request to URL : " + url);
System.out.println("Post parameters : " + postParams);
System.out.println("Response Code : " + responseCode);
// 서버 응답 읽기
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
// 응답 데이터를 한 줄씩 읽어서 버퍼에 저장
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
// 서버 응답 출력 (디버깅 용도)
System.out.println(response.toString());
// JSON 응답을 파싱하여 'success' 필드 값 반환
JsonReader jsonReader = Json.createReader(new StringReader(response.toString()));
JsonObject jsonObject = jsonReader.readObject();
jsonReader.close();
return jsonObject.getBoolean("success");
} catch (Exception e) {
// 예외 발생 시 스택 트레이스를 출력하고 검증 실패 처리
e.printStackTrace();
return false;
}
}
}
7. Controller에 reCAPTCHA 사용하기
리캡차를 사용하기 위해 VerifyRecaptcha 클래스를 사용해 controller를 작성한다.
package com.test.controller;
import java.util.Map;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.stereotype.Controller;
import com.test.config.CaptchaSettings;
import com.test.config.VerifyRecaptcha;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@Controller
public class RecaptchaController {
private final CaptchaSettings captchaSettings;
@ResponseBody
@PostMapping("/VerifyRecaptcha")
public int VerifyRecaptcha(@RequestBody Map<String, String> recaptcha) {
VerifyRecaptcha.setSecretKey(captchaSettings.getSecret());
String gRecaptchaResponse = recaptcha.get("response");
try {
if (VerifyRecaptcha.verify(gRecaptchaResponse))
return 0; // 성공
else
return 1; // 실패
} catch (Exception e) {
e.printStackTrace();
return -1; // 에러
}
}
}
8. html에 내용 reCAPTCHA삽입
스프링 부트 사용으로
th:attr="data-sitekey=${@captchaSettings.getSite()}"
이렇게 적었지만 보통
data-sitekey="your-site-jey"
이렇게 직접 적기도 한다. 하지만 보안의 이슈가 있으니 이방법은 추천하지 않는다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Test Form</title>
</head>
<body>
<form id="testForm" th:action="@{|/test/create|}" method="post" onsubmit="return setCSecretValue()">
<div>
...
<tr>
<td>보안</td>
<td>
<div id="recaptcha" class="g-recaptcha"
th:attr="data-sitekey=${@captchaSettings.getSite()}"
data-callback="recaptchaCallback"></div>
</td>
</tr>
...
<!-- 숨겨진 필드 -->
<input type="hidden" id="g-recaptcha-response" name="g-recaptcha-response">
</div>
<input type="submit" value="등록" id="test_registration">
</form>
<!-- reCAPTCHA API 불러오기 -->
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
<!-- JavaScript 파일 불러오기 -->
<script src="/path/to/your/recaptcha.js"></script>
</body>
</html>
9. JavaScript 작성하기
javascript를 아래와 같이 작성해준다.
// reCAPTCHA 완료 시 호출되는 콜백 함수
function recaptchaCallback(token) {
// reCAPTCHA 응답 토큰을 숨겨진 입력 필드에 설정
document.getElementById('g-recaptcha-response').value = token;
}
// 폼 제출 시 호출되는 함수
function setCSecretValue() {
var token = document.getElementById('g-recaptcha-response').value;
if (!token) {
alert("Please complete the reCAPTCHA");
return false; // reCAPTCHA가 완료되지 않았으면 폼 제출을 막음
}
return true; // reCAPTCHA가 완료되었으면 폼을 제출
}
reCAPTCHA 전달방식
1. 리캡차 로드
사용자가 웹페이지를 방문하면, 웹페이지는 구글 리캡차 스크립트를 로드한다.
이는 일반적으로 <script src="https://www.google.com/recaptcha/api.js"></script> 태그를 통해 이루어진다.
위에 적은 내용에서는 이 부분이다.
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
2. 리캡차 랜더링
<div class="g-recaptcha" data-sitekey="your_site_key"></div>
리캡차 위젯이 웹페이지에 렌더링된다. 이는 g-recaptcha 클래스를 가진 HTML 요소를 통해 이루어진다.
위에 적은 내용에서는 이 부분이다.
<div id="recaptcha" class="g-recaptcha"
th:attr="data-sitekey=${@captchaSettings.getSite()}"
data-callback="recaptchaCallback"></div>
3. 사용자 상호작용
사용자가 리캡차 위젯과 상호작용한다. 보통 "나는 로봇이 아닙니다" 체크박스를 클릭하거나 이미지 기반의 문제를 해결해야 한다.
4. 토큰 생성
사용자가 리캡차를 성공적으로 완료하면, 리캡차 시스템은 사용자가 로봇이 아님을 증명하는 토큰을 생성한다. 이 토큰은 사용자의 브라우저에서 생성되며, 리캡차 위젯이 있는 폼의 숨겨진 필드에 자동으로 추가된다.
<input type="hidden" name="g-recaptcha-response" value="토큰">
5. form 제출
사용자는 폼을 제출하고, 이 때 리캡차 토큰이 폼 데이터와 함께 서버로 전송된다.(백엔드로 전송되는 것)
6. 서버 검증
서버는 구글의 리캡차 API를 호출하여 제출된 토큰을 검증한다. 이를 위해 서버는 비밀 키와 토큰을 구글 리캡차 서버로 전송한다. 위에 적은 내용에선 서버검증이 VerifyRecaptcha 클래스를 통해 이루어진다. 이 클래스는 클라이언트에서 받은 리캡차 응답 토큰을 구글 리캡차 서버에 보내어 유효성을 확인한다.
7. 검증 결과 처리
구글 리캡차 서버는 검증 결과를 서버로 반환한다. 검증 결과는 JSON 형식으로 반환되며, 성공 여부와 함께 추가 정보를 포함한다. 서버로 전달된 리캡차 응답 토큰은 RecaptchaController 클래스에서 검증을 수행한 후, 그 결과에 따라 적절한 응답을 반환한다.
성공 (0): 리캡차 검증이 성공했을 때 반환된다.
실패 (1): 리캡차 검증이 실패했을 때 반환된다.
에러 (-1): 검증 중 예외가 발생했을 때 반환된다.
8. 결과에 따른 처리
서버는 검증 결과를 바탕으로 추가 처리를 수행한다. 검증이 성공하면, 서버는 사용자가 요청한 작업을 계속 진행하며, 실패하면 에러 메시지를 반환하고 요청을 중단한다.
리캡차 검증 결과에 따라 클라이언트에게 응답이 반환되며, 그에 따라 클라이언트 측에서 다음 단계를 수행할 수 있다.
성공 (0): 리캡차 검증이 성공한 경우, 폼 데이터가 서버로 제출되고 이후 처리(예: 데이터베이스에 저장, 이메일 전송 등)가 진행된다.
실패 (1): 리캡차 검증이 실패한 경우, 클라이언트는 오류 메시지를 표시하거나 리캡차를 다시 완료하도록 요청할 수 있다.
에러 (-1): 예외가 발생한 경우, 클라이언트는 에러 메시지를 표시하며 사용자에게 재시도를 요청할 수 있다.
'언어&프레임워크 > Spring&Spring Boot' 카테고리의 다른 글
| [Spring Boot]Security (1) | 2024.10.02 |
|---|---|
| [Spring Boot]Pagination (1) | 2024.09.26 |
| [Spring Boot]JUnit이란? (0) | 2024.07.24 |
| [Spring Boot]@Transactional에 대해 알아보자! (0) | 2024.07.15 |
| [Spring Boot] 프로젝트 구성방법 (0) | 2024.07.02 |
