Webアプリケーションを作っていると、必ずと言っていいほど直面するのが「セキュリティ」の問題です。
「パスワードってどうやって管理するのが正解?」
このように不安になったことはありませんか?
PHPにはデータを守るための強力な機能が備わっていますが、用途によって「暗号化」と「ハッシュ化」を使い分ける必要があります。
ここを間違えると、せっかく暗号化したのに情報漏洩……なんてことにもなりかねません。
この記事では、PHPの標準ライブラリであるOpenSSLを使った「元に戻せる暗号化(復号化)」の実装方法を中心に、パスワード管理の正解、そして私が過去にやらかした失敗談まで、最新情報を交えて解説します。
![]() 執筆者:マヒロ |
|
「暗号化」と「ハッシュ化」の決定的な違い
コードを書く前に、これだけは絶対に押さえておきたいポイントがあります。
それは「暗号化(Encryption)」と「ハッシュ化(Hashing)」の違いです。
ここを混同していると、設計レベルで失敗します。
元に戻せるのが「暗号化」、戻せないのが「ハッシュ化」
- 暗号化: 鍵を使ってデータを無意味な文字列に変換すること。正しい鍵があれば元のデータに戻す(復号する)ことができます。
- 用途:クレジットカード番号、住所、メールアドレスなど、後でシステムが利用するデータ。
- ハッシュ化: データを一方通行の計算で別の文字列に変換すること。元のデータに戻すことはできません。
- 用途:ログインパスワード。
「パスワードを暗号化して保存する」というのは、実はセキュリティ的には間違いです(鍵が漏れたら全員のパスワードがバレるから)。
パスワードは「ハッシュ化」、個人情報は「暗号化」。この使い分けを大前提として進めていきましょう。
【実践】OpenSSL関数でデータを暗号化・復号化する
PHPで可逆的な(元に戻せる)暗号化を行うなら、標準拡張モジュールのOpenSSL関数を使うのが現在のデファクトスタンダードです。
かつては mcrypt というライブラリがありましたが、今は完全に廃止されているので使ってはいけません。
openssl_encrypt と openssl_decrypt の使い方
ここでは、現在もっとも一般的で安全とされるアルゴリズム AES-256-CBC を使った実装例を紹介します。
<?php
class Security
{
// 暗号化方式(AES-256-CBC が推奨)
const METHOD = 'AES-256-CBC';
// 秘密鍵(実際は.envなどで管理し、絶対に公開しないこと!)
private $key = 'my_secret_password_key_12345';
/**
* 文字列を暗号化する
*/
public function encrypt($data)
{
// IV(初期化ベクトル)の長さを取得
$ivLength = openssl_cipher_iv_length(self::METHOD);
// ランダムなIVを生成(これがないと毎回同じ暗号文になり危険)
$iv = openssl_random_pseudo_bytes($ivLength);
// 暗号化実行
$encrypted = openssl_encrypt($data, self::METHOD, $this->key, 0, $iv);
// IVと暗号文を結合してBase64エンコード(保存しやすくするため)
// 復号時にIVが必要になるため、一緒に保存しておくのが定石です
return base64_encode($iv . $encrypted);
}
/**
* 暗号文を復号(元のデータに戻す)する
*/
public function decrypt($data)
{
// Base64デコード
$data = base64_decode($data);
// IVの長さを取得
$ivLength = openssl_cipher_iv_length(self::METHOD);
// データからIV部分を切り出す
$iv = substr($data, 0, $ivLength);
// 残りの部分が実際の暗号文
$encrypted = substr($data, $ivLength);
// 復号実行
return openssl_decrypt($encrypted, self::METHOD, $this->key, 0, $iv);
}
}
// --- 実行テスト ---
$security = new Security();
$originalText = "このデータは秘密です!";
echo "元のデータ: " . $originalText . "\n";
// 暗号化
$cipherText = $security->encrypt($originalText);
echo "暗号化後: " . $cipherText . "\n";
// 復号(複合化)
$decryptedText = $security->decrypt($cipherText);
echo "復号後: " . $decryptedText . "\n";
?>
実行結果とコードのポイント
元のデータ: このデータは秘密です!
暗号化後: dC45aG...(ランダムな文字列)...==
復号後: このデータは秘密です!
このコードで特に重要なのが 「IV(初期化ベクトル)」 の扱いです。
openssl_encrypt を使うとき、「鍵さえあればいいんでしょ?」と思いがちですが、IVを使わずに(あるいは固定のIVで)暗号化すると、同じ平文から毎回同じ暗号文が生成されてしまい、解読のヒントを与えてしまいます。
上記のコードでは、暗号化のたびにランダムなIVを生成し、それを暗号文の先頭にくっつけて保存しています。
復号するときは先頭からIVを取り出して使う仕組みです。
これなら安全かつ、DBのカラムも1つで済みます。
【パスワード編】password_hash でハッシュ化する
次に、ログインパスワードの保存方法です。
先ほどの openssl_encrypt ではなく、PHPがネイティブに提供しているパスワードハッシュ関数を使います。
安全なパスワード保存と検証のコード
<?php
// ユーザーが入力したパスワード
$password = "MyStrongPassword123!";
// 1. ハッシュ化して保存(登録時)
// PASSWORD_DEFAULT を指定すると、その時のPHPバージョンで推奨される最強のアルゴリズムが選ばれます
// 2026年現在は通常 Argon2id や Bcrypt が使われます
$hash = password_hash($password, PASSWORD_DEFAULT);
echo "DBに保存するハッシュ値: " . $hash . "\n";
// 2. パスワードの検証(ログイン時)
// 入力されたパスワードと、DBから取り出したハッシュ値を比較
$loginInput = "MyStrongPassword123!";
if (password_verify($loginInput, $hash)) {
echo "ログイン成功!";
} else {
echo "パスワードが間違っています。";
}
?>
password_hash 関数は、ソルト(ランダムなデータ)の生成まで自動でやってくれます。
「SHA256でハッシュ化すればいいや」と hash('sha256', ...) を使うのは、もう古いです(計算が速すぎて総当たり攻撃に弱いため)。
必ず password_hash を使いましょう。
【失敗談】私が過去にやらかした暗号化のミス
ここで少し、私が駆け出しの頃にやってしまった失敗談をお話しします。
これから実装する皆さんの反面教師になれば幸いです。
失敗1:秘密鍵をソースコードに直書きしてGitにプッシュ
今回のサンプルコードでは便宜上 $key をクラス内に書いていますが、実務でこれをやると大事故になります。
かつて私は開発中の勢いで秘密鍵をコードに直書きし、そのままGitHubの公開リポジトリにプッシュしてしまったことがあります。
【対策】
秘密鍵は必ず .env ファイルなどの環境変数で管理し、Git管理外に置きましょう。
クラウド(AWSなど)を使うなら、KMS(Key Management Service)などの鍵管理サービスを使うのがベストです。
失敗2:IV(初期化ベクトル)を固定値にしていた
「毎回IVを生成して保存するのが面倒くさいから、全部 0000... でいいか」と、IVを固定して実装したことがありました。
これだと、例えば「田中さん」と「鈴木さん」の住所が同じだった場合、暗号文も全く同じになってしまいます。
「あ、この人たちのデータ同じだな」と推測されるリスクがあり、暗号化の強度がガタ落ちします。
【対策】
面倒でもIVは毎回ランダム生成し、暗号文とセットで保存しましょう。
ファイル自体の暗号化はどうする?
データベースの文字列だけでなく、アップロードされた画像やPDFファイル自体を暗号化したい場合もあるでしょう。
基本的には先ほどの openssl_encrypt と考え方は同じですが、ファイルの中身を読み込んで処理します。
// ファイルの中身を読み込む
$data = file_get_contents('secret.pdf');
// 暗号化(先ほどのクラスを使用)
$encryptedData = $security->encrypt($data);
// 暗号化されたファイルとして保存
file_put_contents('secret.pdf.enc', $encryptedData);
ただし、巨大なファイルを扱う場合はメモリ不足になる可能性があるため、ストリーム処理などを検討する必要があります。
PHPのスキルを活かして年収を上げる方法
以上、PHPでの暗号化と復号化について解説してきました。
なお、PHPのスキルがある場合には、「転職して年収をアップさせる」「副業で稼ぐ」といった方法を検討するのがおすすめです。
PHPエンジニアの需要は非常に高く求人数・案件数も多いため、転職によって数十万円の年収アップはザラで、100万円以上年収が上がることも珍しくありません。
なお、転職によって年収を上げたい場合は、エンジニア専門の転職エージェントサービスを利用するのが最適です。
併せて、副業案件を獲得できるエージェントにも登録しておくと、空いている時間を活かして稼げるようなPHPの案件を探しやすくなります。
転職エージェントも副業エージェントも、登録・利用は完全無料なので、どんな求人や副業案件があるのか気になる方は、気軽に利用してみるとよいでしょう。



