PHPでDKIM署名を作成する

yamadaDKIM, PHP

はじめまして。入社 2 年目クライゼルグループの yamada です。
初投稿となります。

最近、電子メールの認証技術として主流になりつつあるDKIM署名ですが、ネットで調べてもDKIM署名を作成するプログラムについてはこれといった情報がなかったので、今回はライブラリを使って DKIM 署名 (DKIM-Signatureヘッダ) を作成するプログラムを紹介します。

ライブラリのダウンロード

ネットで検索すると PHP の DKIM ライブラリはいくつかヒットしますが、今回は下記URLのライブラリを使います。

zipに含まれる「dkim.class.php」がライブラリの本体です。それ以外はテスト用のサンプルソースなので今回は使いません。

DKIM-Signatureヘッダの仕様決め

次にDKIM-Signatureヘッダの仕様を決めます。今回は下記の通りとします。

  • a タグ (署名作成のアルゴリズム) : rsa-sha1
  • q タグ (公開鍵取得方法) : dns/txt
  • c タグ (メールの正規化方式) : relaxed/simple (ヘッダ/本文)
  • h タグ (署名対象のヘッダ) : From、To、Subject
  • i、l、x、zタグは省略

※c タグのヘッダ正規化方式、a タグ、q タグについては、このライブラリでは固定値となります (変更する場合はライブラリの一部を書き換える必要があります)。

また、以下の値についても事前に決めておく必要があります。ここに設定する値はサンプルですので適宜変更して下さい。

  • d タグ (ドメイン) : example.com
  • s タグ (セレクタ) : dkim.sl.20131025

これらを踏まえて、作成する DKIM-Signature ヘッダは下記となります。t、bh、b タグについてはライブラリによって自動生成されることになります。

DKIM-Signature: v=1;
        a=rsa-sha1;
        q=dns/txt;
        s=dkim.sl.20131025;
        t=<送信日時>;
        c=relaxed/simple;
        h=from:to:subject;
        d=example.com;
        bh=<本文のハッシュ値>;
        b=<電子署名>

鍵の生成と DNS サーバへのレコード登録

DKIM 署名を行う秘密鍵と公開鍵のセットを作成します。CentOS 6 系であれば、opendkim パッケージの opendkim-genkey コマンドで簡単に作成できます。

# yum install opendkim
$ opendkim-genkey -d example.com -s dkim.sl.20131025

-d オプションにドメイン、-s オプションにセレクタを指定しています。上記コマンドを実行すると、以下のファイルが生成されます。

  • dkim.sl.20131025.private : 秘密鍵 (パスフレーズなし)
  • -----BEGIN RSA PRIVATE KEY-----
    MIICXAIBAAKBgQCo58N8KhMa1kblbGlhGINznh7kmQmK85kt2XSiaBmincAPeeLK
                          (省略)
    h0rlopDKO9J91moEQpkCQBeJDjKIzj3N1m2qqs4G6pWbMabHOE4StHJGAuIEFB4X
    ACOnSiiod6TaFl4QE6VI/6xH7s7gc/osRkoaFexIhcc=
    -----END RSA PRIVATE KEY-----
  • dkim.sl.20131025.txt : 公開鍵 (DNS レコード形式)
  • ; ----- DKIM key dkim.sl.20131025 for example.com
    dkim.sl.20131025._domainkey IN TXT "v=DKIM1; k=rsa; p=MIGfM (省略) DAQAB" 

この公開鍵 (DNS レコード形式) をドメインを管理する DNS サーバのレコードに事前に登録しておきます。ただし、未登録でも DKIM 署名のメール自体は送れるので、とりあえずライブラリの使い方を知りたいという方はスキップで OK です (もちろんその場合、署名されたメールは意図したとおりには検証されません)。

プログラム作成と実行

これで準備ができたのでプログラムを作っていきます。

なお、OpenSSL関数とマルチバイト文字列関数を使うため、事前にライブラリのインストールが必要です。CentOS 6 であれば以下で OK です。

# yum install openssl php-mbstring

プログラムは以下の通りです。例として宛先を to@example.com、送信者を from@example.com としていますので、ご利用の際は適宜書き換えて下さい。なお、以下のプログラムは PHP 5.3 で動作確認しています。

[send-dkim-mail.php]

<?php

include_once("dkim.class.php");

$to          = "to@example.com";
$subject     = "DKIM test";
$body        = "This is DKIM test mail.";
$headers     = "From: from@example.com";

$domain      = "example.com";
$selector    = "dkim.sl.20131025";

$private_key = "-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCo58N8KhMa1kblbGlhGINznh7kmQmK85kt2XSiaBmincAPeeLK
                      (省略)
h0rlopDKO9J91moEQpkCQBeJDjKIzj3N1m2qqs4G6pWbMabHOE4StHJGAuIEFB4X
ACOnSiiod6TaFl4QE6VI/6xH7s7gc/osRkoaFexIhcc=
-----END RSA PRIVATE KEY-----";

$pass_phrase = "";      // パスフレーズなし

$options = array(
    "dkim_body_canonicalization" => "simple",   // 本文の正規化方式
    "signature_headers" => array(               // 署名対象のヘッダ
        "From",
        "To",
        "Subject"
    )
);

$signature = new mail_signature(
    $private_key,
    $pass_phrase,
    $domain,
    $selector,
    $options
);

// DKIM-Signature ヘッダを作成する
$signed_headers = $signature->get_signed_headers($to, $subject, $body, $headers);

// 通常のメールヘッダの前に、作成した DKIM-Signature ヘッダを付け加える
$headers = $signed_headers . $headers;

// DKIM 署名 (DKIM-Signatureヘッダ) 付きのメールを送信する
mb_send_mail($to, $subject, $body, $headers);

このプログラムを以下のように実行すれば DKIM 署名付きのメールを送信することができます。

$ php send-dkim-mail.php

署名が正しく作成されたかどうかを確認するには、メールを Gmail などの DKIM に対応した Web メールに送るのが手っ取り早いでしょう。

Gmail 側で受信したメールのソースを開いて、Authentication-Results ヘッダに「dkim=pass」と記録されていれば、署名が正しく作成されたことになります。

今回紹介したライブラリは簡単で使いやすいですが、パラメータが固定されていたりと不便な点もあるので、ぜひその辺を改修したバージョンがリリースされることを期待したいですね。

yamadaDKIM, PHP

Posted by yamada