今日、ログインや登録のためのアプリケーションは、SMS CAPTCHAを使用しています。これらのシナリオでは、CAPTCHA は本当に不可欠です。技術の発展に伴い、また、元のグラフィカルなCAPTCHAからCAPTCHAを作り、今日のスライダーに、反転テキストのクリック、数学的計算、ジェスチャー、スライド、ジグソーパズル、スクレイピング...などなど、様々なトリック。このように、あらゆる種類のトリック、要するに、目的は、ロボットへのアクセスを防ぐことです。
CAPTCHAというのはユーザーにとって本当に嫌な経験で、多くのアプリは本当に難解なCAPTCHAを持っていて、人々を狂わせます。
ReCaptcha
これはGoogleCaptchaプログラムで、無料で、強力で、多くのワールドクラスのアプリが使用しています。
現在では、さらに人気の高い2つのバージョンがあります!
ReCaptcha 2次のようになります。
このキャプチャを見ると、かなりイライラして心配になります。
ReCaptcha 3
見せられない... そう、写真もプッシュボタンもありません。これは最も高度なバージョンで、ユーザーに嫌がらせをするわけではありません。その代わり、クライアントからいくつかの環境データを密かに読み取り、サーバーに送信し、サーバーはそれを数値で評価します。アプリケーションはこのスコアを使って、現在のリクエストが正当かどうかを判断する必要があります。
以下では、ReCaptcha 3にアクセスする場合のデモを、登録から始めます。
登録
以下のアドレスが開けない理由は聞かないでください。
登録はwww.google.com/recaptcha/a
簡単で、必要な名前とアクセスするアプリケーションのドメイン名を記入するだけです。それだけです。
登録成功
覚えておく必要があるキーは2つあります。つはフロントエンド鍵と呼ばれ、クライアントに公開されます。もう一つはバックエンドキーと呼ばれ、リモートサーバとの通信に使用され、クライアントには公開されません。
管理コンソール
コンソールでは、リクエスト数などの検証情報を見ることができます。
ドキュメント
developers.google.com/recaptcha/i...
詳しくは公式ドキュメントをご覧ください。
SpringBootアプリケーションの作成
バリデーション・インターセプターをstart.springboot.io/
作成プロセスは省略され、サードパーティの依存関係は必要なく、基本的なSpringBootの依存関係があります。
ymlでキーを設定します。
recaptcha:
client-key: "6LdvzboZAAAAALrLVyjabnd5xfb06izncgK0JXCt"
server-key: "6LdvzboZAAAAAE1mLwijdq9noxVUbWRBmqm-4Ava"
ymlで設定すると、プログラムは柔軟に
Webクライアントとの統合
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>ReCaptcha V3</title>
<!-- renderアノテーションの値はフロントエンドのキーである>
<script src="https://..//.?=Ct"></>
</head>
<body>
<input name="name" placeholder="名前を入力する " id="name"/>
<button id="button"> </button>
</body>
<script type="text/javascript">
// フロントエンドのキー
const CLIENT_KEY = "6LdvzboZAAAAALrLVyjabnd5xfb06izncgK0JXCt";
// grecaptcha.ready => CAPTCHA 初期化成功後のコールバック
grecaptcha.ready(() => {
console.log('CAPTCHA 初期化 OK');
});
// フォーム投稿
document.querySelector('#button').addEventListener('click', () => {
// grecaptcha.execute => トークンを生成する
/**
最初のパラメータはフロントエンドのキーである
2番目のパラメータはオブジェクトで、アクション属性はカスタムの "シーン名 "だ。”.アプリはN個の検証シナリオを持つことができ、バックグラウンドで異なるシナリオの検証データを見ることができる。
3番目のパラメータはコールバック・メソッドで、トークンが正式なパラメータとなる。
**/
grecaptcha.execute(CLIENT_KEY, {action: 'test'}).then((token) => { // リクエストボディを構築する
const body = new URLSearchParams();
body.set('token', token); // CAPTCHAコールバックトークン
body.set('name', document.querySelector('#name').value); // フォームデータ// リクエストを開始する
fetch('/test', {
method: 'POST',
body: body
}).then(resp => {
if (resp.ok){
resp.json().then(message => {
if (message.success){
document.querySelector('#name').value = '';
} else {
alert('人間による検証は失敗する');
}
})
}
});
});
});
</script>
</html>
テンプレートエンジンのレンダリングであれば、設定ファイルからフロントエンドのキーをページにレンダリングすることができます。
注目すべき点
jsライブラリ読み込み
<script src="https://..//.?er={クライアント・アイ}"></>
CAPTCHA 初期化完了コールバック。
grecaptcha.ready(() => {
console.log('CAPTCHA 初期化 OK');
});
executeメソッドを実行してトークンを取得します。
grecaptcha.execute("{クライアント・キー}", {action: '{action}'}).then((token) => {
// トークンを取得したら、データをサーバーに送信する。
});
サーバーサイドのバリデーション
バリデーションのステップ
1.Httpクライアントを使用して、3つのパラメータを持つリモートサーバーへのPOSTリクエストを開始します。
https://..///fy
| secret | バックエンドキー | で御座います |
| response | クライアントが生成したトークン | で御座います |
| remoteip | クライアント ip | いいえ |
2.サーバーの応答
{
"success": true|false, // このリクエストは、このサイトにとって有効なreCAPTCHAトークンか?
"score": number // 1が人間、0が機械である。
"action": string // 定義された検証シナリオ
"challenge_ts": timestamp, // ロードされたタイムスタンプ
"hostname": string, // reCAPTCHAを使用しているサイトのホスト名
"error-codes": [...] // オプションのエラー・コード
}
エラーコードの説明
3.評価によって出すか出さないかを自分で判断してください。
完全なコード
import java.util.Collections;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
@RestController
@RequestMapping("/test")
public class TestController {
private static final Logger LOGGER = LoggerFactory.getLogger(TestController.class);
// 最初にIOCにRestTemplateを登録する必要がある。
@Autowired
private RestTemplate restTemplate;
// 設定ファイルからバックエンドのキーを読み込む
@Value("${recaptcha.server-key}")
private String serverKey;
// リクエスト・アドレス
private static final String SITEVE_RIFY = "https://..///fy";
@PostMapping
public Object test (HttpServletRequest request,
@RequestParam("name") String name,
@RequestParam("token") String token) {
LOGGER.info("name={}, token={}", name, token);
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE);
httpHeaders.set(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
MultiValueMap<String, Object> requestBody = new LinkedMultiValueMap<>();
requestBody.add("secret", this.serverKey); // サーバー側のキー
requestBody.add("response", token); // クライアント側でのトークン送信
requestBody.add("remoteip", request.getRemoteAddr()); // クライアントのIPアドレスは必須パラメータではない。
ResponseEntity<String> responseEntity = restTemplate.postForEntity(SITEVE_RIFY, new HttpEntity<>(requestBody, httpHeaders), String.class);
JsonObject jsonObject = JsonParser.parseString(responseEntity.getBody()).getAsJsonObject();
LOGGER.info("recaptcha response={}", jsonObject);
// 実行が成功したかどうか
if (!jsonObject.get("success").getAsBoolean()){
// 失敗した場合は、例外ステータスコードを取得する。
JsonArray errorCodes = jsonObject.get("error-codes").getAsJsonArray();
LOGGER.error("recaptcha error={}", errorCodes);
return Collections.singletonMap("success", Boolean.FALSE);
}
//
double score = jsonObject.get("score").getAsDouble();
if (score < 0.5) {
// もし0以下なら.5スコア、サービスはリクエストを受け入れない
return Collections.singletonMap("success", Boolean.FALSE);
}
return Collections.singletonMap("success", Boolean.TRUE);
}
}
実行ログ1件
i.s.web.controller.TestController : name=qwdqw, token=03AGdBq26J8YBZT6VuzU27VyuOk-KmKxN-UB6ETQ_MKOuDyea8upMmMBsX6H3TZ5NNK_VwgvJpxEJVppdmHNERK2d4Eo_w-YpxCi0TJmTyWJLRXD7279DScPOLxuRbj0nH_pTyYJw7OCf9o06gOeBQUqF7bCI_I4rakW4LvQSXd5d2jyFBdOf-FET6vqYzOYB93LyOsKcZdMci9YxIJ-9p8x_gm9YetFvyzQBt5il7iDHEqeLAd7HfLSh6UVOeDtHDncbkIgKWitHv4DuEO8_O8Pm7Fz6Sdc_GoAJgPeYAHkZs5vMvPqwv6H7hUKhh8RI-zCm3cYKe6nYK3Fc7Mc1Xr5bRnJqrSgrJkLBva4v2y-gSffm7E8GmtFgE9Kgr1iaualNUVzmYAiTx
i.s.web.controller.TestController : recaptcha response={"success":true,"challenge_ts":"TZ","hostname":"localhost","score":0.9,"action":"test"}
プライバシーポリシーアイコン
このバージョンのCAPTCHAを使用すると、画面の右下に小さなアイコンが表示されます。結局のところ、他の人のを使った後、それを維持することをお勧めします。
非表示にするには、cssを追加してください。
.grecaptcha-badge {
display: none;
}
最後に
汎用性を考えると、とてもシンプルです。バリデーション・インターセプターを抽象化し、アノテーションを定義します。アノテーションには、そのインターフェイスで最低限許されるスコアを記述します。アノテーションの値はインターセプターで取得され、判定とバリデーションが行われます。このほうがはるかに汎用的で柔軟です。





