MENU

PHPで理解するハッシュ関数

目次

はじめに: ハッシュ関数は「元に戻さない」ための変換

前回の記事では、Cookieとセッションを使ってログイン状態を管理する仕組みを見ました。では、ログインに使うパスワードは、サーバー側でどのように保存すればよいのでしょうか。

あわせて読みたい
CookieとセッションをPHPで理解する CookieとセッションをPHPで理解する 副題: JavaScript/PHPで、試験に出る知識を実務につなげる はじめに: Cookieとセッションは「ログイン状態」を理解する入口 Webサイ...

実務では、パスワードをそのまま保存することは避けます。もしデータベースの内容が漏えいしたとき、平文のパスワードがそのまま読めてしまうからです。そこで重要になるのが、ハッシュ関数です。

ハッシュ関数は、入力されたデータからハッシュ値と呼ばれる値を作る仕組みです。大きな特徴は、基本的に「元に戻す」ことを目的にしていない点です。暗号化のように、あとから復号して元の文字列を取り出すものではありません。

基本情報処理技術者試験でも、ハッシュ関数はセキュリティ、認証、改ざん検知といった文脈で登場します。用語だけを見ると少し抽象的ですが、PHPで実際に文字列をハッシュ化してみると、役割がかなりつかみやすくなります。

この記事では、PHPのサンプルコードを使いながら、ハッシュ関数の基本、暗号化との違い、パスワード保存での使い方を整理していきます。

ハッシュ関数とは何か

ハッシュ関数とは、入力されたデータからハッシュ値を作る関数です。入力するデータは、文字列でもファイルでもかまいません。ハッシュ関数を通すと、元のデータに対応する一定の形式の値が得られます。

ハッシュ関数には、いくつか大事な特徴があります。

  • 同じ入力からは、同じハッシュ値が得られる
  • 入力が少しでも変わると、ハッシュ値も大きく変わる
  • ハッシュ値から元のデータを戻すことは前提にしない

たとえば、hello という文字列をハッシュ化した結果と、Hello という文字列をハッシュ化した結果は別物になります。大文字と小文字が1文字違うだけでも、コンピュータにとっては違うデータだからです。

この性質は、パスワードの保存やデータの改ざん検知に使われます。「同じ入力なら同じ値になる」「でも元の文字列には戻せない」というところが、ハッシュ関数を理解する入口です。

PHPで文字列をハッシュ化してみる

PHPでは、hash() 関数を使うと文字列をハッシュ化できます。ここでは、代表的なハッシュアルゴリズムのひとつであるSHA-256を使ってみます。

<?php
echo hash('sha256', 'hello');

実行すると、hello という文字列に対応するハッシュ値が表示されます。同じコードを何度実行しても、入力が同じであれば結果も同じです。

次に、同じ文字列と少しだけ違う文字列を比べてみます。

<?php
echo hash('sha256', 'hello') . PHP_EOL;
echo hash('sha256', 'hello') . PHP_EOL;
echo hash('sha256', 'Hello') . PHP_EOL;

1行目と2行目は同じ入力なので、同じハッシュ値になります。一方、3行目は先頭が大文字の Hello なので、まったく違うハッシュ値になります。

ハッシュ関数の説明では、md5() を見かけることもあります。ただし、MD5は現在の実務では安全性の面で注意が必要な古い方式です。学習用に名前を知っておくのはよいですが、パスワード保存などの重要な用途では使わない、と覚えておきましょう。

ハッシュ化と暗号化の違い

ハッシュ化と混同しやすい言葉に、暗号化があります。どちらも元のデータを別の形に変換する点では似ていますが、目的が違います。

暗号化は、元に戻すことを前提にした変換です。たとえば、秘密のメッセージを暗号化して送り、受け取った人が鍵を使って復号すれば、元のメッセージを読めます。ここでは「復号できること」が重要です。

一方、ハッシュ化は元に戻すことを目的にしません。hello からハッシュ値を作ることはできますが、そのハッシュ値から hello を取り出す使い方はしません。入力された値が同じかどうかを、ハッシュ値を使って確認するイメージです。

パスワード保存でよくある誤解が、「パスワードを暗号化して保存する」という表現です。実務では、復号できる形で保存するよりも、元に戻せない形でハッシュ化して保存するのが基本です。ログイン時には、入力されたパスワードを同じ方法で確認し、保存済みのハッシュ値と照合します。

基本情報処理技術者試験でも、暗号化、復号、ハッシュ化の違いは混同しやすいところです。「暗号化は戻せる」「ハッシュ化は戻すためのものではない」と整理しておくと、問題文を読みやすくなります。

パスワード保存では password_hash() を使う

ここまでの説明だけを見ると、パスワードも hash('sha256', $password) でハッシュ化して保存すればよさそうに見えるかもしれません。

ただし、実務のパスワード保存では、単純に hash() を使うのではなく、PHPが用意している password_hash() を使うのが基本です。

理由は、パスワード保存には通常のハッシュ化だけでは足りない工夫が必要だからです。たとえば、同じパスワードでも毎回違うハッシュ値になるようにするソルトや、総当たり攻撃をしにくくするための計算コストが関係します。

password_hash() を使うと、こうしたパスワード保存向けの処理をPHPに任せられます。自分でソルトを連結したり、独自ルールでハッシュ化したりするより、安全な標準機能を使う方が実務では適しています。

PHPでパスワードをハッシュ化して検証する

ユーザー登録時には、入力されたパスワードをそのまま保存せず、password_hash() でハッシュ化した値を保存します。

<?php
$password = 'secret123';

$passwordHash = password_hash($password, PASSWORD_DEFAULT);

echo $passwordHash;

ここで表示される値が、データベースに保存するハッシュ値です。保存するのは secret123 という元のパスワードではありません。

ログイン時には、ユーザーが入力したパスワードと、保存済みのハッシュ値を password_verify() で照合します。

<?php
$inputPassword = 'secret123';
$savedHash = '$2y$10$example...'; // 実際にはデータベースから取得する

if (password_verify($inputPassword, $savedHash)) {
    echo 'ログイン成功';
} else {
    echo 'ログイン失敗';
}

password_verify() は、入力されたパスワードが保存済みのハッシュ値と対応しているかを確認します。ハッシュ値から元のパスワードを取り出しているわけではありません。

この点が、ハッシュ化を使ったパスワード保存の大事なところです。サーバー側は元のパスワードを知らなくても、入力されたパスワードが正しいかどうかを確認できます。

ハッシュ関数は改ざん検知にも使われる

ハッシュ関数は、パスワード保存だけでなく、データが改ざんされていないかを確認する用途にも使われます。

たとえば、ある文章やファイルのハッシュ値をあらかじめ記録しておきます。あとから同じデータをもう一度ハッシュ化して、記録しておいたハッシュ値と一致すれば、内容は変わっていないと判断できます。逆に、ハッシュ値が変わっていれば、どこかで内容が変化した可能性があります。

PHPで簡単に見ると、次のようになります。

<?php
$original = '重要なメッセージ';
$changed = '重要なメッセージ。';

echo hash('sha256', $original) . PHP_EOL;
echo hash('sha256', $changed) . PHP_EOL;

この例では、2つ目の文字列に句点が1つ増えているだけです。それでも、ハッシュ値は大きく変わります。人間にとっては小さな違いでも、コンピュータにとっては別のデータとして扱われるからです。

実務では、ダウンロードしたファイルが壊れていないかを確認するチェックサムや、データの整合性確認などで同じ考え方が使われます。基本情報処理技術者試験でも、ハッシュ関数は「改ざん検知」と結びつけて問われることがあります。

ただし、ハッシュ値が一致するからといって、どんな場面でも完全に安全と言い切れるわけではありません。異なる入力から同じハッシュ値が得られてしまうことを衝突と呼びます。実務では、用途に応じて安全性の高いハッシュアルゴリズムを選ぶことが重要です。

試験ではどう問われるか

基本情報処理技術者試験では、ハッシュ関数そのもののコードを書くよりも、性質や用途を理解しているかが問われます。

まず押さえたいのは、ハッシュ値から元のデータを復元することは目的ではない、という点です。問題文に「元のデータに戻す」「復号する」といった表現が出てきた場合、それは暗号化の話なのか、ハッシュ化の話なのかを切り分ける必要があります。

次に、同じ入力からは同じハッシュ値が得られるという性質です。この性質があるからこそ、パスワードの照合や改ざん検知に使えます。逆に、入力が少しでも変わればハッシュ値も変わるため、データの変化に気づきやすくなります。

また、衝突という用語も重要です。衝突とは、異なる入力から同じハッシュ値が得られてしまうことです。現実のハッシュ関数では、ハッシュ値の長さに限りがあるため、理論上は衝突が起こり得ます。そのため、セキュリティ用途では古い方式ではなく、安全性の高い方式を選ぶ必要があります。

試験対策としては、次のように整理しておくとよいでしょう。

  • ハッシュ化は、元に戻すための変換ではない
  • 同じ入力からは同じハッシュ値が得られる
  • 入力が変わると、ハッシュ値も変わる
  • 改ざん検知や認証に使われる
  • 衝突とは、異なる入力から同じハッシュ値が得られること
  • 暗号化、復号、ハッシュ化の違いを混同しない

実務ではどう使われるか

実務でハッシュ関数が使われる場面は、パスワード保存だけではありません。

代表的な用途には、次のようなものがあります。

  • パスワードのハッシュ化
  • ファイルの整合性チェック
  • API署名やトークン検証の一部
  • キャッシュキーの生成
  • 重複データの検出

たとえばキャッシュでは、URLや検索条件などからハッシュ値を作り、それをキーとして使うことがあります。長い文字列や複雑な条件をそのまま扱うより、一定の形式の値に変換した方が管理しやすいからです。

また、API連携では、送信内容と秘密情報を組み合わせてハッシュ値を作り、リクエストが改ざんされていないかを確認する仕組みに使われることがあります。この場合は、単なる hash() ではなく、HMACのような仕組みが使われることもあります。

大切なのは、ハッシュ関数は用途によって使い分ける必要があるという点です。文字列の変化を確認したいだけなのか、パスワードを保存したいのか、外部との通信を検証したいのかによって、選ぶ関数や考え方が変わります。

PHPで一般的なハッシュ値を試すなら hash()、パスワード保存なら password_hash()password_verify()。まずはこの使い分けから押さえておくと、実務のコードも読みやすくなります。

まとめ: ハッシュ関数はWebセキュリティの基礎

ハッシュ関数は、入力データからハッシュ値を作る一方向の変換です。同じ入力からは同じハッシュ値が得られ、入力が少しでも変わると結果も変わります。

暗号化と違い、ハッシュ化は元に戻すことを目的にしません。この違いを押さえておくと、パスワード保存、改ざん検知、認証の仕組みが理解しやすくなります。

PHPでハッシュ関数の基本を試すなら hash() が使えます。ただし、パスワード保存では password_hash()password_verify() を使うのが基本です。

基本情報処理技術者試験では、ハッシュ関数の性質、暗号化との違い、改ざん検知への利用が問われやすいポイントです。実務でもログインやセキュリティの理解につながるので、用語だけでなくコードの動きとあわせて覚えておきましょう。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

20代前半に、ゲームボーイアドバンス、ニンテンドーDS、Wii向けソフトの開発に携わりました。

その後、20代後半にかけては組み込み系エンジニアとして、主にサーバーソフトウェアの開発を経験。

30代からはWebエンジニアとして、さまざまなWebサービスの開発に携わってきました。

現在は40代となり、ゲーム開発、組み込み開発、Web開発で培った経験を活かしながら、技術をわかりやすく伝える活動にも取り組んでいます。

コメント

コメントする

CAPTCHA


目次