最近管理しているサーバーに不正なアクセスが多発していて、
お問合せフォームに最終データをPOSTしてきやがるBOTが多い事多い事。
という事で最終チェックにGoogleの提供しているreCAPTCHAを取り入れる事にしました。
v2はチェックつけるタイプでv3はなんと何もせずにスコア値で評価されるとの事です。
設置の流れ
- KeyとSecretを取得
- javascriptを設置してスコアを収集(トークンに隠蔽されます)しフォーム送信
- バックエンドでGoogleのAPIにトークンを問い合わせてスコアを取得
こんな感じです。詳しくは公式ドキュメントに。
PHP版は書いている方がいたので(GoogleのreCAPTCHA v3をPHPで使う)
今回はバックエンド部分をGoでさくっとやってみます。
githubに全ソース置きました
キーさえ取ればdocker-composeで即動かせます。
1.KeyとSecretを取得
Googleアカウントが必要です。
https://www.google.com/recaptcha/にアクセスし、Admin Consoleからサイトキー、サイトシークレットを取得します。
タイプはv3を。ローカルでテストする場合ドメインには0.0.0.0
やlocalhost
等を入れる必要があります。
2.フロントにjavascriptとinputフィールドを追加
{{YOUR_SITE_KEY}}
は取得したキーを置き換えてください。githubのソースではgoのtemplateを使ってます。
<!-- reCAPTCHA -->
<script src="https://www.google.com/recaptcha/api.js?render={{YOUR_SITE_KEY}}"></script>
<script>
var recaptcha = document.getElementsByName('recaptcha_token');
console.log(recaptcha);
if (recaptcha != null) {
grecaptcha.ready(function() {
grecaptcha.execute('{{YOUR_SITE_KEY}}', {action: 'homepage'}).then(function(token) {
recaptcha[0].value = token
}, function (reason) {
console.log(reason)
});
});
}
</script>
<!-- /reCAPTCHA -->
homepage
の部分は以下4つから選べる。
- homepage:See a cohesive view of your traffic on the admin console while filtering scrapers.
- login:With low scores, require 2-factor-authentication or email verification to prevent * credential stuffing attacks.
- social:Limit unanswered friend requests from abusive users and send risky comments to moderation.
- e-commerce:Put your real sales ahead of bots and identify risky transactions.
フォーム内にトークン送信用のフィールドを設置
some field...
<input type="hidden" name="recaptcha_token" value=""/>
... submit button
ここまででアクセスした時点でサイトの右下にシールがつきます。
valueにもすぐにパラメータが入ってきます。
3.バックエンド(Go)
問い合わせ用の関数と結果の受け取り用のstructはこんな感じ。
"YOUR_SITE_SECRET"を取得したシークレットに置き換えてくださいね。
type RecaptchaResponse struct {
Success bool `json:"success"`
Score float64 `json:"score"`
Action string `json:"action"`
ChallengeTS time.Time `json:"challenge_ts"`
Hostname string `json:"hostname"`
ErrorCodes []string `json:"error-codes"`
}
func reCaptchaVerify(token string) (r RecaptchaResponse, err error) {
const recaptchaServerName = "https://www.google.com/recaptcha/api/siteverify"
resp, err := http.PostForm(recaptchaServerName,
url.Values{"secret": {"YOUR_SITE_SECRET"}, "remoteip": {"127.0.0.1"}, "response": {token}})
if err != nil {
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return
}
err = json.Unmarshal(body, &r)
if err != nil {
return
}
return
}
フォームから送信されたトークンを渡します。
if r, err := reCaptchaVerify(r.FormValue(FormNameRecaptcha)); err == nil {
if r.Success && r.Score > 0.7 {
// success action
} else {
// error action
}
}
}
スコアはユーザーエージェントの付け替えや、広告ブロック等の状態で変動するそうです。
広告ブロックくらいは許して良いだろという事で0.7くらいで丁度いいかなと思いますが
実際に動かして調整してみると良いかもしれません。