記事内にはプロモーションが含まれています

【PHP】暗号化と復号化の実装マニュアル!OpenSSLの使い方など

【PHP】暗号化と復号化の実装マニュアル!OpenSSLの使い方など PHP

Webアプリケーションを作っていると、必ずと言っていいほど直面するのが「セキュリティ」の問題です。

「データベースに保存する顧客の住所、そのまま保存して大丈夫かな?」
「パスワードってどうやって管理するのが正解?」

このように不安になったことはありませんか?

PHPにはデータを守るための強力な機能が備わっていますが、用途によって「暗号化」と「ハッシュ化」を使い分ける必要があります。
ここを間違えると、せっかく暗号化したのに情報漏洩……なんてことにもなりかねません。

この記事では、PHPの標準ライブラリであるOpenSSLを使った「元に戻せる暗号化(復号化)」の実装方法を中心に、パスワード管理の正解、そして私が過去にやらかした失敗談まで、最新情報を交えて解説します。

【本記事の信頼性】
プロフィール
執筆者:マヒロ
  • 執筆者は元エンジニア
  • SES⇒大手の社内SE⇒独立
  • 現在はこじんまりとしたプログラミングスクールを運営
  • モットーは「利他の精神」

「暗号化」と「ハッシュ化」の決定的な違い

コードを書く前に、これだけは絶対に押さえておきたいポイントがあります。

それは「暗号化(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の案件を探しやすくなります。

転職エージェントも副業エージェントも、登録・利用は完全無料なので、どんな求人や副業案件があるのか気になる方は、気軽に利用してみるとよいでしょう。