Tips


ログ振り分け

ローカルアクセスやロボットのログを分けてみる。

#ローカルIPアドレス
SetEnvIf Remote_Addr 127.0.0.1 local nolog
SetEnvIf Remote_Addr 192.168.x.x local nolog

#クローラ
SetEnvIf Remote_Host msnbot search nolog
SetEnvIf User-Agent googlebot search nolog

#ログ振り分け
CustomLog logs/access_log combined env=!nolog
CustomLog logs/search_log combined env=search
CustomLog logs/local_log combined env=local

Ciphersの指定

SSLCipherSuiteで弱い奴を弾いてみる。
openssl ciphersコマンドで確認し、指定したパラメータをApache側へ反映する。
Apacheに限らず、同様の指定が可能なものであれば利用できる。
主に2008年以前のガラケーやandroid2.xなど、古い端末はもはや切り捨てる。

/usr/local/ssl/bin/openssl ciphers -v 'TLSv1.2:!aNULL:!eNULL:!RC2:!MD5:!DES:!IDEA:!EXP:!SEED:!MD5:!RC4@STRENGTH'

ALLを指定、認証なし(eNULL)またはanonymous認証(aNULL)は除外、
輸出用暗号(EXP)、RC2、DES、IDEA、SEEDは弱い、不要などの理由で除外、
MacでMD5は除外。RC4もRFC7465で禁止された。
この設定では以下のスイートが利用可能。 

スイート名                      プロトコル  鍵交換方式      認証/署名方式   暗号方式        メッセージダイジェスト
ECDHE-RSA-AES256-GCM-SHA384     TLSv1.2     Kx=ECDH         Au=RSA          Enc=AESGCM(256) Mac=AEAD
ECDHE-ECDSA-AES256-GCM-SHA384   TLSv1.2     Kx=ECDH         Au=ECDSA        Enc=AESGCM(256) Mac=AEAD
ECDHE-RSA-AES256-SHA384         TLSv1.2     Kx=ECDH         Au=RSA          Enc=AES(256)    Mac=SHA384
ECDHE-ECDSA-AES256-SHA384       TLSv1.2     Kx=ECDH         Au=ECDSA        Enc=AES(256)    Mac=SHA384
DH-DSS-AES256-GCM-SHA384        TLSv1.2     Kx=DH/DSS       Au=DH           Enc=AESGCM(256) Mac=AEAD
DHE-DSS-AES256-GCM-SHA384       TLSv1.2     Kx=DH           Au=DSS          Enc=AESGCM(256) Mac=AEAD
DH-RSA-AES256-GCM-SHA384        TLSv1.2     Kx=DH/RSA       Au=DH           Enc=AESGCM(256) Mac=AEAD
DHE-RSA-AES256-GCM-SHA384       TLSv1.2     Kx=DH           Au=RSA          Enc=AESGCM(256) Mac=AEAD
DHE-RSA-AES256-SHA256           TLSv1.2     Kx=DH           Au=RSA          Enc=AES(256)    Mac=SHA256
DHE-DSS-AES256-SHA256           TLSv1.2     Kx=DH           Au=DSS          Enc=AES(256)    Mac=SHA256
DH-RSA-AES256-SHA256            TLSv1.2     Kx=DH/RSA       Au=DH           Enc=AES(256)    Mac=SHA256
DH-DSS-AES256-SHA256            TLSv1.2     Kx=DH/DSS       Au=DH           Enc=AES(256)    Mac=SHA256
ECDH-RSA-AES256-GCM-SHA384      TLSv1.2     Kx=ECDH/RSA     Au=ECDH         Enc=AESGCM(256) Mac=AEAD
ECDH-ECDSA-AES256-GCM-SHA384    TLSv1.2     Kx=ECDH/ECDSA   Au=ECDH         Enc=AESGCM(256) Mac=AEAD
ECDH-RSA-AES256-SHA384          TLSv1.2     Kx=ECDH/RSA     Au=ECDH         Enc=AES(256)    Mac=SHA384
ECDH-ECDSA-AES256-SHA384        TLSv1.2     Kx=ECDH/ECDSA   Au=ECDH         Enc=AES(256)    Mac=SHA384
AES256-GCM-SHA384               TLSv1.2     Kx=RSA          Au=RSA          Enc=AESGCM(256) Mac=AEAD
AES256-SHA256                   TLSv1.2     Kx=RSA          Au=RSA          Enc=AES(256)    Mac=SHA256
ECDHE-RSA-AES128-GCM-SHA256     TLSv1.2     Kx=ECDH         Au=RSA          Enc=AESGCM(128) Mac=AEAD
ECDHE-ECDSA-AES128-GCM-SHA256   TLSv1.2     Kx=ECDH         Au=ECDSA        Enc=AESGCM(128) Mac=AEAD
ECDHE-RSA-AES128-SHA256         TLSv1.2     Kx=ECDH         Au=RSA          Enc=AES(128)    Mac=SHA256
ECDHE-ECDSA-AES128-SHA256       TLSv1.2     Kx=ECDH         Au=ECDSA        Enc=AES(128)    Mac=SHA256
DH-DSS-AES128-GCM-SHA256        TLSv1.2     Kx=DH/DSS       Au=DH           Enc=AESGCM(128) Mac=AEAD
DHE-DSS-AES128-GCM-SHA256       TLSv1.2     Kx=DH           Au=DSS          Enc=AESGCM(128) Mac=AEAD
DH-RSA-AES128-GCM-SHA256        TLSv1.2     Kx=DH/RSA       Au=DH           Enc=AESGCM(128) Mac=AEAD
DHE-RSA-AES128-GCM-SHA256       TLSv1.2     Kx=DH           Au=RSA          Enc=AESGCM(128) Mac=AEAD
DHE-RSA-AES128-SHA256           TLSv1.2     Kx=DH           Au=RSA          Enc=AES(128)    Mac=SHA256
DHE-DSS-AES128-SHA256           TLSv1.2     Kx=DH           Au=DSS          Enc=AES(128)    Mac=SHA256
DH-RSA-AES128-SHA256            TLSv1.2     Kx=DH/RSA       Au=DH           Enc=AES(128)    Mac=SHA256
DH-DSS-AES128-SHA256            TLSv1.2     Kx=DH/DSS       Au=DH           Enc=AES(128)    Mac=SHA256
ECDH-RSA-AES128-GCM-SHA256      TLSv1.2     Kx=ECDH/RSA     Au=ECDH         Enc=AESGCM(128) Mac=AEAD
ECDH-ECDSA-AES128-GCM-SHA256    TLSv1.2     Kx=ECDH/ECDSA   Au=ECDH         Enc=AESGCM(128) Mac=AEAD
ECDH-RSA-AES128-SHA256          TLSv1.2     Kx=ECDH/RSA     Au=ECDH         Enc=AES(128)    Mac=SHA256
ECDH-ECDSA-AES128-SHA256        TLSv1.2     Kx=ECDH/ECDSA   Au=ECDH         Enc=AES(128)    Mac=SHA256
AES128-GCM-SHA256               TLSv1.2     Kx=RSA          Au=RSA          Enc=AESGCM(128) Mac=AEAD
AES128-SHA256                   TLSv1.2     Kx=RSA          Au=RSA          Enc=AES(128)    Mac=SHA256

ブラウザ使用CipherSuites例。

Apache2.4.17 + OpenSSL1.0.2d で

SSLHonorCipherOrder Off
SSLCompression Off
SSLProtocol all -SSLv2 -SSLv3

を設定した場合。

Chrome46       TLSv1.2 ECDHE-RSA-AES128-GCM-SHA256
Firefox42      TLSv1.2 ECDHE-RSA-AES128-GCM-SHA256
Edge           TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384
IE11(Win10)    TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384
IE11(Win8)     TLSv1.2 ECDHE-RSA-AES256-SHA384

SNI

以下の条件のもと、SNIが使用可能。
もちろんブラウザの対応も必要。

1.Apache2.2.12以降
2.OpenSSL0.9.8h以降
3.OpenSSLがTLS拡張有効(enable-tlsext)でビルドされている

あとは普通に

NameVirtualHost *:443
SSLStrictSNIVHostCheck on

などとする。

IE8(Vista以降)以降、Firefox、Chrome、Opera11、Safari(Apple)は現状対応済み。
Android2.3.3(の標準ブラウザ)はダメだった( ´ω`)

Rewriteの順序

Rewriteを書くのがとても苦手(´・ω・`)
なぜなら書いてある順番と適用順が直感的に結びつかないから。
なので適用順序をおさらい。

1.RewriteRuleを書いてある順番に見ていくよ(`・ω・´)
↓
2.RewriteRuleにマッチしたかな?マッチしなかったら次のルール見てね。
↓
3.マッチした(`・ω・´)!
↓
4.マッチしたルールの上にRewriteCondはある?なかったらRewriteだ!
↓
5.あった(`・ω・´)!
↓
6.RewriteCondにマッチしたかな?マッチしなかったら次のルール見てね。
↓
7.マッチした(`・ω・´)!
↓
8.Rewriteだ!
↓
9.書き換えた(`・ω・´)!
↓
10.ルールにLフラグはあるかな?なかったら次のルール見てね。
↓
11.あった(`・ω・´)!
↓
12.じゃあそれが最後のルールだから「書き換えたURIについて1.からまた繰り返す」よ。
↓
13.えー(´・ω・`)

多分よく引っかかるのは

・書いてある順番からしてRewriteCondを先に評価しがち。
 →ルールが先。ルールにヒットしたあとコンディションを評価する。
・Lフラグがあるのにループする。
 →書き換えたあとのURIが(.*)などの正規表現にマッチしてループしている。

じゃないだろうか。

ExpiresとCache-Control

YSlowやPageSpeedで「キャッシュ期限を長めにしなされ」というアドバイスがある。
勿論、サイトの性質によって長く出来ない場合もあるが、原則静的コンテンツは変更頻度が低いものとして扱い
これらをmod_expiresで調整する。

例1)
サイト全体で
・すべてのファイルを
・アクセス時刻から1ヶ月先を期限にする
httpd.confに
ExpiresActive On
ExpiresDefault "access plus 1 month"

この場合レスポンスヘッダには、例えば

Cache-Control:max-age=2592000
Expires:Tue, 20 Nov 2012 11:04:05 GMT

のようなヘッダがつく。
バーチャルホストごとに設定。
<VirtualHost *:80>
    ExpiresActive On
    ExpiresDefault "access plus 1 month"
</VirtualHost>
ディレクトリごとに設定。
<Directory "/var/www/html/hoge">
    ExpiresActive On
    ExpiresDefault "access plus 1 month"
</Directory>
Files、Locationも同様。
例2)
・あるディレクトリの
・画像ファイルだけを
・アクセス時刻から1ヶ月先を期限にする
・それ以外のすべてのファイルはアクセス時刻から1週間先を期限にする
・ただし日替わり画像があるので、それはファイル更新時刻から1日先を期限にする
ExpiresActive On
ExpiresDefault "access plus 1 week"
<Directory "/var/www/images">
    ExpiresActive On
    ExpiresByType images/png    "access plus 1 month"
    ExpiresByType images/jpeg   "access plus 1 month"
    ExpiresByType images/gif    "access plus 1 month"
    ExpiresByType images/x-icon "access plus 1 month"
</Directory>
<Files "daily.png">
    ExpiresDefault "modification plus 1 day"
    または
    ExpiresByType images/png "modification plus 1 day"
</Files>

mod_cache

次はブラウザキャッシュではなく、サーバキャッシュ。
マニュアルに書いてある通りだが、以下のディレクティブは要注意。

CacheIgnoreCacheControl Off
Onの場合、Cache-Controlリクエストヘッダを無視してキャッシュで返事するので
スーパーリロード(Cache-Control: no-cache や Pragma: no-cache)しても
キャッシュ期間中はサーバキャッシュが返る。
CacheIgnoreHeaders Set-Cookie
キャッシュしたくないヘッダを列記する。Cookieキャッシュしたらコワイよね。
CacheIgnoreNoLastMod Off
Onの場合、Last-Modifiedレスポンスヘッダを無視してキャッシュに貯め込む。
CacheStoreNoStore Off
Onの場合、Cache-Control: no-storeを無視してキャッシュする。
no-sotreは「取り扱いが慎重な (例えばバックアップテープ上の) 情報の不注意な漏洩や保留を防ぐ事」が目的なので
基本、キャッシュしていいものではない。
CacheStorePrivate Off
Onの場合、Cache-Control: privateを無視してキャッシュする。
privateは「レスポンスメッセージのすべてもしくは一部は、単一のユーザのために用意された物であり、
共有キャッシュによってキャッシュされてはならない」ので同じくキャッシュしていいものではない。

CacheIgnoreHeadersを除くこれらのディレクティブはデフォルトがOffなので、
よほどの事がない限りいじらない方がよいかと( ´ω`)

セキュリティにまつわるヘッダ

アプリケーションで吐くとよいのだが、サイトによってはApacheで一括して吐かせた方が楽な場合もあると思う( ´ω`)

X-Frame-Options: [DENY | SAMEORIGIN]
クリックジャッキング防止に一定の効果があるヘッダ。

DENY:とにかくiframe frame表示は不可
SAMEORIGIN:自ドメインのみ表示可

今時フレーム、という感もあるが
フレームを使っているアプリケーションは自前でSAMEORIGINを吐いている事が多い。
Access-Control-Allow-Origin: [* | URI]
スクリプトによるクロスサイトリクエストの制御を行うヘッダ。

*:他ドメインからもアクセス許可
URI:指定ドメインのみアクセス許可

API提供サイトは"*"を指定すれば他サイトはJSONPでなくともリクエスト可能になる(CORS)。
また自サイトのURIを指定すれば自サイト内のXHRのみ許可され、SameOriginePolicy制約となる。
Strict-Transport-Security: max-age=expireTime [; includeSubdomains]
HTTPSのサイトに一度でもHTTPSで接続すると
同サイトにHTTPで接続しようとしたときにブラウザにHTTPSで接続し直させる。
サーバでリダイレクト処理などを行わなくてよいため
Man-In-the-Middle攻撃防止に一定の効果があるヘッダ。

max-age:有効時間(秒)。アクセス時刻+設定秒間、ブラウザは有効なhttpsサイトに接続する。
includeSubdomains:サブドメインを含めたい場合、記述する。

同ドメイン内にHTTPとHTTPSが混在していると、とにかくHTTPSで接続するので設定には注意が必要。
例1)AjaxでPOSTする先のファイル群があるディレクトリ
<Directory "/var/www/html/bin">
    Header always set Access-Control-Allow-Origin "http://www.example.jp"
</Directory>

例2)ログインフォームを含むファイル群があるディレクトリ
<Directory "/var/www/html/bin">
    Header always set X-Frame-Options SAMEORIGIN
</Directory>

例3)SSLで接続が必要なログイン画面
<Location "/login/">
    Header always set Strict-Transport-Security "max-age=604800"
</Location>

BEASTとCRIMEとあとなんか色々

1.BEAST
OpenSSLは0.9.6dで疾うの昔に対策済み。
ApacheもOpenSSLもまめに更新するべし。
Apache+OpenSSLだと実はこれだけでよさげ。
ブロックではなくストリームを使えばよろしいという流れがあり、RC4を使うことがあったが
RC4自体RFC7465で禁止となった。
2.CRIME
圧縮しない。ためのオプションは以下。

SSLCompression Off

2.2系は2.2.24以降でインプリメントされているので忘れないように。
3.Lucky13
OpenSSL1.0.1dで対策済み。更新しましょう。
4.RC4マルチセッション攻撃
RC4使わない。
5.POODLE
SSLv3を使わない。このためTLSv1以降に対応していないクライアントは接続出来なくなる。
SSLv2と同様に扱うだけ。

まとめると

SSLCompression Off
SSLProtocol all -SSLv2 -SSLv3
SSLCipherSuite 'TLSv1.2:!aNULL:!eNULL:!RC2:!MD5:!DES:!IDEA:!EXP:!SEED:!MD5:!RC4@STRENGTH'

みたいな。SSLv3も無効にしたのでTLSv1.2だけが有効となる。
こうなるとTLSに対応していない端末やブラウザは接続出来なくなるのだが そのようないにしえの端末は早々に切り捨てる方が世のため人のため(´・ω・`)

SSLCompressionの確認方法

Chromeでカギマーククリック→接続タブ
で、以前は圧縮してあるしてないの説明が出ていたのだが今は出ない( ´ω`)
なのでopensslコマンドで直接見る。

openssl s_client -connect example.com:443

●SSLCompression On の場合

New, TLSv1/SSLv3, Cipher is DHE-RSA-AES256-SHA
Server public key is 4096 bit
Secure Renegotiation IS supported
Compression: zlib compression ←ここ
Expansion: zlib compression ←ここ
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : DHE-RSA-AES256-SHA

    == snip ==

    Compression: 1 (zlib compression) ←ここ
    Start Time: 1375790533
    Timeout   : 300 (sec)
    Verify return code: 20 (unable to get local issuer certificate)
---
●SSLCompression Off の場合

New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES256-GCM-SHA384
Server public key is 4096 bit
Secure Renegotiation IS supported
Compression: NONE ←ここ
Expansion: NONE ←ここ
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : ECDHE-RSA-AES256-GCM-SHA384
 ---

で、確認可能。

Qualys SSL Labs SSL Server Test

https://www.ssllabs.com/ssltest/index.html
でのテストだが、普通のWebサイト運用では100をもらえる事はないと思うw
専用クライアント使うとかブラウザ超限定とか、実運用で100もらえるのは特殊な環境じゃないかな・・・。

■採点基準(PDFより)
Table 3. Protocol support rating guide

Protocol Score
SSL 2.0    20%
SSL 3.0    80%
TLS 1.0    90%
TLS 1.1    95%
TLS 1.2   100%

TLSv1.2「のみ」対応でないと100%にはならない。
TLSv1.2「のみ」対応にすると、BEAST、CRIME判定もクリアする。
SSLv3もダメになった今、もはやTLSv1.2のみでよいかと。
Table 4. Key exchange rating guide

Weak key (Debian OpenSSL flaw) 0%
Anonymous key exchange (no authentication) 0%
Key or DH parameter strength < 512 bits 20%
Exportable key exchange (limited to 512 bits) 40%
Key or DH parameter strength < 1024 bits (e.g., 512) 40%
Key or DH parameter strength < 2048 bits (e.g., 1024) 80%
Key or DH parameter strength < 4096 bits (e.g., 2048) 90%
Key or DH parameter strength >= 4096 bits (e.g., 4096) 100%


nginxはパラメータで4096bitのDHパラメータファイルを指定すれば良い。
DHパラメータファイルはOpenSSLなどで作成する。
Table 5. Cipher strength rating guide

Cipher strength             Score
0 bits (no encryption)         0%
< 128 bits (e.g., 40, 56)     20%
< 256 bits (e.g., 128, 168)   80%
>= 256 bits (e.g., 256)      100%

256bit以上のCipherを指定する。
多くのAndroid標準ブラウザはつながらなくなるんじゃなかろうか( ´ω`)

80以上でGRADE Aなので、普通に構成していればGRADE Aでしょう。
あと、BEASTとCRIMEの判定もあるので参考にするとよいかも。

Mozilla SSL Configuration Generator

https://mozilla.github.io/server-side-tls/ssl-config-generator/
指針に使うとよいかも


トップ   編集 凍結解除 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2015-11-09 (月) 13:18:12