🕵️‍♂️

クライアント側バリデーション:ユーザーエクスペリエンスの向上とサーバー負荷の軽減

2023/07/10に公開

はじめに

WEBアプリケーションはクライアントとサーバの間で多くのデータ交換を行います。このプロセスに欠かせないユーザの入力は、通常入力フォームを通じてサーバに送信されます。
なので、入力フォームはWEBアプリケーションにおいてクライアントの情報をサーバに渡す重要な機能をします。

しかし、適切なバリデーションが行われないと、これらのフォームは意図せずに不正なデータや不完全な形式のデータを転送する経路になってしまう可能性があります。その結果WEBアプリケーションのセキュリティ問題や脆弱性になる可能性があります。

このようなリスクを避けるために、は、クライアント側のバリデーションのような戦略を採用する必要があります。
今回は入力フォームとクライアント側のバリデーションについて勉強したことを共有したいと思います。

入力フォーム

ユーザーからデータを受け取るために、WEBアプリケーションはフォームと呼ばれる要素を利用します。フォームは、inputlabelbuttonselectなどの関連タグを<form></form>タグで囲むことで作成されます。
例えば、以下のコードが基本的なフォームになります。

<form action="/" method="get">
  <label for="name">名前</label>
  <input id="name" name="my-name" type="text" />
  <label for="age">年齢</label>
  <input id="age" name="my-age" type="number" />
  <button type="submit">提出</button>
  <button type="reset">リセット</button>
</form>
  • form:フォームを開始と終了を定義して、データの送信先と送信方法を指定します。
  • input:ユーザーのの入力を取り込むための入力ボックスを生成します。指定されたtype属性に基づいて異なるデータタイプを扱うことができます。
  • label:入力ボックスの名前を定義し、関連する入力フィールドの説明フィールドの説明をテキストに提供します。
  • button:ボタンを生成してフォームデータの送信やリセットなど、様々な機能をします。

form

https://developer.mozilla.org/ja/docs/Web/HTML/Element/form
<form>タグはHTMLの基本要素であり、ユーザー入力を可能にするフォームを定義します。<input><select>buttonなどの要素を囲んで、ユーザーの操作やサーバへのデータ送信に使われます。<form>タグの属性としてはactionmethodenctypeautocompleteがあります。

  • action:送信時にフォームデータを送信するURLを指定します。
  • method:データの送信方法を定義します。主な方法は、GETPOSTがあります。
  • enctypemethodPOSTの場合フォームをサーバに送信する際にコンテンツのMIMEタイプを表します。application/x-www-form-urlencodedが基本値です。
  • autocomplete:自動完成有可否も表示します。

input

https://developer.mozilla.org/ja/docs/Web/HTML/Element/input
inputタグは、様々なタイプのユーザーの入力をできる汎用的な要素です。typeに用事て、テキスト、セレクトボックス(ラジオ、チェックボックス)、ボタンなどの機能ができます。以下のいくつかのタイプをご紹介します。具体的にはMDNを参考してください。

  • text : 一般的なテキスト入力を受けます。ディフォルト値です。
  • password : パスワード項目で入力すると*処理をして入力内容がマスキングされて、画面に表示されないです。
  • button : カスタム関数を実行できるボタンです。関数をバインディングしないと何も機能しません。
  • submit : formタグのactionに指定されたアドレスに内容を転送します。valuesubmitボタンの名前になります。
  • radiocheckbox : ラジオ、テキストボタンを生成します。
  • search : ユーザーの検索を受けます。入力内容中改行を無視します。それと、入力するとXというボタンが出てきて入力内容を削除することができます。モバイルで確認すると虫眼鏡アイコンが出てきます。
  • tel : 電話番号を入力を受けます。モバイルで確認すると数字用キーボードが表示されます。

フォームデータを送信する際に発生する問題

ユーザーからの情報をインプット要素で受けてフォームを通じてサーバに送信できることを確認しました。しかし、フォームデータを検証せずに送信するといくつかの重要な問題が発生する可能性があります。

不完全または不正なデータ

フォームデータをそのまま送信すると不完全または否定なデータをがサーバ側に送信されます。
まず、不完全なデータはサーバ側が特定なデータを期待する場合アプリケーションでエラーを引き起こす可能性があります。
それと、不正なデータの場合重要なWEBセキュリティリスクを含むより深刻な結果をもたらす可能せがあります。このような脅威では、クロスサイトスクリプてイング(XSS)、クロスサイトリクエスト偽造(CSRF)、SQLインジェクション攻撃などがあります。

不必要なサーバ負荷

検証されてないデータがサーバに到着するとサーバのリソースに負荷がかかる可能せがあります。極端的な場合、DoS(サービス拒否)またはDDOS(分散サービス拒否)攻撃が発生するかもしれません。
このような攻撃によってユーザがアプリケーションにアクセスできなくなります。

ユーザーエクスペリエンス

不完全、不正、不要なサーバ以外にユーザーエクスペリエンスとしてもフォームの検証は必要です。
どこかのサイトで情報を入力した後、「次へのボタン」をクリックした際に分からないエラーが発生して最初から情報を入力したことがあると思います。

なので、サーバに送る前にクライアント側で検証すれば、改めて最初から入力しなくても良いメリットがあります。

クライアント側のバリデーション

不完全または不正なデータ、不必要なサーバ負荷を避けてユーザーエクスペリエンス上げるためには、検証がバリデーションが必要です。バリデーションではクライアント側のバリデーション、サーバ側のバリデーションなどがあります。
今回はクライアント側のバリデーションについて調査しました。
クライアント側のバリデーションはクライアント側でサーバに送る前にクライアント側で検証を実施することです。

HTML5のバリデーション

HTML5の属性を利用してクライアント側のバリデーションを実装することができます。このような属性は必要な入力タイプを指定して、入力したパターンを作るなどの方法を利用してフォームの要素に追加することができます。
バリデーションでHTML5を使うとJavaScriptを利用せず、バリデーションを実装できるメリットがあります。

HTML5のバリデーションチェック

HTML5を利用してチェックできる属性は下記になります。

  • required : required属性を入力フィールドに追加してユーザーがフォームを提出する前に入力しなければならないことを指定できます。
  • pattern : `pattern`属性を使用すると、入力フィールドの値が一致しなければならない正規表現式を指定できます。
  • minmax : 数字タイプの最小値および最大値を指定できます。
  • minlengthmaxlength : テキスト(文字列)の最小および最大長さを指定できます。
  • type : 入力データが数字、メール、テキストなどのタイプを指定できます。

required

<form>
  <label for="name">名前:</label><br />
  <input type="text" id="name" name="name" required /><br />
  <button>提出</button>
</form>

名前をrequired属性を指定したため、Submitボタンを押したら、警告が出て提出できません。

pattern

<form>
  <label for="pwd">パスワード:</label><br />
  <input
    type="password"
    id="pwd"
    name="pwd"
    pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}"
    title="パスワードは1以上の大文字、1以上の小文字、1以上の数字、8桁以上の文字列でお願いします。"
    required
    /><br />
    <button>提出</button>
</form>

パスワードにpattern属性を指定したため、指定したパターンに合わせなかったらSubmitボタンを押しても進めれません。

minとmax

<form>
  <label for="quantity">容量(1から5の間を選んでください)</label><br />
  <input
    type="number"
    id="quantity"
    name="quantity"
    min="1"
    max="5"
    required
  /><br />
  <button>提出</button>
</form>

容量の入力フィールドにminmax属性を設定して1から5間の値のみ指定することができます。

minlengthとmaxlength

<form>
  <label for="username">ユーザー名:</label><br />
  <input
    type="text"
    id="username"
    name="username"
    minlength="5"
    maxlength="15"
    required
  /><br />
  <button>提出</button>
</form>

minlengthmaxlengthを使用してユーザーの名が515の間の長さかをチェックします。

type

<form>
  <label for="quantity">メール</label><br />
  <input type="email" id="email" name="email" required /><br />
  <button>提出</button>
</form>

メールにemailタイプを指定して、有効なメールアドレスではないと提出できません。

JavaScriptのバリデーション

JavaScriptを利用してクライアント側のバリデーションを実行できます。JavaScriptはカスタマイズできるので、様々な場合をチェックすることができます。
以下はJavaScriptのバリデーションを利用して実装した例です。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <form>
      <label for="name">名前</label>
      <input type="text" class="nameField" />
      <button type="submit">提出</button>
    </form>
    <script src="index.js"></script>
  </body>
</html>
const form = document.querySelector("form");
const nameField = document.querySelector(".nameField");

const handleClick = () => {
  if (nameField.value === "") {
    alert("Name must be filled out.");
    return false;
  }
};

form.addEventListener("submit", handleClick);

HTML5とJavaScriptのバリデーションの比較

HTML5とJavaScript両方利用して、クライアント側のバリデーションを実装することができますが、いくつかの違いがあります。

  • 実装の容易さ : HTM5の場合は、入力フィールドに特定の属性を追加追加するだけなので、実装が簡単です。一方、JavaScriptの場合は、カスタム関数を作成する必要があり、より複雑になる可能性があります。
  • 柔軟性 : JavaScriptの場合はHTML5よりも柔軟性があります。JavaScriptを使用すると、カスタムバリデーションルールを作成し、即時フィードバックを提供し、ユーザーインタラクションに基づいて動的な検証ルールを作成することができます。
  • ブラウザ互換性 : HTML5バリデーションは、一部ブラウザ、特に古いブラウザではサポートされてませんが、JavaScriptのバリデーションはより広くサポートされてます。

実は😇

クライアント側のバリデーションはユーザーエクスペリエンスを向上させ、不要なサーバロードの削減で重要です。しかし、HTML5とJavaScriptを利用したバリデーションは限界があります。

悪意のあるユーザーがクライアント側のバリデーションを簡単に回避し、セキュリティの脆弱性を引き起こしやすいです。
ブラウザでJavaScriptを無効にするか、開発者ツールを使用してHTMLを変更することで、クライアント側の検証を回避することができます。
例えば、入力フィールドからrequired属性を削除したり、pattern属性を変更して全ての入力を許可したりすることができます。また、フォームを完全に迂回してHTTPリクエストをサーバ直接送ることもできます。

サーバ側のバリデーション

クライアント側のバリデーションが回避できることを考慮すると、サーバ側のバリデーションは必ず必要です。
サーバ側のバリデーションは、フォームデータが送信された後にサーバで実行されます。これにより、クライアント側の検証が回避された場合でも、サーバ側のバリデーションを処理または保存する前に確認できます。なので、サーバ側のバリデーションはユーザがが回避することが難しいので、、不正なデータや悪意のあるデータに対する重要な対策になります。

クライアント側のバリデーションが必要な理由

であれば、クライアント側のバリデーションは回避しやすいため不要、サーバ側のバリデーションのみ必要だと思われるかもしれません。
それにも関わらず、クライアント側のバリデーションが必要理由は、即時のフィードバックをすることで、ユーザーがサーバの応答を待つことなく、入力できます。なので、ユーザーエクスペリエンスを向上させることもできます。
また、データがサーバに送信される前に単純な入力エラーを検出することで、不要なサーバのj負担を減らすことができます。
但し、これを唯一の検証方法として使用してはいけません。データのセキュリティーと整合性を維持するためにバックアップとして、常にサーバ側の検証が行われていることを確認する必要があります。クライアント側とサーバ側の両方のバリデーションを使用するとよりよいユーザーエクスペリエンスとセキュリティーを向上することができます。

まとめ

ブラウザ上のユーザー入力はフォームを利用してサーバに送信することができます。但し、適切な検証なくてサーバに全ての情報を送信するとサーバに不要なデータや負担を起こせます。なので、クライアント側に適切なバリデーションを実施して可能な限りチェックしてユーザーエクスペリエンスとサーバの負担を減らす方法がありました。
しかし、クライアント側のバリデーションは回避しやすいため、サーバ側のバリデーションも必ず実行しないといけません。

皆さんにも分かりやすく説明できていればと嬉しいです。

Discussion