コンタクトフォームにreCAPTCHA v3を導入した。

コンタクトフォームからのスパムメールが2日に10通くらいのペースで来ていて、困るほどの数でもないけどどうにかしたいレベルにはなってきたので、reCAPTCHA v3を導入してみました。

「私はロボットではありません」選ぶ必要なし 新「reCAPTCHA」Googleが公開、ユーザーは何もしなくてOK - ITmedia NEWS
reCAPTCHA v3  |  reCAPTCHA  |  Google Developers

Akismetでもよかったのですが、今までコメントフォームに使ってみて誤検知が結構多い印象だったのと、公開されたばかりなので試してみたいこともあり、こっちにしてみました。
判定の流れとしては以下のとおりです。

  1. クライアントサイドでtokenを取得
  2. 取得したtokenを元にサーバサイドでverify用のAPIを呼び出す
  3. APIから返ってきた結果をもとに、ページにアクセスしてきたのが人間かロボットかを判定する

クライアントサイドの導入方法

  1. 管理ページでAPI実行用のキーを発行する。
  2. 管理ページにjsロード用のscriptタグのスニペットが表示されるので、reCAPTCHAしたいページのhead内に埋め込む。
  3. 管理ページにreCAPTCHAのexecute用のscriptタグのスニペットが表示されるので、reCAPTCHAしたいページのどこかしらに埋め込む
<script>
grecaptcha.ready(function() {
  grecaptcha.execute('Site key', {action: 'action_name'}) // action_nameはサーバサイドの処理で使用する
    .then(function(token) {
    // Verify the token on the server.
  });
});
</script>

サーバサイドの導入方法

  1. クライアントからtokenを受け取る。
  2. Secret keyとtokenを使用してスコアの問い合わせを行う。APIからのレスポンスの形式はドキュメントを参照
curl https://www.google.com/recaptcha/api/siteverify  -X POST -d "secret=secret&response=token"
{
  "success": true,
  "score": 0.9,
  "action": "contact_form", // クライアントサイドで決めたaction_name
...
}

しきい値を決めて、それを下回るならエラーを返す等の処理をサーバサイドに書きます。

コンタクトフォームはContact Form 7を使用しているのですが、そのうちプラグイン側がv3に対応しそうなのと、自分で改造するのが面倒なので、reCAPTCHA用のエンドポイントを設置して、「エンドポイントからのレスポンスが200以外だったら、送信ボタンのDOMをremoveした上でsubmitイベントを無効化する」とかいう意味があるんだかないんだかわからない処理を入れておきました。
DOMの処理終わる前に送信されたら意味ないし、そもそもスパムの送信元がJS無効化してたら詰むんだけどまぁものは試しなので…。
reCAPTCHA用のjsも本当は全ページに読み込ませないといけないのですが、スパムの送信元はどうせコンタクトフォームに直接アクセスしてきてるので、コンタクトフォームのページにだけ読み込ませています。

設置してから4日くらい経ちますが、スパムが3通くらいしか届いていないのである程度効果はあるのかなと思っています。

だから私はQiitaに投稿しない。

最近のQiitaの記事の質が下がってきている事への考察 – Qiita
これ読んでいろいろ思うことがあったのでポエム。

メールで問い合わせ受けたときに何回か「この記事Qiitaに投稿してほしかった(Qiitaに投稿してくれたらもっと早く見つけられた)」と言われたことがあるんですが、私は多分Qiitaには行かないと思います。

ポエムとかJAVAの人の記事は論外として、何かしら記事書いても「質の高い記事を投稿しろ」って言われてしまうなら、じゃあQiitaには投稿しないわ、ってなっちゃう。
今までQiitaに投稿された色々な記事に助けられてきたけど、私の書く記事がそうなれるかって言ったらなれないんですよね。多分。

Qiitaって技術ブログのInstagramみたいだとずっと感じてて、見る分にはほんとに楽しいしすごいなぁって思うんですが、私は投稿するのきついです。
意識高い人やいけてる人がめっちゃキラキラした写真を投稿するように、いけてるベンチャーの人やバリバリのフリーランスの人やレベルの高いエンジニアがレベルの高い記事を投稿するのがQiitaで、Qiitaには質の高いものばっかりなきゃいけない、みたいな感じになってる気がします。(でもそれってほんとにQiitaと、Qiitaを見に来る人にとっていいことなんですかね?)
「質の高い記事だけ探して読むわ」って人が集まるんじゃなくて「質の高い記事だけ投稿しろ」っていう人が集まってるところに記事投稿しても自分が悲しくなるだけだなぁって。

ポエムも書きたいし自分の好きな言語だけで好きなものだけ作りたいので、私はこのブログでいいです。

Gutenberg 4.1.1が有効の状態でSyntaxHighlighter Evolvedを使うとbr /が混ざる。

「新しいものは良いもの」という信条があるのでOSアップデートでもなんでも即試すんですが、ただしGutenberg、テメーはだめだ。
Gutenberg | WordPress.org
レビューにdisasterってコメントがあるのは笑ってしまった。

もう絶対原因こいつだろと決めてかかって無効化したらSyntaxHighlighter Evolvedで出力してる箇所にbr /は混ざらなくなりました。これ標準エディタ化されるとマジで詰みますね。どうしよう。
原因まで調べてる時間がなかったので、具体的にどのコードがSyntaxHighlighter Evolvedにちょっかいをかけているのかはわかっていないです。とりあえずメモとして記事を残しておきます。

某飲食店予約システムのインフラ構成を予想したい。

インフラのイの字もわからないのにインフラ系のことをせざるを得ない状況になっており、勉強のために某飲食店予約システムのインフラ構成を予想しようと思いました。ピンクくて丸いやつ向けです。

注意

記事の内容は、野球の試合をテレビで見ながらイチャモンをつけるおっさんくらい薄く、知識量に比例して正確性は皆無です。インフラをわかってない人が頑張るとこういう予想にたどり着くんだね、という参考にはなるかもしれません。

参考にしたページ

とりあえず情報を集めます。

トレタのインフラ運用、支えている道具(Packer, Terraform, Serverspec, Ansible, Roadworker, Circle CI)、考え方 – トレタ開発者ブログ
トレタのインフラ運用 – Speaker Deck
トレタのMySQL MySQL casual #8
記事が結構古いからだいぶ変わってそうですね。どっかに答え載ってるんじゃないかと思って開発者ブログを見てみたけど最近の記事はなかった…。SlideShareとかにはあるのかもしれないですね。

うっす~いよそう

実際に使ってみてのエラーの返り方やレスポンスの感じだと以下のような構成でしょうか…?

  • サーバ:Amazon EC2
  • ロードバランサ:ALB?NLB?
  • バックエンド:Ruby on Rails
  • DB:Amazon RDS for MySQL
  • 静的コンテンツ(json等):CloudFront
  • 静的コンテンツ(画像等):Amazon S3

default backend – 404(多分Nginx Ingress Controllerのデフォルトバックエンドのレスポンス)が時たま返ってきたことから予想すると、おそらくRoRはKubernetesのPodで動いてるかもしれません。AWSを使ってるなら、GKEを採用しているのかなぁと予想しました。(リバースプロキシもIngressを使用)

実際の挙動からのうっす~いよそう

予約用の内部APIは予約対象の店舗のIDごとに処理する仮想サーバが決まっているわけではないようで、一店舗に予約処理が集中すると他の店舗のリクエストも応答しなくなるという挙動でした。(実際、先月はそれで巻き添え食らったところが落ちていた)
EC2使ってるならスケールアウトするか、予行演習で前もってやばいのはわかってたので、ピンクいやつだけL7ロードバランサでRDSもRoRも専用のインスタンスに処理させるとかいくらでも手は打てたと思うのですが、どうしてこうしなかったのかはよくわかりません。

以下を読んだのですが、ELB自体は5万RPSかけても受けきれるっぽいのと、API叩いたときに502 Bad Gateway返ってきてたので、Ingress Controllerまでは問題なくて、バックがボトルネックになっているのかなぁと思いました。(小学生並みの感想)
[社内勉強会]ELBとALBと数万スパイク負荷テスト

感想

やっぱりよくわからない。

metabaseを日本語化するとバグりすぎてつらいので英語のまま使う。

metabase v0.30.3の話です。コントリビューターの方々には本当に申し訳ないのですが、日本語化すると表示周りのバグのせいでビジュアライゼーションの種類が選択できなくなるのと、翻訳がめちゃくちゃで使い勝手が著しく悪くなるので、英語の状態のまま使用することにしました。 
ビジュアライゼーションの種類が選択できなくなるのは、ブラウザのDeveloper Tool等で要素を書き換えれば回避可能です。issueにはすでに上がっていました。

ここを書き換えれば選択可能になる

対策案

  1. metabase.jarをいじる
  2. リバースプロキシ(nginx)の設定でaccept-languageからja-JPを消す

metabase修正するのはできるけど、バージョン上がっても治ってなかった場合に同じことを繰り返すのがつらいので、リバースプロキシ(nginx)でどうにかします。

proxy_hide_header accept-language;
proxy_set_header accept-language "en-US,en;q=0.9";

無事英語のダッシュボードが表示されるようになりました。