わけわからないタイトルになってしまいました。これは
  • ウェブブラウザの JavaScript を使わずに、HTML と CSS でマウスの軌跡を追跡する方法が発見された
  • 実際に確認できるサンプルが Go 言語で実装されていたので、JavaScript に移植してみた
ということです。

まず、元ネタはこれです:
Researcher Finds CSS-Only Method to Track Mouse Movements

spyware


セキュリティの研究者である Davy Wybiral 氏の以下のデモ動画付きツイートを紹介する形で伝えられていました。このデモでは JavaScript が無効にされた Tor ブラウザが使われていますが、確かに左画面でのマウスの動きが右画面で確認できています。左の画面をユーザーが使っていて、右画面ではそこでのマウスの動きがほぼリアルタイムに再現されています:




もともとウェブページにおいては JavaScript を利用することでマウスの動きを検知することができるようになっています。移動したり、クリックしたり、クリックが開放されたり、といったタイミングや、そのイベントが発生したときのマウス位置を知ること自体はこれまでも可能でした。

ただし、それには JavaScript が有効になっている、という条件があります。多くのウェブブラウザにおいて、JavaScript ははじめから有効になっているもので、あえて無効になるよう設定しない限りは有効なままです。また最近のウェブページも JavaScript が有効になっている前提で作られているものが多いので、JavaScript が有効であることが特別に危険ということはないと思っています。 一方で JavaScript を使ったイタズラページが存在していることも事実で、あえて JavaScript を無効にしてから利用する、というシーンが(それによって思い通りに動かない、ということはあるかもしれませんが)ないわけではありません。


・・・という中での今回のニュースです。安全性を高める目的でウェブブラウザの JavaScript を無効にしていても、マウスの動きがウェブページ提供側に知られてしまう可能性(というか方法)があった、というものでした。上述の Davy 氏が Go 言語で作成したサンプルも公開されています(みるとわかりますが、このシンプルなコードだけで実現できるという明瞭さ!):
https://gist.github.com/wybiral/c8f46fdf1fc558d631b55de3a0267771


で、自分がこれを参考にしてサーバーサイド JavaScript である、Node.js 向けに移植したサンプルを作ってみた、というものでした。なのでサブジェクトは正確には
 『クライアント JavaScriptを使わずにCSSでマウスを追跡する方法』をサーバーサイド JavaScript で実装してみた
という感じになりますかね。

ちなみに移植したコードはこちら:
https://github.com/dotnsf/noscript-tracking.js


で、(ブラウザ側の)JavaScript を使わずにどうやってマウスの座標を調べるのか、という話です。具体的には CSS の :hover 疑似クラスと、その background 属性に画像を指定することで、特定のエリアに入ったことを知らせるリクエストをサーバー側に発生させる、という方法によって実現しています。

上記移植コードを見ると、2つのページが定義されています。1つはコンテキストルート( "/" )へのリクエストがあった際に表示される index ページで、そのテンプレートは views/index.ejs です。もう1つは "/watch" へのリクエストがあった際に表示される watch ページ(テンプレートは views/watch.ejs)です。index ページには JavaScript は一切使われていないのですが、このページの上でマウスを動かすと、その軌跡がほぼリアルタイムに watch ページから確認できるようになる、という内容のサンプルです:
2019051501
(↑左が index ページ、右が watch ページ。index ページ上でマウスを動かす様子が watch ページ上に表示されている)


では JavaScript を使わずに、どうやって index ページから watch ページへマウスの軌跡を知らせているかを説明します。今回ブラウザの JavaScript は使いませんが、サーバーサイドのロジックは必要になります。要はスタンドアロンでどうにかできる、というものではないということです。

まず index ページについて、index ページにアクセスすると画面には格子状(今回の例では 50x50)のブロックが表示されます。個々の格子は <p> タグで構成されています。格子は見えないスタイルにすることも可能ですが、今回は視覚的にわかりやすいようにあえて枠線を表示することで見やすくしています。

そしてスタイルシートを使って、個々の格子(<p>)に :hover 疑似クラスと、その時に背景画像が設定されるよう指定します(つまり各格子の上にマウスが来ると、その格子に背景画像が表示されるように設定します)。

これが CSS だけでマウス軌跡を追跡する方法の肝になります。つまり「ある格子の上をマウスが通過した時に、画像を表示するようなリクエストがサーバー側に送られ」ます。そしてサーバー側はそのようなリクエストに対してエラー処理を行い(つまり画像は表示されない=何も変わらない)、画像を表示する変わりにリクエスト内容を記録します。これによってどの格子の上をマウスが通過したのか、という情報をサーバー側に溜めることが可能になります:
2019051603


そしてもう1つの watch ページ側では上記の処理によってサーバー側に記録されたマウスの軌跡情報ごと取得し、index ページと同様の格子ブロックを描画します。ただしその際にマウスが通過した格子だけには背景色が設定され、マウスが通過していない格子と視覚的に違いがわかるようにしています:
2019051604


この2つのページを横に並べて表示し、index ページ(下図左)上でマウスを動かすと、その情報が watch ページ(下図右)上で確認できる、ということが実現できています。なるほどね~。
2019051501


※僕のコードでは watch ページをリロードする機能までは実装していないので、F5 キーや Ctl+R などで watch ページを定期的に更新する必要がありますが、リアルタイムでサーバー側には記録されている、ということがわかると思います。