Home

技術日記
多重のセキュリティとか出力時のバリデーションとかEdit

なぜPHPアプリにセキュリティホールが多いのか?:第44回 セキュリティ対策が確実に実施されない2つの理由|gihyo.jp … 技術評論社

gihyo.jp セキュリティ対策が確実に実施されない2つの理由

はてなブックマーク - 第44回 セキュリティ対策が確実に実施されない2つの理由|gihyo.jp … 技術評論社

なんではてブでこんなに叩かれているんだ? Rails関連はよう知らんけど、それ以外の内容で特に叩かれるようなことは書いてないと思うんだけど?

「多重のセキュリティ対策」って言葉に引っかかっている人がいるみたいだけど、単に「既にチェック済み,これは数値だからエスケープ処理は不要,などとの誤った判断からエスケープ処理を行っていないコード」みたいな事例に対して、入力値でバリデーションしたから出力値はエスケープしなくていいとか考えるなって言っているだけでしょ。

で、上記みたいな誤った判断をする人がその理由として、「だってDRYって言うし、いったんこの入力値に対してはチェックコードを書いたから、出力時の処理は書かなくていいよね」とか言いかねないから、「セキュリティ対策とコーディングのベストプラクティスは相反する」と言ってるんじゃないの? 結局ここで言うベストプラクティスってのは「重複処理を排除した効率よいコード記述」のことみたいだし。「それを重複と考えるのはおかしい」とか言っても、それを重複と考えるような馬鹿を前提とした文章だって読み取れるじゃん。

あと出力時のバリデーションに関しては、「1と2の対策が不可能な場合は出力時にバリデーション処理を行う」と書いてあるとおり、どうしてもエスケープなどを使った安全な出力ロジックが使えない場合は、しょうがないから出力に関してもバリデーションしようね、という話になっていて、別に推奨しているわけじゃないし、実際特殊な環境向けの出力ではあり得る話だと思うんだけど。

それにしても「セキュリティ対策」って言葉は曖昧で良くないな。

  1. 普通に動作させるために必要な設計と実装(そして、それができなかった際に発生するバグ)。
  2. 情報漏洩や情報破壊を引き起こしうるバグに対する注意。
  3. 積極的なセキュリティアタックに対しての対抗策。
それらが全部なんとなく「セキュリティ対策」でくくられてしまうけど、全部混ぜて議論すると焦点がぼやけてぐだぐだになる。どこまでわかっている(問題にしている)人に対して、何を伝えたいのかがそれぞれ違ってくる。

Published At2011-12-01 13:08Updated At2011-12-01 13:08

ニュース記
Carrier IQ、PS VitaEdit

AndroidとiOS、プライバシーを丸裸にするソフトが仕込まれていたことが発覚 -INTERNET Watch

このCarrier IQってのは何なんだ? OSをまたがって採用されているってことは、モバイル端末でトラブルが起こったときに後から詳しく解析するための情報を記録しておくための、ミドルウェアみたいなものなのかな。

しかも、この記事を読む限りでは、端末内にログを保存するだけでなく、外部にその情報を送信しているのか。送信処理がなくて、故障とかで修理送りになったときに工場とかだけで内容を確認するんだったらセーフだったかな?

【西田宗千佳のRandomTracking】PS Vita発売前の最終情報を開発チームに聞く -AV Watch

DSもVitaもゲーム機がどんどんPDAっぽくなってくるなー。結局PS Vitaはスマートフォンにゲーム優先動作モードをつけて、ゲーム機ならではの囲い込み機能を用意したものだよなー。最初のうちはゲーム機として開発されたVitaが先行するだろうけど、そのうちスマートフォン系機種にもゲーム方面に特化した亜種が増え始めて、あっさりVitaを食ってしまいそうな気がする。

Published At2011-12-02 19:11Updated At2011-12-02 19:11

技術日記ZendFramework
Zend_Frameworkにおけるバリデーションコードの置き場所Edit

Zend_Frameworkにおけるバリデーションコードの置き場所ってどうよ? ってのをいろいろ試行錯誤した結果、今のところこうしてるよ、というのをまとめてみる。

DBアクセスレイヤーは基本的にZendDbTableを使っている。テーブルにマッピングできないものも、データ操作レイヤーに関するものはapplication/models/以下に置いて、ZendDbTableと同じようなインターフェースを持たせて使う。で、共通化できるバリデータはこのモデルクラスにまとめて持たせる。

[sourcecode language="php"]
class ModelBase extends ZendDbTable
{
  protected $validators = array();
  public function getValidators()
  {
    return $this->validators;
  }
  public function getValiator($name)
  {
    if (!isset($this->validators[$name]) {
      $this->validator[$name] = new ZendValidate();
    }
    return $this->validator[$name];
  }
}
[/sourcecode]
みたいなベースクラスを作っておいて、 各実装クラスでは、
[sourcecode language="php"]
class FooTable extends ModelBase
{
  public funciton init()
  {
    $this->getValidtor('foo')
    ->addValidtor(new ZendValidateStringLength(5, 15));
  }
}
[/sourcecode]
みたいな感じでinit()内でバリデータをセットしておく。そうすると、ZendDbTableRowとかでこのバリデータを使いたい場合は、
[sourcecode language="php"]
class FooTableRow extends ZendDbTableRow
{
  public function isValid()
  {
    $result = true;
    foreach ($this->getTable()->getValidators() as $name => $validator) {
      $result = $validator->isValid($this->$name) && $result;
    }
    return $result;
  }
}
[/sourcecode]
なんて感じでバリデーションを書ける(上の例は共通バリデータをぶん回すだけでOKな場合の話ね)。また、このFooTableに対してのCRUDを行うようなZendFormでは、
[sourcecode language="php"]
class FormFoo extends Zend_Form
{
  public function init()
  {
    $fooTable= new FooTable();
    $foo = $this->createElement('input', 'foo');
    $foo
    ->addValidator($fooTable->getValidator('foo'))
    ->addValidator(new CustomValidatorForForm());
    $this->addElement($foo);
  } 
}
[/sourcecode]
なんて感じでFooTableの該当パラメータ用のバリデータを使うことができるし、それにフォーム専用の追加パラメータを追加することもできる。

アクションコントローラのパラメータの場合は、

[sourcecode language="php"]
class FooController extends ZendControllerAction
{
  public function fooAction()
  {
    $foo = $this->_getParam('foo');
    $fooTable = new FooTable();
    $validator = $fooTable->getValidator('foo');
    if (!$validator->isValid($foo)) {
      // IIIINNNNVALIIIIIIIDDDDDDDDDDD!!!!!!!!!!!!!!!!
    }
  }
}
[/sourcecode]
なんて感じで、使いたい要素のバリデータだけ引っ張り出して使える。

ということで、バリデータはモデルクラスにパラメータ名ごとに共通(使い回せる)部分を突っ込んでおいて、シチュエーションごとにそれを取り出しつつ、シチュエーションに特化したバリデータはその場でaddValidator()して使う、いう置き方が一番きれいなんじゃないかと思うのだが、どうだろう。

フィルターに関しては、まとめて同じ処理をしたいという要求がそれほど大きくない、というか同じパラメータでも入力シチュエーションによってどういうフィルターをかけたいかが変わるんで、必要な場所(アクションメソッドとかフォーム要素とか)にそれぞれ書くのが無難な気がする。フィルタークラス自体はアプリケーションに特化したものをapplication/filters以下に用意しておいた方が楽だけど。

と、久しぶりにZendFrameworkで新しいアプリを書こうと思い、どうせならZendFrameworkのコンポーネントを使い倒した書き方にしてみるかといろいろ試行錯誤した結果、こんな感じになったという話でした。

Windows Server 2008でManaged DirectXを使ったASP.NET MVC3が動かないという、ググってもレアケース過ぎて解決策が見つからないシチュエーションからの現実逃避の一環でもある。単にDirect 3Dのベクトル演算関数をサーバーサイドでも使いたいだけなんだけどなー。なんで依存関係が解決できないんだろう。

Published At2011-12-02 20:16Updated At2019-12-30 15:06

技術日記
Eclipse使っている人はSubversion 1.7系へのアップデートはもうちょい待ったほうがいいかもEdit

追記@2012/02/03)解決したよ→今日の検索キーワード:ASP.NET MVC3、Subversion 1.7+Eclipse動いた<!--more-->

WindowsでSubversion関連を扱うためのツール類をいろいろ使っているわけだ。具体的には、TortoiseSVNとか、EclipseのSubversionプラグイン(Subversive、Subclipse)とか、VisualStudioのSubversionプラグイン(AnkhSVN)とか。

で、各開発環境(IDE)を使うときにはそれぞれの開発環境用プラグインを使い、そうじゃない場合はTortoiseSVNを使っているわけなんだけど、TortoiseSVNは結構よくアップデートされていて、アップデートがあると起動時に「アップデートしないかい?」というダイアログが出る。

でまあ、Explorer拡張であるTortoiseSVNのアップデートはたいてい再起動を伴うんで、面倒くさくて「いいや、アップデートしない」としておくんだけど、しばらくアップデートしていなかったんで久しぶりに「いいよ、アップデートしても」と返事をした。まあTortotiseSVNのアップデートは今まで問題が出たことなかったし、特に何も考えずに。

で、アップデートしてから普通に使おうとしたら、「Working Copyの形式がSubversionの1.7形式になっていないから、1.7形式にアップグレードするかい?」と聞かれた。へー、今回のアップデートはその辺も変わったのかと「いいよ、やっちゃってよ」と返事をしたら、いろいろ問題が出た。

このフォーマット変更は、結構互換性がない変更だったのね。っつーか、.svnフォルダをルートのみに置くようになったのか。それはすげー便利。けど、Subversion 1.7形式に対応していない古いプラグイン達からこのWorking Copyを扱えなくなってしまった。くそー、Subversion関連のアップデートで今更こんな互換性がない代物が発生するとは。油断していた。

それでもまあ、VisualStudioプラグインであるAnkhSVNに関しては、ちゃんとSubversion 1.7以降に対応したバージョンがすでにリリースされていたんで、それにアップデートしたらちゃんと扱えるようになった。ありがとう。

しかし、Eclipseプラグインの方は、今までSubversiveを使っていたんだけど、こちらはまだSubversion 1.7形式に対応していない。試しにSVNKitの1.7対応アルファ版をインストールしてみたりしたんだけど、だめだった。

Subclipseは1.7対応版が出ているんだけど、今までSubclipseがちゃんと動いたことないんだよなー。インストールして動かそうとしても、JavaHL関連の依存関係エラーが出る。32ビットJava環境で動かしているはずだけど、OSはWindows 7 64ビットなんで試しにSilk SVNの64ビット版を入れてみたりもしたけど、状況は変わらず。

というわけで、結局現時点でEclipseのSubversion関連プラグインをSubversion 1.7形式に対応させるのは挫折。

まあそのうち標準的なアップデートインターフェースからアップデートされてくるだろうし、TortoiseSVNが使えるんでEclipseプラグインが使えなくても使い勝手が大幅に悪くなるわけじゃないんだけど、まだ1.7系にアップデートしていない人でEclipseも使っている人は、1.7系にアップデートするのはしばらくやめておいた方がいいと思う。

まあ、Working Copyを1.7形式にアップグレードせずに使い続ければいいんだろうけど、TortoiseSVNで新規にcheckoutしたWorking Copyを後からEclipseでマウントしようとしたら、SVNアクセスがうまくいかない、とかの罠にはまるのも面倒だし。

Published At2011-12-07 16:17Updated At2011-12-07 16:17

ニュース記
connectFree、アプリの翻訳、Andoroidセキュリティ?Edit

connectFreeについて高木浩光さんのツイートまとめ(12/05 06:00まで) - Togetter

平成23年12月5日 コネクトフリー株式会社 お客様情報の取得に関するお詫びとご説明

Twitter / @craftgear: ほんとだ、コネクトフリーの会社概要から人名がごっそり ...

フリーのWebスペースで、メニューのオーバーレイとかやるのは見たことあるけど、あれはどうせWebサーバー握ってるところがやってるからなー。フリープロバイダー(WiFi)がHTTP通信中のHTMLをがんがん書き換えちゃいつつ、必要以外の個人情報も収集しちゃったのか。いまどき個人でやっている人たちだって、ここまでやったらやばいかなーくらいは考えそうなことを、あっさりと突き抜けて好き放題やっちゃってるなー。そして指摘されたら即時やめましたって、何も考えなさそうすぎて怖すぎる。

fladdict » アプリの翻訳を依頼するコツ

参考情報をあらかじめ相手に予備知識として提示しておく+事後に起こりうる具体的なトラブル対策を考慮した出力形式を指定する、って感じかな。まさしくノウハウ。

一部の Android 端末でアプリ権限を迂回できる問題、端末データの削除など -- Engadget Japanese

別アプリのクリティカルな機能をインテントを使って呼ぶことができた、とかかなー。

カラム名/メソッド名の命名のための英語辞書 - CODIC

iPhoneの辞書アプリ(英辞郎)はほぼそのために買ったんだけど、これで代替できるかな。

Published At2011-12-09 14:52Updated At2011-12-09 14:52

技術日記
SilverlightでのWeb APIアクセス処理(無駄な試行錯誤の過程)Edit

なんかもう、Silverlightの普通の.NET Frameworkとの互換性のなさにはうんざりしているんだけど、その中でも特にうんざりしたWebRequest周りについて。

普通に.NET FrameworkでWeb APIとかにアクセスしたい場合、System.Net.WebClientとかを使うと簡単にできる。

[sourcecode language="c#"]
var client = new System.Net.WebClient();
var url = "http://example.com/path/to/api";
var values = new NameValueCollection(){{"key", "value"}};
var byteResult = client.UploadValues(url, values);
var stringResult = Encoding.UTF8.GetString(byteString);
[/sourcecode]
受け取った文字列がJSONだった場合は、
[sourcecode language="c#"]
var serializer = new JavaScriptSerializer();
var result = serializer.Deserialize(stringResult, typeof(ObjectForMapping);
[/sourcecode]
みたいな感じで受け取り用のクラス(ObjectForMapping)を用意しておいて、それにデシリアライズしたりとか。 あと、これだけだとCookieベースの認証とかが維持できないんで、webclient 継承 cookiecontainerでググると出てくるような感じで、
[sourcecode language="c#"]
class MyClient: WebClient
{
  protected CookieContainer _cookie = new CookieContainer();
  protected override GetWebRequest(Uri address)
  {
    var request = base.GetWebRequest(address);
    if (request is HttpWebRequest) {
      (request as HttpWebRequest).CookieContainer = _cookieContainer;
    }
    return request;
  }
} 
[/sourcecode]
みたいな感じでCookieを扱えるクラスを作っておくと、自動的にCookieを維持してくれるようになる。 でまあ、Silverlightでも同じようなことができるよね、と思って、クラスライブラリの名前空間とかファイルとかの構成がいろいろ変わっているのを乗り越えて、
[sourcecode language="c#"] 
using System.Windows.Browser; 
using System.Net.Browser; 
class MyClient: WebClient  
{
} 
[/sourcecode]
とやったところ、これはコンパイル自体は通るくせに、new MyClient()するコードブロックを通ったとたんに、何のエラーメッセージも出さずにそっと落ちる。 どうやらWebClientを継承したらだめなようだ。

けど、そんなドキュメント、どこにも見つからないし、だいたいコンパイルは通ってるんだけどなー。っつーか、結局WebClientを継承するだけでもだめだ、と気づくまでどれだけ時間がかかったことか。 しょうがないんで、自前でWebRequestを使って処理を行うような構成に変更することにする。必要に応じて、

[sourcecode language="c#"]
var request = WebRequest.Create(new Uri(url));
(request as HttpWebRequest).CookieContainer = _cookie; // 使い回すCookieContainer
request.BegubGetResponse(callback, request);
[/sourcecode]
みたいな感じね。でも、これが通らない。なぜかというと、
[sourcecode language="c#"]
var request = WebRequest.Create(new Uri(url));
[/sourcecode]
で返されるWebRequestがHttpWebRequestではなくBrowserHttpWebRequestってやつになっている。なんじゃそりゃ。それはどの辺のドキュメントに書いてあるんだよ。MSDN内で検索してもそのドキュメントが見つからないぞ。

いろいろ探し回った結果、方法: Cookie の取得と設定を行うというドキュメントを見つけた。解説自体は今までやっていたことを説明しているだけで、特に新しい情報はない。しかし、サンプルコードに見慣れない処理が入っている具体的には、

[sourcecode language="c#"]
IWebRequestCreate creator = WebRequestCreator.ClientHttp;
WebRequest.RegisterPrefix("http://", creator);
WebRequest.RegisterPrefix("https://", creator);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://api.search.live.net/clientaccesspolicy.xml")
[/sourcecode]
なんじゃこりゃ。WebRequestCreatorクラスのドキュメントを見てみると、
Silverlight では、ブラウザーとクライアントのどちらで Silverlight ベース アプリケーションの HTTP 処理を行うかを指定できます。既定では HTTP 処理はブラウザーによって行われるため、クライアントで HTTP 処理を行う場合は選択の必要があります。通常、HTTP の要求と応答の処理方法を指定するには、このクラスのプロパティを WebRequest の RegisterPrefix メソッドSilverlight では、ブラウザーとクライアントのどちらで Silverlight ベース アプリケーションの HTTP 処理を行うかを指定できます。既定では HTTP 処理はブラウザーによって行われるため、クライアントで HTTP 処理を行う場合は選択の必要があります。通常、HTTP の要求と応答の処理方法を指定するには、このクラスのプロパティを WebRequest の RegisterPrefix メソッドに渡します。に渡します。
なるほど、Silverlightってそこまでブラウザと密結合していたのね。 標準ではBrowserHttpWebRequestってのが使われるから、非Silverlight環境と互換性のあるHttpWebRequestを使いたい場合は、サンプル通りにSilverlight側でhttpスキームを処理するように指定してからWebRequest.Createしなければならないのか。そうやったらちゃんとHttpWebRequestが生成されるようになった。CookieContainerも使えている。

で、一通りコンパイルは通るようになったし、実行もできるようになったんだけど、なぜかCookieによる認証が維持されない。認証CookieがHttpOnlyなんで、中身をのぞけないからよくわからないが、少なくとも同じようなコードで通常の.NET Frameworkでは動作するものが、Silverlight環境ではうまくいかない。

うがー、どないなっとんねん。と、SilverlightのHTTP通信周りのドキュメントをもう一度良い返してみる。そうしたら、Silverlightの標準の方のBrowserHttpWebRequestでは、ブラウザの機能を使ってHTTPリクエストを処理するんで、ブラウザ側のCookieがそのまま使えるっぽい? なんか非Silverlight用に作ったコードを移植しようとしていたのは無駄な努力だった?

というわけで、単純に認証Cookieを保持したいだけだったら、わざわざHttpWebRequestを生成して自前でCookieContainerを処理したりする必要はなく、何も考えずにSilverlight標準のWebアクセスクラスを使ってしまえば、ブラウザ相当のCookie処理が使われてくれる。

先に非Silverlight用のWeb APIクライアントコードを書いて、それをSilverlightでも動くように移植しようとしたせいで、無駄にはまったんだね。はじめからSilverlight用に書いていれば何も考えなくても動くものが作れた気がする。ただし、ブラウザ互換のWebアクセスクラスにも制約があるんで、それで全部いけるわけではないけど。

書き忘れていたけど、クロスドメインアクセス用のcrossdomain.xmlとかは、Flashとかと同様、サーバーサイドにあらかじめ用意しておく必要がある。

で、APIアクセスライブラリとしては一通り動くようになったから、SilverlightアプリケーションからWeb APIをコールして、その結果をTextBoxに表示するというテストアプリを作ってみた。が、「System.UnauthorizedAccessException: 無効なスレッド間アクセスです。」というエラーが出て表示できない。

どうやらAsyncCallbackから呼び出されるスレッドと、UI部品などを管理するメインスレッドとは別スレッドだから、直接は呼び出せないと言うことらしい。

いろいろググったところ、Silverlight 奮戦記 ファイルを読む β2 対応版という情報を見つけた。AsyncCallbackから呼び出されたメソッドから、さらにSyncronizationContect.Current.Post()を使ってメインスレッドとの同期を取ってから、メインスレッド側のパーツに対する処理を行えば回避できるみたいだ。でも、この辺の情報は公式ドキュメントではどの辺に書いてあるのかなー。

といった感じで、.NET Frameworkがらみのドキュメントは非常にわかりにくいし、同じ名前のクラスが多いくせに制限事項が違うSilverlight環境の場合は、それがさらにひどくなっているんで、あまり深入りしたくない気持ち満点になった。デバッグ環境としてできがいいVisualStudioなのに、Silverlightのデバッグだとうまく動かないことがあまりにも多いし。

Published At2011-12-09 21:43Updated At2011-12-09 21:43

ニュース記
PHP VM、Chrome Native Client、Silverlight5、UPS拡張パック、Q4MEdit

PHPのJITコンパイラ「HipHop Virtual Machine」、Facebookがオープンソースで公開 - Publickey

HipHopの段階から試していないんだけど、これっていろいろ制限が大きそうな気がするんだけど、その辺の情報が見当たらなくて試してみるのも躊躇している。実際どの程度のPHPのコードにまで適用できるんだ? 大規模なフレームワークとかを使ったコードでも使えるの? まあそんなの自分で試せって話なんだけど。

Tonny Xu: SQLiteを用いて、iOSで高速全文検索をしよう

SQLiteの全文検索って日本語でも使い物になるの?と思っていたけど、このベンチマークを見る限りはそれなりに使えるっぽいな。ただ、単語辞書だとこんな感じでいけるけど、実際に日本語文章を扱おうと思ったら、実データを使っていろいろ試してみてからの方が良さそうだ。

米Google、「Chrome上でスクエニなどのゲームがプレイ可能に」 -INTERNET Watch

あれ、C#にも対応しているの? 俄然興味が出てきた。と思ってSDKインストールしたりドキュメント読んだりしてみたけど、まだC#に対応してなくね? 将来はC#とかの他言語にも対応するつもりだよ、と書いているのしか見つけられないんだけど。

Microsoft、「Silverlight 5」正式版を公開 -INTERNET Watch

Windows 8のタッチUI用IE10はプラグインに非対応。FlashもSilverlightも使えず - Publickey

Microsoftでは、次期OSの「Windows 8(開発コード名)」に搭載されるInternet Explorer 10(IE10)について、Metroスタイル向けのIE10ではFlashやSilverlightなどのプラグインをサポートしないことを表明してい る。また、Silverlight 5のサポートライフサイクルが2021年10月12日までと長期に設定されていることから、海外のメディアなどではSilverlight 5が最後のメジャーバージョンになるのではないかと報じている。
マイクロソフトの迷走なのか、明確な戦略があってのそれぞれの技術開発なのか、現状だと前者にしか見えないのがいやだよなー。インターネット関連技術の発展にスタートからついていけなかったマイクロソフトが、圧倒的なシェアと資金力を背景にごまかしごまかし今までやってきたけど、いまだにインターネット関連技術には弱いまんまって感じだ。人材がいないわけはないから、会社がでかすぎてインターネット的な技術文化を会社に浸透させることができないって感じなのかなー。

【清水理史の「イニシャルB」】 第469回:拡張パック利用で3時間超の給電も可能! UPS「APC RS XL500」 -INTERNET Watch

小型家電・PC周辺機器向けバッテリーパック規格で書いたネタに近い感じのイメージだな。この拡張バッテリーポートと接続ケーブルを規格化して一般家電でもそのまま使えるようにならないだろうか。特にハードディスクレコーダーとか録画機では標準採用して欲しい。東芝とかAPCと提携してやってくれないかなー。

Javascript (ECMAScript) の変なところ - fujlog

なんか知らないことが多い。というかJavaScriptの言語仕様はちゃんと知らない。JavaScript 第5版もGood Partsも買っただけでちゃんと読んでないし。早めにちゃんと読んでおいた方がいいんだろうなー。

Q4Mを簡単に導入する方法 - MySQL Casual Advent Calendar 2011 - blog.nomadscafe.jp

Q4M専用のMySQLを、データストレージ用MySQLとは別ディレクトリにインストールして、それぞれ別に手軽に利用できる環境を作るインストールスクリプト。Q4Mは環境条件が厳しくてインストールが面倒くさいから、これはとても便利そう。

Published At2011-12-13 18:49Updated At2011-12-13 18:49

技術日記
さくらVPS+CentOS+PHPでCatchAllなメール受信Edit

試しにやってみたらやたらとはまったのでメモ。

さくらのVPSに適当なバーチャルホスト(foo.example.com)を割り振り、そのバーチャルホスト宛に届いたすべてのメール(*@foo.example.com)をPHPスクリプトで受信したい。

CatchAllじゃないんだったら、受信したいアカウントの.forwardとかからスクリプトを呼び出せばいいんだけど、CatchAllとなるとまず受信したいアカウントというものが存在しないわけで、その辺から設定する必要がある。

具体的には、まず適当な受信用のアカウント(mailreciever)を用意する。

[sourcecode language="plain"] useradd -s /sbin/nologin mailreciever [/sourcecode]

で、そのアカウントとバーチャルホストのCatchAll転送先を結びつける。まずはバーチャルホストをsendmailが受信するドメインとして追加するために、/etc/mail/local-host-namesに以下を追加。

[sourcecode language="plain"] foo.example.com [/sourcecode]

そして、そのドメインのCatchAll転送先としてmailrecieverアカウントを登録するために、/etc/mail/virtualusertableに以下を追加。

[sourcecode language="plain"] @foo.example.com mailreciever [/sourcecode]

virtualusertableはコンパイルが必要なので、

[sourcecode language="plain"] yum install sendmail-cf # 必要ならば makemap hash /etc/mail/virtualusertable.db < /etc/mail/virtualusertable [/sourcecode]

mailrecieverアカウントに受信したときにPHPスクリプト(/path/to/script.php)を実行するように/etc/aliasesに以下を追加。

[sourcecode language="plain"] mailreciever: "|/usr/bin/php /path/to/script.php" [/sourcecode]

というのは実はうまく動かなかった。smrsh環境の制約に引っかかるらしい。そこで、

[sourcecode language="plain"] ln -s /usr/bin/php /etc/smrsh/php [/sourcecode]

のように/etc/smrshディレクトリ内にPHPのCLIバイナリのシンボリックリンクを作っておいて、先ほど書いた/etc/aliasesの内容を、

[sourcecode language="plain"] mailreciever: "|/etc/smrsh/php /path/to/script.php" [/sourcecode]

と変更するとsmrsh環境が原因のエラーを回避できる。

ちなみに/etc/aliasesもコンパイルが必要なので、

[sourcecode language="plain"] newaliases [/sourcecode]

を実行してコンパイルしておく。

これでlocalhost上で*@foo.example.com宛てのメールを送ると、ちゃんと/path/to/script.phpが起動できるようになったのだが、外部からメールを送ってもちゃんと着信していない。

ああ、もちろんそれ以前に、foo.example.comのドメインを該当サーバーのIPアドレスでDNS登録しておく必要があるけど、そういう問題ではない。

あと、自分でセットしたソフトウェアファイアウォールで25ポートINがふさがっているのかと思ったりもしたが、それもない。さくらインターネットが25ポートINを外側でふさいでいるのかと思ったのだが、それでもない。

正解は、さくらVPS+CentOSでインストールされるsendmailのデフォルト設定は、localhostからのSMTPしか受信しないようになっている、だった。

sendmail.cfには触らないと心に誓っているんで、あきらめてpostfixにでも入れ直そうかと思ったんだけど、ググってみたらそれほど設定変更は大変そうじゃなかったんで、sendmailのまま設定を変えて対応した。

/etc/mail/sendmail.mcの

[sourcecode language="plain"] DAEMON_OPTIONS('Port=smtp,Addr=127.0.0.1, Name=MTA')dnl [/sourcecode]

という行をコメントアウトして、

[sourcecode language="plain"] dnl # DAEMON_OPTIONS('Port=smtp,Addr=127.0.0.1, Name=MTA')dnl [/sourcecode]

に変更し、

[sourcecode language="plain"] m4 /etc/mail/sendmail.mc /etc/mail/sendmail.cf [/sourcecode]

でコンパイルしてからsendmailを再起動したら、無事外部からのSMTP接続も受信してくれるようになり、foo.example.com宛てのすべてのエールを/path/to/script.phpで処理できるようになった。

なんかものすごくはまりどころが多かった。

Published At2011-12-19 23:22Updated At2011-12-19 23:22