【Rails】ひらがな入力を必須にして海外スパムボットによるお問い合わせフォーム送信を禁止する

## はじめに

僕の妻はパン屋をやっていて、僕はそのWebサイトを開発・運用しています。
Webサイトにはお問い合わせフォームがあるのですが、どこからともなくボットがやってきて、「あなたのサイトのプロモーションをお手伝いします！」みたいな英語のメッセージを送信してきます。

たとえばこんなメッセージです。


> Hi my name is Livia Schacter and I just wanted to send you a quick note here instead of calling you. I came to your Contact - Coupé Baguette クープ バゲット website and noticed you could have a lot more hits. I have found that the key to running a successful website is making sure the visitors you are getting are interested in your subject matter. There is a company that you can get keyword targeted traffic from and they let you try their service for free for 7 days. I managed to get over 300 targeted visitors to day to my site. https://～～
Livia Schacter http://～～


今までは[simple\-captcha](https://github.com/pludoni/simple-captcha)というgemを使って、画像認証をフォームに組み込んでいました。

![Screen Shot 2017-01-01 at 16.52.39 2.png](https://qiita-image-store.s3.amazonaws.com/0/7465/a52741ae-be8a-0d69-0fe6-d172d4e6e13d.png "Screen Shot 2017-01-01 at 16.52.39 2.png")

ただ、なんかカッコ悪いし、ユーザビリティも良くないので、サイトのデザインリニューアルを機に画像認証を外しました。

![Screen Shot 2017-01-08 at 15.19.20.png](https://qiita-image-store.s3.amazonaws.com/0/7465/ebc1e80a-5789-e82c-ab0a-7945f24b1afb.png "Screen Shot 2017-01-08 at 15.19.20.png")

「ボットが来たら、そのときに対策を考えよう」と思っていたのですが、サイトをリニューアルした翌日ぐらいに早速ボットがメッセージを送信してきたのです！

「Oh、こりゃあかん。。また、画像認証を組み込むしかないのかな～」と思ったのですが、今さら画像認証を復活させたくない。

というわけで別の対策を考えてみました。

## 海外スパムボット対策＝ひらがなの入力を必須にする

はい、なんててことはありません。
入力フォームのお問い合わせ本文に「ひらがなの入力を必須にする」というバリデーションを付けただけです。

日本人がメッセージを送る場合は、普通ひらがなが最低1文字は含まれるはずです。
それをひっくり返せば、海外スパムボットによるメッセージを禁止するバリデーションルールが作れます。

このバリデーションはコードで書くとわずか一行です。

```ruby
validates :text, presence: true, format: { with: /\p{Hiragana}/, \
  message: 'には日本語を含めてください。(Text must contain hiragana.)' }
```

こうすると、冒頭で紹介したようなスパムボットのメッセージはバリデーションエラーになります。

![Screen Shot 2017-01-08 at 15.26.01.png](https://qiita-image-store.s3.amazonaws.com/0/7465/bc963c3e-22c3-cb58-980a-944a867c2adb.png "Screen Shot 2017-01-08 at 15.26.01.png")

ただ、この方法だと本当に海外の人がメッセージを送ろうとしたときにもこのバリデーションエラーが発生します。
とはいえ、エラーメッセージには"Text must contain hiragana."と書いてあるので、どうしてもメッセージを送りたければ「こんにちは」の一言ぐらいがんばって書いてくれるだろう、と考えています。

もちろん、ボットが日本語でメッセージを送ってきた場合はこの方法では対処できません。
今のところそのケースは発生していないのですが、もしそういうことが起きたら別の対策を考えます。。

## この対策の効果を確認する

この対策をリリースした後のログを見ると、ボットがこのバリデーションエラーに引っかかっている記録が見つかりました。

```
Started POST "/contact" for 141.101.69.128 at 2017-01-08 11:41:06 +0900 
Processing by ContactsController#create as HTML 
  Parameters: {"utf8"=>"&#x2713;", "authenticity_token"=>"2wJfPX2fg8NSnF+AH41CDoeZpLbgU38Z+mVHMkWRz/+WHT8Ro6VyStwVSF+Zi2DOZeXh3hrCyGZ2p7WQXc02KQ==", "commit"=>"送信", "contact"=>{"name"=>"Natalie Murray", "email"=>"gnbxnmbux@jzlkkrsum.com", "tel"=>"Natalie Murray", "text"=>"I was just looking at your Contact - Coupé Baguette クープ バゲット site and see that your site has the potential to become very popular. I just want to tell you, In case you don't already know... There is a website network which already has more than 16 million users, and the majority of the users are interested in websites like yours. By getting your website on this service you have a chance to get your site more popular than you can imagine. It is free to sign up and you can read more about it here: http://s.t0m-s.be/5q - Now, let me ask you... Do you need your site to be successful to maintain your way of life? Do you need targeted traffic who are interested in the services and products you offer? Are looking for exposure, to increase sales, and to quickly develop awareness for your website? If your answer is YES, you can achieve these things only if you get your website on the service I am describing. This traffic service advertises you to thousands, while also giving you a chance to test the network before paying anything at all. All the popular sites are using this service to boost their traffic and ad revenue! Why aren’t you? And what is better than traffic? It’s recurring traffic! That's how running a successful website works... Here's to your success! Find out more here: http://nightcity25.ru/11a\r\nNatalie Murray http://ker.li/ol"}} 
  Rendering contacts/show.html.haml within layouts/application 
  Rendered contacts/_header.html.haml (0.3ms) 
  Rendered contacts/show.html.haml within layouts/application (2.8ms) 
  Rendered layouts/_header.html.haml (1.0ms) 
  Rendered layouts/_footer.html.haml (0.2ms) 
Completed 200 OK in 11ms (Views: 7.7ms | ActiveRecord: 0.0ms) 
```

POSTした記録は残っていますが、こちらに通知メールは届いていないので作戦成功です！:ok_woman:

## まとめ

というわけでこの記事では、海外スパムボットによるお問い合わせフォーム送信を禁止する方法を紹介しました。
技術的に高度なことをやっているわけではありませんが、そのぶんお手軽に実現できるので、同じような問題で困っている人がいたら参考にしてみてください。

### 妻のパン屋のWebサイトリニューアルについて

妻がやっているパン屋のWebサイトをリニューアルした話は僕のブログでも紹介しています。
デザイン周りの話や、Webサイトの品質チェックツール等を紹介しているので、興味がある方はこちらもどうぞ！

[妻のパン屋のWebサイトを4年ぶりにレスポンシブデザインに作り替えた話 \- give IT a try
](http://blog.jnito.com/entry/2017/01/05/071101)<a href="http://b.hatena.ne.jp/entry/http://blog.jnito.com/entry/2017/01/05/071101" class="bookmark-widget-counter"><img src="https://b.hatena.ne.jp/entry/image/http://blog.jnito.com/entry/2017/01/05/071101" alt="はてなブックマーク - 妻のパン屋のWebサイトを4年ぶりにレスポンシブデザインに作り替えた話"></a>


[![20170105051358.png](https://qiita-image-store.s3.amazonaws.com/0/7465/8b70dc2d-028a-a457-af93-37c22229f3fb.png "20170105051358.png")](http://blog.jnito.com/entry/2017/01/05/071101)

### 2020.1.20 追記
一時期[invisible_captcha](https://github.com/markets/invisible_captcha)というgemに移行していたんですが、最近またこの方式に戻ってきました。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">今まではinvisible_captchaっていうgemを使ってお問い合わせフォームの迷惑メッセージ送信を防いでたんだけど、最近はボットも賢くなってこの仕組みをすり抜けるようになってきたので、再度この方法で迷惑メッセージを防ぐようにしました。<a href="https://t.co/1pw25OQqDG">https://t.co/1pw25OQqDG</a></p>&mdash; Junichi Ito (伊藤淳一) (@jnchito) <a href="https://twitter.com/jnchito/status/1214369865105989632?ref_src=twsrc%5Etfw">January 7, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<blockquote class="twitter-tweet" data-conversation="none"><p lang="ja" dir="ltr">ちなみにinvisible_captchaっていうのはこのgemです。人間は通常入力しようとしない見えないテキストボックスをわざと用意して、そこに入力があればボットと見なす、という仕組みです。（で、この仕組みを回避するボットが最近増えてきた・・・🤖）<a href="https://t.co/f40b9vvsFR">https://t.co/f40b9vvsFR</a></p>&mdash; Junichi Ito (伊藤淳一) (@jnchito) <a href="https://twitter.com/jnchito/status/1214370556159483904?ref_src=twsrc%5Etfw">January 7, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>