きり丸の技術日記

技術検証したり、資格等をここに残していきます。

google reCAPTCHA v3を実装しようとして1週間くらい苦労した話

2020/07/27 追記

実装した記事を書きました。
GitHubにソースもあります。

nainaistar.hatenablog.com


色んなサイトですぐに認証できるというように書いてたのに、ずっと突破できなかったので、自分の中で整理するために纏めます。
結論としては、書いてあることをちゃんと実装したらすぐに終わりました。

google reCAPTCHAとは

ウェブサイトをスパムや不正利用から守るためのサービス。
ちょっと昔にあった「信号の表示されている絵をすべて選択してください」という認証がgoogle reCAPTCHAで実装できる(v2)。 種類としては、v2, invisible, v3の3種類がある。

無料で使える点はメリット。
v3は画像認証等も必要とせず、画面の操作を元にスコアを決定する。

1点気を付けるべきなのは、スコアが低かった場合、ハンドリングは実装者に任されるので、ただ入れるだけで認証できるわけではない。
入れるだけで認証したいのであれば、V2を使用したほうがよい。
(ただし、V2の画像認証は非常に不評らしいので、弊社では使用していない。)

前提知識

  • CORSを多少知っている
  • node.jsは良く知らない
  • vueはそれなり
  • Nuxtの初心者
  • google reCAPTCHAは知らない
  • AWSを自分で構築したことはない

やりたかったゴール

  • 静的サイトでgoogle reCAPTCHAの認証をする

思考経緯

  • google reCATPCHAのトークン発行はすぐに終わった。
  • API gatewayとか触ったことないから、ローカルで認証できないかな。
  • トークン発行できてるってことは、ローカルから認証できるだろう。
    • ここが第一の誤り。
      トークン発行はgoogleが提供するjsファイルを使用しているので、CORSの問題なかった。
      そもそも、reCAPTCHAの認証サーバは、ローカルから認証はできない。
  • axiosのheaderに"Access-Control-Allow-Origin:*"を設定していれば、postできた記憶があるのに、まったくできない。
  • Nuxt.js特有のCORS対策があるのかも。
  • 公式ページにCORSを突破できそうな方法が書いてあった!
  • なるほど!Nuxtではproxyを使ったらいいんだな!
    • 第二の誤り。
      ServerSideRenderingを使うなら、この解決方法でもいいんですが、今回のゴールとしては「静的サイト」での実装。
      proxyという文言に違和感を感じつつも、Nuxtではそういう風に表現するんだなって、勝手に納得して深く考えていなかった。
  • できた!
    • 静的サイトではできてない。
      ビルドして動作確認していると時間がかかりすぎるので、"yarn nuxt"で確認してたことが原因。
    • "yarn nuxt"の挙動もちゃんと理解していなかったのも大きい。
      node.jsのサーバーとして動いていたからこそ、XMLHttpRequestの制約が効いていなかったことを把握していなかった。
  • proxyを使わずにaxiosのみで実装する方法を模索する
  • API gateway + Lambda でサーバーサイドから実装する方法を模索する
  • Node.jsのhttpモジュールだと疎通は取れているようだが、"missing-input-secret", "missing-input-response"が発生する
  • Content-Typeに"application/x-www-form-urlencoded"を設定する。
  • Postだが、bodyに"secret", "response"を設定しても正常に動作しない。
  • どうやら、PostかつQueryParameterとして実行してみると良いようだ
  • 静的にビルドして動いた!

何が悪かったか

  • 具体的に悪いところをちゃんと理解していなかった。
    • CORSが突破できない。
      という曖昧な理解、かつ、過去の思い込みで調査を続けてしまったこと。
  • サーバー認証を極度に避けたこと
    • API gatewayやLambdaを使用したことが無かったので、極力避けたかった。
      だがしかし、それを避けて実装したことで余計に長時間かかってしまった。

学んだこと  

クライアントとしては、サーバーの許可する"Method"、"Content-Type"、"Access-Control-Allow-Origin"を一致させるという以上のことはできないので、それができなかった時点で、サーバー側で実装するしかない。

また、マニュアルに記載されている内容の解釈を勝手に変更しない。

その他ではデフォルトのContent-Typeは通信のライブラリによって違うことは学べました。

axios http
application/x-www-form-urlencoded text/plain

実はよくわかっていないこと

postでのクエリパラメータに設定したら動きましたけど、postってクエリパラメータ効くんでしたっけ?
application/x-www-form-urlencodedなら問題ないんですかね…?

実装参考サイト

https://developers-jp.googleblog.com/2017/09/guard-your-web-content-from-abuse-with.html