今日のハマりどころ

まだまだ、SNIに対応してないクライアントは沢山ある

サーバのSSL証明書を更新したらある程度古いAndroid端末からSSL通信できないという事象が発生。
ジオトラストの証明書にしたんで、きっと中間証明書かクロスルート証明書絡みなんだろうな〜と思いながら調査をしていたが、

$ openssl s_client -showcerts -connect www.mydomain.jp:443

の値も更新前の証明書の値が返ってきたりで...

ん?virtual host??
www

対象のAndroid端末はすべてDefaultHttpClientからリクエス
以下の記事にあるように「HttpURLConnectionではSNI接続を試みる」とあるようにDefaultHttpClientではSNIに対応してないように読み取れる
http://android-developers.blogspot.jp/2011/09/androids-http-clients.html

で、対象のサーバの設定を確認してみたところ、が思いっきり、更新前の証明書を参照しているではありませんかwww
SNIに対応してないクライアントへはdefault virtual hostの期限切れ証明書を返していただけというオチ。

で特に複数証明書を運用するサーバでもなかったので、default virtual hostを停止したんだけど...






真剣にSNI運用しているサーバって非対応クライアントからのアクセスどうしるんだろう...

svn resolvオプションメモ

tree衝突した時のオプションをよく忘れるので。

$ svn resolve --accept working filename

base
 作業コピーを更新する前の、BASE リビジョンのファイルを選択します。これは、最後の編集を行う前のチェックアウトしたファイルです。
working
 手動で競合解決を行ったと仮定し、現在作業コピーにあるファイルを、このファイルのバージョンとして選択します。
mine-full
 競合したすべてのファイルを、svn update を実行する直前にあったファイルのコピーで、解決します。
theirs-full
 競合したすべてのファイルを、svn update を実行したときにサーバから取得したファイルのコピーで、解決します。

あとは、ディレクトリ全体のsvn revert
$ svn revert --recursive .

HostヘッダーなしでプライベートIPがLocationヘッダーに出力される件

http://www.intellilink.co.jp/article/column/security-net02.html

通常、下のようなURLにアクセスし、
http://example.com/img
サーバ内のDocumentRootにimgというファイルが存在しない場合、

Location:http://example.com/img/

のヘッダーが吐き出され、http://example.com/img/ にリダイレクトする

ある特定の条件下で、

Location:http://192.168.0.1/img/

のようにプライベートIP漏洩するケースがある

条件は

  • HTTP/1.0
  • クライアントからHostヘッダーの送信なし (HTTP/1/1は必須)
  • apacheの場合、httpd.confのServerNameディレクティブが未定義 vhostsのServerNameは関係しない

理屈としては、LocationヘッダーによるリダイレクトはHostヘッダーを見て定義する、存在しない場合はServerNameディレクティブの値とするということらしい。

解決はhttpd.confのServerNameディレクティブを設定することで対応できる (vhostsは不可)

limit offsetが重い時

なんの変哲もないSQLが重い時

select * from tablename where column1 = condition order by colmun2 limit 100 offset 0;

column1とcolmun2に単独のインデックスを貼っていてもorder byでインデックスは使われない。
ので、複合indexを貼ればよい

CREATE INDEX tablename_idx ON tablename (column1, colmun2);

但し、インデックスの並び順に注意。必ず条件句で索引するカラムを先にもってくること。

plpgsqlでdelete & insert

plpgsql内のBEGIN〜END間で暗黙的トランザクションが張られる。
insertが失敗した場合、deleteの処理がロールバックされるので、
原子性保証はしたいが、書き込みキュー等へ処理を委譲したい場合の解決の1案として。

CREATE OR REPLACE FUNCTION table_delete_insert(
  ids  int[]
) RETURNS BOOL AS
$$
DECLARE
    multi_values text;
    insert_query text;
    vals text[];
    id int;
BEGIN
    delete from tablename;

    IF array_length( ids, 1 ) > 0 THEN
        FOREACH id IN ARRAY ids
        LOOP
           vals := array_append(vals, '(' || id || ')');
       END LOOP;
       multi_values := array_to_string(vals, ',');
       insert_query := 'insert into tablename ( columnname ) values' || multi_values ;
       EXECUTE insert_query;
    END IF;

    RETURN TRUE;

    EXCEPTION WHEN OTHERS THEN
        RETURN FALSE;
END;
$$
LANGUAGE plpgsql;
select table_delete_insert();

レプリケーション時のシーケンス状態に差異がある

マスターとスレーブでシーケンスのlast_valueがずれる場合があるので注意

master

 last_value    | bigint  | 50
 start_value   | bigint  | 1
 increment_by  | bigint  | 1
 max_value     | bigint  | 9223372036854775807
 min_value     | bigint  | 1
 cache_value   | bigint  | 1
 log_cnt       | bigint  | 32
 is_cycled     | boolean | f
 is_called     | boolean | t

slave

 last_value    | bigint  | 82
 start_value   | bigint  | 1
 increment_by  | bigint  | 1
 max_value     | bigint  | 9223372036854775807
 min_value     | bigint  | 1
 cache_value   | bigint  | 1
 log_cnt       | bigint  | 0
 is_cycled     | boolean | f
 is_called     | boolean | t

テーブル自体の値はマスターからのwalログ伝播なので差異はないが、フェイルオーバー時には数値が先に進む可能性があるので注意。

参考
https://devon.so/2015/02/06/as-tale-of-sequences-and-postgresql-replication-9/