【DevTools入門】おみくじの結果を改ざんしてフロントエンドの限界を知る

章: 1章

技術タグ: DevTools JavaScript

今回やること

前回は、HTML・CSS・JavaScriptだけで動くおみくじアプリを作りました。

今回は、そのおみくじアプリを使って、ブラウザの開発者ツール、つまりDevToolsを触ります。

目的は、かっこいいデバッグ技術を覚えることではありません。

今回の目的は、かなり重要です。

フロントエンド側のコードは、ユーザーに見える
フロントエンド側の表示は、ユーザー側で一部書き換えられる
だから、重要な処理をブラウザ側だけに置くのは危険

つまり今回は、作ったものをあえて壊します。

壊すことで、なぜサーバー側の処理が必要になるのかを体験します。


今回の前提

この記事では、第1話で作ったおみくじアプリが手元にある前提で進めます。

第1話のHTMLでは、CSSとJavaScriptの読み込みを head にまとめ、JavaScriptには defer を付ける形にします。

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>おみくじアプリ</title>
  <link rel="stylesheet" href="style.css" />
  <script src="script.js" defer></script>
</head>

defer を付けることで、HTMLの読み込みを邪魔せずにJavaScriptを読み込み、HTMLの解析が終わったあとに実行できます。

この連載では、読み込み系は head にまとめる方針で進めます。


DevToolsとは何か

DevToolsとは、ブラウザに付いている開発者向けの道具です。

Google Chromeなら、次の方法で開けます。

  • 画面上で右クリックして「検証」を選ぶ
  • キーボードのF12キーを押す
  • Windowsなら Ctrl + Shift + I を押す

DevToolsを使うと、HTMLやCSSの構造を見たり、JavaScriptのエラーを確認したり、通信内容を調べたりできます。

今回は主に、次の2つを使います。

タブ何を見るか
ElementsHTMLやCSSの状態を見る・一時的に書き換える
ConsoleJavaScriptをその場で実行する

最初は難しく見えるかもしれません。でも今回は、全部を覚える必要はありません。

まずは「ブラウザ側の中身は見える」という事実を体験するだけで十分です。


ElementsでHTMLを見てみる

まず、おみくじアプリをブラウザで開きます。

画面上で右クリックして「検証」を押すと、DevToolsのElementsタブが開きます。

Elementsタブでは、今ブラウザに表示されているHTML構造を見ることができます。

たとえば、今回のおみくじアプリには次のようなHTMLがあります。

<p id="result" class="omikuji__result">結果はここに表示されます</p>
<button id="draw-button" class="omikuji__button" type="button">
  おみくじを引く
</button>

ここで大事なのは、id="result"id="draw-button" のような情報が、ブラウザ側から見えるということです。

つまり、JavaScriptがどの要素を操作しているのか、ある程度推測できてしまいます。


Elementsで画面の文字を書き換えてみる

次に、Elementsタブ上で画面の文字を一時的に書き換えてみます。

たとえば、以下の文字を探します。

結果はここに表示されます

Elementsタブ上でその文字をダブルクリックすると、文字を編集できることがあります。

そこで、次のように書き換えてみます。

大吉

すると、実際の画面上でも表示が変わります。

ここで勘違いしてはいけないのは、これはサーバー上のファイルを書き換えたわけではないということです。

あくまで、自分のブラウザ上で一時的に表示を書き換えただけです。

ページを再読み込みすれば、元に戻ります。

ブラウザに表示されているものは、ユーザー側で一時的に書き換えられる

ConsoleでJavaScriptを実行してみる

次に、Consoleタブを使います。

Consoleでは、JavaScriptをその場で実行できます。

まずは、結果表示エリアの文字をJavaScriptで書き換えてみます。

document.getElementById('result').textContent = '大吉';

これをConsoleに貼り付けてEnterを押すと、画面上の結果が 大吉 に変わります。

これは、第1話で書いた textContent と同じ考え方です。

つまり、ブラウザ側で動くJavaScriptは、ユーザーの手元でも実行できるということです。


ボタンの文字も変えてみる

結果だけでなく、ボタンの文字も変えられます。

document.getElementById('draw-button').textContent = '絶対に大吉を引く';

これを実行すると、ボタンの表示が変わります。

もちろん、これも自分のブラウザ上だけの一時的な変更です。

しかし、ここで大事なのは「画面の表示だけを信用してはいけない」という感覚です。


見た目も変えられる

ConsoleからCSSのような見た目も一時的に変えられます。

document.body.style.backgroundColor = '#111';
document.body.style.color = '#fff';

実行すると、背景色や文字色が変わります。

これは遊びのように見えますが、DevToolsの重要な使い道でもあります。

実務では、CSSを少し変えて見た目を確認したり、問題の原因を切り分けたりする時にも使います。


JavaScriptファイルの中身も見える

DevToolsでは、読み込まれているJavaScriptファイルの中身も確認できます。

Chrome DevToolsなら、SourcesタブやNetworkタブから script.js を見ることができます。

そこには、第1話で書いたような処理が見えるはずです。

const resultText = document.getElementById('result');
const drawButton = document.getElementById('draw-button');

const fortunes = ['大吉', '中吉', '小吉', '吉', '凶'];

/**
 * おみくじ結果をランダムに1つ選んで画面に表示する
 *
 * @returns {void}
 */
function drawFortune() {
  const randomIndex = Math.floor(Math.random() * fortunes.length);
  const selectedFortune = fortunes[randomIndex];

  resultText.textContent = selectedFortune;
}

drawButton.addEventListener('click', drawFortune);

このコードを見ると、おみくじ結果の候補が配列で書かれていることがわかります。

大吉
中吉
小吉
吉
凶

つまり、ブラウザに読み込ませているJavaScriptは、基本的にユーザーから見えるものだと考える必要があります。


大吉100%にするならどうなるか

ここからが今回の核心です。

もし、このおみくじアプリを悪意ある人が見たら、こう考えるかもしれません。

この処理、書き換えたら大吉だけ出せるのでは?

実際、JavaScriptの処理を次のように変えると、必ず大吉になります。

function drawFortune() {
  resultText.textContent = '大吉';
}

さらに、完成形として見るとこうなります。

const resultText = document.getElementById('result');
const drawButton = document.getElementById('draw-button');

const fortunes = ['大吉', '中吉', '小吉', '吉', '凶'];

/**
 * おみくじ結果を必ず大吉にして画面に表示する
 *
 * 注意:
 * これは学習用の改ざん例です。
 *
 * @returns {void}
 */
function drawFortune() {
  resultText.textContent = '大吉';
}

drawButton.addEventListener('click', drawFortune);

これは学習用の例です。実際の他人のサイトやサービスに対して、このような改ざんや不正利用をしてはいけません。

ここで理解したいのは、攻撃方法そのものではなく、フロントエンド側に重要な判定を置く危険性です。


ただのおみくじなら問題は小さい

今回作っているのは、ただのおみくじアプリです。

だから、画面上で大吉に書き換えられても大きな問題にはなりません。

しかし、もしこれが次のような仕組みだったらどうでしょうか。

  • 大吉が出たらギフト券プレゼント
  • 当たりが出たらクーポン発行
  • 抽選で有料コンテンツを無料開放
  • ゲーム内アイテムを配布

このような場合、ブラウザ側だけで当たり判定をしていると危険です。

なぜなら、ユーザー側で見える処理、ユーザー側で操作できる処理は、信用しきれないからです。


フロントエンド側でやっていいこと・危険なこと

ここで、フロントエンド側でやっていいことと、危険なことを整理します。

種類考え方
やってよいこと見た目の変更、入力補助、簡単な表示切り替えユーザー体験を良くするために使う
注意が必要なこと入力チェック、料金計算、抽選結果最終判断はサーバー側でも確認する
置いてはいけないもの秘密情報、重要な認証情報、不正されると困る判定ブラウザ側に見せない

JavaScriptが悪いわけではありません。JavaScriptは、画面を動かしたり、ユーザー体験を良くしたりする強力な道具です。

ただし、重要な判断をブラウザ側だけに任せるのが危険なのです。


今回わかったこと

今回、DevToolsを使って次のことを体験しました。

  • ElementsでHTML構造を見られる
  • Elementsで画面の文字を一時的に書き換えられる
  • ConsoleでJavaScriptを実行できる
  • JavaScriptから画面の文字を変更できる
  • 読み込まれているJavaScriptファイルの中身を確認できる
  • フロントエンド側の処理はユーザーから見える
  • 重要な処理をフロントエンドだけに置くのは危険

これはWeb開発のかなり大事な入口です。

フロントエンドは、ユーザーの手元で動きます。だからこそ、便利ですが、信用しすぎてはいけません。


では、どうすればいいのか

答えは、重要な処理をサーバー側に移すことです。

今回のおみくじで言えば、抽選処理をJavaScriptだけで行うのではなく、PHP側で行う形にします。

ブラウザ側のJavaScriptは、PHPに対して「おみくじを引きたい」とリクエストします。

PHPはサーバー側で抽選を行い、結果だけをブラウザに返します。

ブラウザ
↓
PHPにリクエスト
↓
PHP側で抽選
↓
結果だけをブラウザへ返す

こうすると、少なくとも抽選ロジックそのものをブラウザ側に丸見えで置くよりは安全になります。

この考え方が、フロントエンドとバックエンドを分ける大きな理由のひとつです。


次回予告

次回は、今回のおみくじアプリの抽選ロジックをPHP側に移します。

JavaScriptだけで結果を決めるのではなく、サーバー側であるPHPに抽選を担当させます。

次回のテーマは、以下です。

【PHP入門】おみくじの抽選ロジックをサーバー側に移してみる

ここから、ブラウザだけで動くアプリから、サーバーと通信するWebアプリへ進みます。

フロントエンドの限界を見たあとに、バックエンドの必要性を理解する。

ここが、Webシステム開発への入口です。