PHP 7.1.xからMcryptはdeprecated(非推奨)になり、PHP 7.2以降ではコアから削除されました。

PHP 7.2にバージョンアップするにはMcryptへの対処が必須です。

本記事ではMcryptが削除された経緯・避けるべき理由を解説した上で、2つの対処方法について説明します。

1つはMcryptを使い続ける方法、もう1つはOpenSSLへ移行する方法です。

Mcryptとは



バージョンアップに際して非推奨な機能を調べていたら出てきたMcryptという名前。


Mcryptを詳しく知らないという方向けに、Mcryptとは何かを簡単に説明します。


暗号・復号関数

元々McryptはUnix cryptの代替コマンドで、エニグマ暗号に近いアルゴリズムを使用した暗号化ツールでした。


MCryptは各種PHPフレームワーク・ECサイト(Electronic Commerce Site)・CMS(Contents Management System)などに利用されました。


主な目的はパスワード・個人情報・顧客情報などの暗号化・復号化です。


Mcrypt関数



PHP Manual > Mcrypt


PHPのMcryptはデータやテキストの暗号化・復号化をするのに利用される関数です。


直接暗号化・復号化を行う関数の他、指定した暗号の名前やブロックサイズを得るための関数などが用意されています。


Mcryptが削除された経緯



ext/mcryptはPHPの拡張モジュールです。


ext/mcryptは10年近く放置されていたため、公式にdeprecated(非推奨)に設定されました。


古い拡張モジュールはコア機能から削除されます。


削除された拡張モジュールのうち、使用可能かつメンテナンスが継続されているもののみPECLリポジトリから取得できます。


ext/mcryptもPECL(PHP Extension Community Library)に移動されました。


Mcryptを避けるべき理由



使用し続けるべきでない理由を明示しておきます。


  • 放置されたソフトウェア
  • 記述方法が直感的でない


放置されたソフトウェア

LibmcryptはMCryptが使用する暗号化ライブラリで、暗号化関数自体とこれらへのアクセス機構を提供するものです。


しかしこれらは数多くのバグを含んでおり、安全でないコードを書ける構造上の欠陥があります。


Libmcryptの最終更新は2007年で、セキュリティ専門家によりAbandonware(放棄ウェア)の宣言が成されました。


またPECLリポジトリの拡張モジュールのうち、更にメンテナンスが停滞したものはSVN経由の取得に変わります。


例えばPECLパッケージとしてリリースされていないものや、知らないうちにサポートされなくなったものなどです。


SVNの拡張モジュールを利用するのは大変なので、少なくともPECLで取得できるうちには移行しなければなりません。


記述方法が直感的でない



例えばmcrypt_encryptはプレーンテキストを暗号化する関数です。


  • mcrypt_encrypt(string MCRYPT_暗号名, string 暗号化キー, string 暗号化するデータ, string MCRYPT_MODE_モード名[, string IVサイズ] ) : string

MCRYPT_暗号名で指定するMCRYPT_RIJNDAEL_256はAES-256ではありません。Rijndaelというブロック暗号の別種です。


AES-256を使用する際のMCRYPT_暗号名はMCRYPT_RIJNDAEL_128です。


OpenSSLでこれらの暗号アルゴリズムを指定するときは、AES-128-CBC・AES-256-CTRなどの素直な名前を使用します。


Mcryptの対処法



PHP 7.2でコアから削除されるMcryptへの対処方法は大きく分けて2つあります。


  • 対処法1:Mcryptを使い続ける
  • 対処法2:OpenSSLに移行する

対処法1はPECLリポジトリからインストールして、既存のアプリケーションがそのまま動くようにする方法です。


「Mcryptを避けるべき理由」で説明した通り、あまり推奨された方法ではありません。


仕様やアプリケーションの稼働期間、コストなどを考えてどうしてもMcryptでなければならない場合に限るでしょう。


対処法2はOpenSSLをインストールして、既存のアプリケーションの改修を行う方法です。


息の長いシステムであれば移行してしまった方が良いでしょう。こちらがいわば正攻法です。

対処法1:Mcryptを使い続ける



どうしてもMcryptを動かす必要がある方向けの項になります。


不要な方は次の「対処法2:OpenSSLに移行する」に進んで下さい。


前提となるPHP動作環境

PHPのインストール方法は色々あります。ここでは以下の方法でインストールをした前提で解説を進めていきますのでご了承下さい。


もし別のバージョンのPHPがインストールされている場合は削除作業が必要です。


PHPのバージョンによってはエラーや警告が発生するので、事前に適用対象と同じ環境を作成して確認することをおすすめします。



  1. $ apt install software-properties-common
  2. $ apt-add-repository ppa:ondrej/php
  3. $ apt update
  4. $ apt install -y php7.2
  5. $ php –version
  6. PHP 7.2.30-1+ubuntu18.04.1+deb.sury.org+1 (cli) (built: Apr 19 2020 07:50:50) ( NTS )
  7. Copyright (c) 1997-2018 The PHP Group
  8. Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
  9. with Zend OPcache v7.2.30-1+ubuntu18.04.1+deb.sury.org+1, Copyright (c) 1999-2018, by Zend Technologies


必要な依存関係をインストールする

以下のコマンドを実行して必要な依存関係のインストールを行いましょう。

  1. $ apt install -y gcc make autoconf libc-dev pkg-config
  2. $ apt install -y libmcrypt-dev
  3. $ apt install -y php7.2-dev php-pear php-xml php7.2-xml

ここで異なるバージョンのPHP拡張モジュールをインストールしてしまうと、エラーが発生したりパスが異常になるので注意が必要です。


mcryptをインストールする



mcryptをインストールしましょう。

  1. $ pecl install mcrypt-1.0.1
  2. (中略)
  3. libmcrypt prefix? [autodetect] :
  4. (中略)
  5. Build process completed successfully
  6. Installing ‘/usr/local/lib/php/extensions/no-debug-non-zts-20170718/mcrypt.so’
  7. install ok: channel://pecl.php.net/mcrypt-1.0.1
  8. configuration option “php_ini” is not set to php.ini location
  9. You should add “extension=mcrypt.so” to php.ini

途中でlibmcryptプレフィックスについて聞かれるので、通常はデフォルトのままEnterキーを押します。


ちなみにphp7.4ではこの方法でmcrypt-1.0.1をインストールすることができなくなっているので注意して下さい。


OpenSSLとは



OpenSSLへの移行方法について説明する前に、OpenSSLとは何かについて説明しましょう。


暗号化通信プロトコル

インターネット経由で通信を行う際、暗号化によって情報漏えいやデータの改竄を防ぎます。


SSL/TLS」という文字をメール設定画面などで見たことがないでしょうか。これもSSLプロトコル・TLSプロトコルという規約です。


OpenSSL関数

PHP Manual > OpenSSL 関数


OpenSSL関数にもデータの暗号化・復号化を行う関数が用意されています。


またOpenSSL関数では秘密鍵・公開鍵によるデータの暗号化・復号化をより手軽に扱うことができます。


McryptとOpenSSLの違い



基本的にMcryptはdeprecated(非推奨)なので、OpenSSLを使うに越したことはありません。


ここでは技術選定上の違いというよりは、移行先のOpenSSLでは何が異なるかという観点から解説を行います。


OpenSSLはMcryptに比べて高速

OpenSSLの暗号化・復号化処理は、Mcryptのそれと比べて高速です。


DES・AESなどの代表的な暗号アルゴリズムで速度比較を行った場合、100倍以上の差が出るという結果も出ています。


性能的にもOpenSSLが上

PHP ManualのMcryptとOpenSSL関数のページを見比べると、メソッド数・対応している暗号の種類はOpenSSL関数の方が多いです。


またMcryptの仕様としてNULLパッディングがありました。


これは暗号化時に固定長文字列に分割したデータに対し、不足する部分をNULL埋めするという仕様です。


この仕様によりPHP以外の言語で暗号化・復号化を行う場合に注意が必要でした。


しかしOpenSSLにすればこの問題は解決します。


対処法2:OpenSSLに移行する



OpenSSLへの移行手順を説明しましょう。


OpenSSLの状態確認

通常OpenSSLはLinux系ディストリビューションにデフォルトでインストールされています。

  1. $ openssl version
  2. OpenSSL 1.1.1 11 Sep 2018 (Library: OpenSSL 1.1.1g 21 Apr 2020)

また上記の前提環境であれば、OpenSSL拡張モジュールは既に使用できる状態の筈です。

  1. $ php -m | grep openssl
  2. openssl

違うバージョンのOpenSSLを使いたい場合、またはPHPの拡張モジュールが有効になっていない場合は別途対応が必要です。


対応するメソッドに置き換える

例えば今までmcrypt_encryptメソッドで暗号化していた箇所は、openssl_encryptメソッドに置き換える必要があります。


以下はAES-128-CBCの場合の例です。

  • mcrypt_encrypt(MCRYPT_RIJNDAEL_128, 暗号化キー, 暗号化するデータ, MCRYPT_MODE_CBC, IVサイズ): string
  • openssl_encrypt(暗号化するデータ, ‘AES-128-CBC’, 暗号化キー, OPENSSL_RAW_DATA, IVサイズ): string

引数の順番や指定する名称が若干異なっています。mcrypt_*を使用している全ての箇所に対して、これらの対応が必要です。


移行方法の詳細は「PHP Manual > OpenSSL 関数」ページにて「mcrypt」でページ内検索をかけて下さい。


「mcryptからopensslに移行する方法」をサンプルコードと共に見つけることができるでしょう。


Mcrypt・OpenSSL対応状況



多くのCMSやWebアプリケーションフレームワークは両方使える状態か、Mcryptを削除する方向で動いている傾向が見られます。


セキュリティ上の問題が大きいことから、近々メジャーバージョンアップで非推奨もしくは削除される可能性が高いです。


また新しい環境でMcryptを動かすのにも骨が折れるものです。


Mcryptのインストールを解説しましたが、載せたソースコードはほんの一部でしかありません。


PHPのバージョン違いでエラーが発生したり、必要な拡張モジュールが不足していたり、PECLのバグを踏んだりなど壁にぶつかることも多いでしょう。


古い拡張モジュールのインストールは予想以上に罠が多いです。


おわりに



アプリケーションの仕様によっては困難かもしれませんが、可能であればOpenSSLへの移行をしてしまうことをおすすめします。


なるべくdeprecated(非推奨)になった時に対応し、できるだけ新しい技術を利用するようにしましょう。


SHIFTフリーランスは、SHIFTグループがプライムとして参画している独自案件をフリーランスエンジニア向けに紹介する唯一のプラットフォームサービスです。

エージェントによるサポートもありますので、ご利用を検討してみてはいかがでしょうか。