PHP:有効期限付きのURLを作る

【注意】 おそらく、こちらの実装のほうがセキュアです:

blog.ohgaki.net


とあるプロジェクトで、有効期限付きのURLを作る必要がでてきました。

これまではURLにパラメータを入れて、 そのパラメータと有効期限をデータベースに保存する方法を取っていました:

http://hoge.foo.bar/?expiry=0ddxg9des23A
expiry_string expires
0ddxg9des23A 2018/01/01 23:59:59

さて、データベースを使うのが面倒なのでURLに有効期限を入れてしまうことにしました。 しかしそのままでは有効期限を改ざんされてしまうので、有効期限を暗号化することにしました:

<?php

$now = time();
$expiry_string = $now + (5 * 60);
$password = '適当なパスワード';
$cipher = 'AES-256-ECB';

$encrypted_expiry_string = rawurlencode(openssl_encrypt($expiry_string, $cipher, $password));
?>

あとはこの$encrypted_expiry_stringをURLにつけます。 リクエストを受けたプログラムはそれを復号化します:

<?php

$now = time();

$encrypted_expiry_string = rawurldecode($_GET['encrypted_expiry_string']); // 等々
$expiry = openssl_decrypt($encrypted_expiry_string, $cipher, $password);

if( intval($expiry) < $now ) {
  echo "有効期限が切れています";
}

さて、上記の方式ですが、cipherAES-256-ECBを使っています。メリットとしてIVが必要ない、という点があります。 IVを使った場合、IVをデータベースに保存する必要があり今回の「DBを使わない」という目的から外れてしまいます。

デメリットは有効期限が同じであれば暗号化された有効期限も同一であることです。 このデメリットが許容される用途であるかどうかが重要ですね。