Hatena::ブログ(Diary)

めもおきば このページをアンテナに追加 RSSフィード

Contact: akitan@gmail.com
noteにて投げ銭受付中 ⇒ 【投げ銭】こたろー写真

2015-07-15

「通信の最適化」の論点

論点書き出してみたけど多すぎて超絶カオス。

  • 現状発生している実害
  • 技術的詳細が非公開
  • 最適化」という単語の是非
  • オプトインとオプトアウト
    • 送信者(コンテンツ提供者)の同意
      • 自衛のために全HTTPS化することで、かえってトラフィック増える問題
      • HTTPS化による計算機コスト、ファイル改竄による不具合対応のリスクの負担
      • サービス内容の意図しない/再現が難しい劣化*1
        受信者の財産権の侵害とも言える。
    • 受信者(顧客)の同意
      • 消費者保護観点からより深い内容周知の上での同意が必要では無いか
    • オプトアウトが可能かどうか
  • ISPとしてのサービスが土管であるべきか否か
    • 例えば、可逆圧縮での再圧縮なら良かったのかどうか
    • 携帯キャリアが提供しているのは「インターネット」サービスかどうか
  • ISPとしての正当業務行為に含まれるかどうか (以下の各種法令における違法性阻却事由)
  • アプリケーションレベルで内容を見ることが「通信の秘密」に触れるか否か
    • DPI議論
    • 帯域制御の運用基準に関するガイドライン
      • 帯域制御を目的するか否か
      • 「個別かつ明確な同意」があったかどうか
    • 電気通信事業法第四条
      • 特に「符号、音響又は影像」で音響と映像が切り出されていることの解釈
  • アプリケーションレベルで内容を変更することが「検閲の禁止」に触れるか否か
    • 憲法21条2項, 電気通信事業法第三条
  • 著作権 (同一性保持権)
  • 公職選挙法
    • 「候補者のウェブサイトの改ざん等、選挙に関し、文書図画を毀棄し、その他不正の方法をもって選挙の自由を妨害」*2

判断ポイント

  • オプトアウトができれば良いのか
  • デフォルトoffで明確な利用者(端末契約者)のオプトインがあれば良いのか
  • 可逆圧縮での再圧縮なら良いのか
  • HTTPレスポンス本文のデコード結果を改変しないレベルなら良いのか
    • 例: HTTPレスポンスをTransfer-Encoding: gzip(delfate)にして圧縮する
    • 例2: HTTP/1.1のpersistent connectionやpipeliningで接続をまとめる
  • HTTPレスポンス本文は変更せずヘッダの改変だけなら良いのか
    • 例: Content-Length外してchunkにする

  • トランスポート層の壁>

  • TCPの再構成だけなら良いのか
  • パケットのフラグメント再構成*3なら良いのか

  • <極論の壁>

  • NAPTに必要なTCP/UDPのポート番号変更以外の全てのIPパケットペイロードの変更を禁じるのか(インターネット原理主義者)
  • NAPTも禁止し、IPパケットヘッダ以外の全ての変更を禁じるのか(真のInternet Protocol原理主義者)

*1:とくにニコニコ動画など「画質」によるフリーミアムモデルを採用している場合

*2http://twitter.com/kei1_yama/status/624094538659860480

*3:例: PFのscrub

2015-06-29

Linuxうるう秒おさらい

7/1 午前9時(JST)にうるう秒が挿入されますが、注意すべきポイントのおさらいです。

うるう秒って何よ

NICTの資料の先頭7ページ目まで読んでください。

ざっくり言うと、現在の時計というのは「原子時計」が基準になっています。太陽の周りを回る公転周期に合わせて微調整するのがうるう年で、地球自体が回転する自転時間に合わせて微調整するのがうるう秒です。

現象としては、「月末」の日付が変わる直前に1秒追加されます。ただし、これはUTC(協定世界時)での話なので、日本標準時では9時間の時差があるので朝9時(の直前)になるわけです。

時間の進みを表にするとこんな感じです。

UTC(協定世界時)JST(日本標準時)うるう秒を知らない時計
2015年 6月30日 23時59分57秒2015年 7月 1日 8時59分57秒2015年 7月 1日 8時59分57秒
2015年 6月30日 23時59分58秒2015年 7月 1日 8時59分58秒2015年 7月 1日 8時59分58秒
2015年 6月30日 23時59分59秒2015年 7月 1日 8時59分59秒2015年 7月 1日 8時59分59秒
2015年 6月30日 23時59分60秒
うるう秒発生!
2015年 7月 1日 8時59分60秒2015年 7月 1日 9時 0分 0秒
2015年 7月 1日 0時 0分 0秒2015年 7月 1日 9時 0分 0秒2015年 7月 1日 9時 0分 1秒
ここで1秒進んでしまう!
2015年 7月 1日 0時 0分 1秒2015年 7月 1日 9時 0分 1秒2015年 7月 1日 9時 0分 2秒
2015年 7月 1日 0時 0分 2秒2015年 7月 1日 9時 0分 2秒2015年 7月 1日 9時 0分 3秒
2015年 7月 1日 0時 0分 3秒2015年 7月 1日 9時 0分 3秒2015年 7月 1日 9時 0分 4秒

おわかり頂けただろうか。


本当はこわいうるう秒

前回のうるう秒は2012年7月1日(JST)に挿入されましたが、このときにLinuxカーネルでいくつかの不具合が判明しました。

一番影響が大きかったものが「CPU利用率が100%に張り付く」というもので、以下のブログ記事が詳しいです。

これは「不具合」による想定外の問題でしたが、そもそも「想定内」の範囲でも以下のような問題があります。

  • タイムゾーンの設定
    • Linuxでは、例えばJSTであれば right/Asia/Tokyo という特殊なタイムゾーンを設定した場合にのみ、59分60秒といううるう秒の時刻を取得できます。
    • Asia/Tokyo のままだと、59分59秒を二周します。IBMの技術記事の表記が分かりやすいので引用します。
      • 23:59:59.000000(→ 23:59:59.999999)→ 23:59:59.000000 → 00:00:00.000000 (小数点以下が 1 秒以下の時刻を表します。) *
  • ログの前後関係の逆転
    • たとえば操作履歴の分析を想像して、手動で全力出しすぎて1秒以内に連続で操作したような場合、59分59秒を2周するような設定だと、操作の前後関係が逆転する可能性があります。
      • 8時59分59秒 800ミリ秒 操作A
      • 8時59分60秒 400ミリ秒 操作B → 8時59分59秒 400ミリ秒と記録され操作Aより前とみなされてしまう
    • また、監査ログの紐付けなどでも同様の問題が発生します。
  • 時刻が修正されるタイミングの不一致
    • 誤ったやり方でうるう秒を回避しようとした場合に発生します。
    • 広く使われているNTPソフトウェアでは、うるう秒の事前情報(後述するLeap Indicator)が無い場合には、時間のずれを検知してから15分間たってから一気に時刻を調整します。上位のNTPサーバに接続する間隔は、サーバの起動時間などの理由でバラバラなので、時刻が調整されるタイミングもバラバラになります。これではログ上の時刻突き合わせもできなくなり死ぬしかなくなります。

このように、きちんと考えると奥が深いのがうるう秒の処理です。


うるう秒を正しく扱う

比較的新しいサービスのみ面倒を見ているのであれば、おそらくうるう秒に起因する不具合もないでしょうから、全力でうるう秒を受け入れてあげるのが良いと思います。2012年以上前のディストリビューションでは上記不具合が修正されていない可能性がありますが、それ以外は特に何の問題も無く動くと期待されています。

「60秒」を保存できることを確認できているなら、right/Asia/Tokyo などのタイムゾーンに変更するとより良いです。

本来のうるう秒の処理

例えば、インターネットマルチフィードのNTPサーバから時刻を受信し、データセンター内の自前NTPサーバを立てているようなケースを想定すると、全体像は以下のようになります。

f:id:nekoruri:20150629203922p:image:w640

うるう秒の情報は、最終的には3つの方法で各サーバのLinuxカーネルに届きます。

1. 清く正しいLinuxカーネルうるう秒を処理

うるう秒の情報は、NTPのLeap Indicator(LI)というフラグを経由して各サーバに配布されます。最新のRFC上は一ヶ月前からフラグを立てても良いことになっていますが、NICTでは以前のRFC等も考慮してうるう秒の24時間前からフラグを立てる運用となっています。

Leap Indicatorを受け取ったNTPクライアントは、adjtimex(2)というシステムコールを呼んでLinuxカーネルうるう秒の情報を伝えます。Linuxカーネルはtime_stateという変数にそれを保存しておき、月末(UTC)になったらその変数を見て必要ならばうるう秒を挿入します。

カーネル内部のシステムクロックは正しくうるう秒を扱いますが、プロセスから現在時刻を聞かれたときには、right/Asia/Tokyo などうるう秒対応のタイムゾーンが設定されていれば、59分60秒という正しいうるう秒時刻を返し、そうでなければ59分59秒を2周するような時刻を返すようになります。2周する場合も、カーネルにより厳密にループが行われるので午前9時0分0秒(JST)になることなく繰り返されます。

標準ntpdのデフォルト設定(STEPモード)ではこの動作となります。また、ChronyではSLEWモードで設定をしていてもLinuxカーネル側でうるう秒を挿入するようです。

万が一、カーネルうるう秒情報を受け取ってしまった後になって回避策を実施したい場合は、ntptimeコマンドでカーネル内のtime_stateを変更することができます。外部NTPサーバを参照するntpdが起動しっぱだとまた受け取ってしまうのでそちらの対応もお忘れ無きよう。

% sudo ntptime

ntp_gettime() returns code 1 (INS)

time d93c801b.a8d4dc28 Tue, Jun 30 2015 11:40:27.659, (.659498716),

maximum error 207343 us, estimated error 490 us, TAI offset 0

ntp_adjtime() returns code 1 (INS)

modes 0x0 (),

offset -30.648 us, frequency -0.114 ppm, interval 1 s,

maximum error 207343 us, estimated error 490 us,

status 0x2011 (PLL,INS,NANO),

time constant 8, precision 0.001 us, tolerance 500 ppm,

% sudo ntptime -s0

(省略)

% sudo ntptime

ntp_gettime() returns code 0 (OK)

time d93c8023.30a87000 Tue, Jun 30 2015 11:40:35.190, (.190070),

maximum error 211343 us, estimated error 490 us, TAI offset 0

ntp_adjtime() returns code 0 (OK)

modes 0x0 (),

offset -30.000 us, frequency -0.114 ppm, interval 1 s,

maximum error 211343 us, estimated error 490 us,

status 0x0 (),

time constant 8, precision 1.000 us, tolerance 500 ppm,

2. NTPうるう秒の処理

何らかの設定により、NTPクライアントうるう秒の処理をする場合があります。

具体的には、ntp-4.2.6p5-1.el6、ntp-4.2.6p5-2.el6_6、および ntp-4.2.6p5-18.el7 以下を実行しているRHELディストリビューションでSLEWモード(後述)を設定した場合などが挙げられます。これらの環境では、Leap IndicatorによりNTPクライアントうるう秒を把握しますが、その情報をLinuxカーネルには渡しません。その代わり、うるう秒になったらstetimeofday(2)やclock_settime(2)などのシステムコールを用いて1秒間時刻を戻します。

カーネルの処理では無いため、一瞬だけ9時0分0秒(JST)を過ぎてから8時59分0秒(JST)に戻されます(検証例あり)。

これは、安定した結果を保障できないため、オススメできません。


3. NTPを利用せずtzdataからうるう秒を取得

タイムゾーンの情報をまとめたtzdataというパッケージには、最新のうるう秒の情報が含まれます。そのため、最新のtzdataパッケージに更新しておくことで、NTPを利用できない場合にもうるう秒の処理を適切に行うことができます。

実際のうるう秒前後の挙動は、1の場合と同じです。

うるう秒を全力を挙げて見逃すには

このように、うるう秒を上手い具合に処理するためにいくつかの方法が用意されているわけですが、古いカーネルで動けど止めづらいサーバがあったり、サーバ数が多すぎて漏れの無い対応がし切れないなどの理由で回避が必要であれば、全力を挙げて見逃す必要があります。その為には、以下の2つをどうするかを考えなくてはいけません。

  • 本来のうるう秒の処理を行わせない。
  • 別の方法でうるう秒の1秒を「うまく」さしこむ。

うるう秒三原則の厳守

回避すると決めたら、大事なのは「うるう秒をもたず、つくらず、もちこませず」の非うるう秒三原則をどう厳守するかを考えます。

1. 持たない

ntpdにパッチを当てることで、強制的にLeap Indicatorをクリアする方法があります。

私は未検証なので紹介に留まりますが、IBMの記事では01や10に強制セットするパッチが下部「図3」として記載されているので、00に強制クリアすることも可能でしょう。

2. 作らない

ntpdが落ちている場合でもうるう秒が不用意に挿入されないよう、意図しないサーバでtzdataが最新にならないようにします。

なお、最新のtzdataが入っているようなケースは他のパッケージでもうるう秒の影響を受けづらいとは思います。

3. 持ち込ませない

Leap Indicatorを除去するためには、仮想化環境でない物理サーバがあるのであれば、ハードウェアクロック(RTC)もそれなりに正確ですので、一時的に外部のNTPサーバへの参照を辞めてしまうのが一番手っ取り早いです。

前述したとおり、NICT系のNTPサーバではうるう秒の24時間前からLeap Indicatorが設定されるので、それより前からうるう秒の後まで、24時間以上を外部への参照を止める必要があります。当然ながら、RTCの品質があまりにも悪い場合や仮想サーバなどでは秒単位で時刻がずれてしまう可能性もあります。

今後Leap Indicatorが一ヶ月前から設定されるようになると現実的では無くなるでしょう。それまでにはうるう秒を誰もが受け入れられる優しい世界か、なんらかの代替策が用意されていると嬉しいです。


1秒の挿入方法

うるう秒を無視するためには、その1秒を何らかの形で「より影響が少ない方法」で反映する必要があります。これは、時計をゆっくり動かして1秒を生み出すのが一般的です。実際に、パブリッククラウドAWSGCP、携帯キャリア、東京証券取引所などではこのやり方を採用しています。

一般的には、ntpdのSLEWモードを使う事になります。特に自前でNTPサーバを立てず、NTPクライアント側で設定を入れるのであれば、「-x」オプションを付ければ良いです。ただし、前述したとおりNTPのバージョンによってはSLEWモードにしていても、うるう秒だけは1秒ガツンと戻されるような不具合がすぐ最近まで残っていたので、注意が必要です。

その一方で、前述の図のように自前NTPサーバを立ててそこを参照しているような場合は、NTPクライアントの設定によりNTPサーバに時刻を聞きに来る頻度がデフォルト設定でも1024秒(約17分強)だったりするので、NTPサーバに「-x」オプションを付けるだけではダメです。また、自前NTPサーバも冗長化している場合にはそのサーバ間での時刻同期も重要となってきます。


このように、結構厄介な地獄が待っていますが、詳しくはそのうちどっかで記事に載るのでは無いでしょうか(他人事)。

確認方法

自由に偽時刻やLeap Indicator、うるう秒を発生させられる検証用NTPサーバNICTさんが配っているので、それを上位NTPサーバとして検証ができます。

まとめ

うるう秒でも正しく動くシステムを作りましょう。

そして、うるう秒の廃絶に向けて、廃止の動きを応援しましょう。


NTPに関する情報

更新履歴

2015-05-21

うるう秒まとめ

今年は、2015/07/01 08:59:60 JST としてうるう秒が挿入されます!(うるう秒実施日一覧)

うるう秒なんてきちんと処理したくない」という人向けのまとめ。

まとめっぽい記事

AWS

GCP

前後10時間ずつ、計20時間かけて調整

  • 最大で0.5秒前後0.5秒のズレ。
  • うるう秒の前は「lie(t) = (1.0 - cos(pi * t / w)) / 2.0」の計算式に沿うが、うるう秒後はSLEW相当?
  • 「おおよそ 100 万分の 14 ずつ」(0.5秒/10時間)ずらして、うるう秒前後で最大0.5秒ズレる。
    • 2011年の時は上記の複雑な計算式を利用していたが、2015年では単純な手法に変更された。
  • metadata.google / metadata.google.internal としてNTPサーバが提供される。外部への提供はない(もし必要なら自前でNTPサーバ建てて公開すれば良い)。

Microsoft Azure

  • 資料が見つからなかった。

ntpd SLEW mode

うるう秒直後時点で1秒時計が先に進むが、そのあと少しずつ修正される。

ntpd LI flag + STEP mode

Leap Indicatorフラグを元に、うるう秒直後に1秒巻戻る。

  • 最重要ポイント: 時間が逆行する(同じ1秒間が二度繰り返される)

23:59:59.000000(→ 23:59:59.999999)→ 23:59:59.000000 → 00:00:00.0000007/1の閏秒を迎えるにあたってLinuxでは何をすべきか?

Windows

ドメイン コントローラーの場合】

(略)

つまり、NTP Server との時刻差が 5.25 秒未満、もしくは 3.5 秒未満の場合は、Slew モードで時刻同期が行われる結果となります。

ドメイン メンバー サーバーの場合】

(略)

つまり、NTP Server との時刻差が 225 秒未満、もしくは 150 秒未満の場合は、Slew モードで時刻同期が行われる結果となります。

【ワークグループの場合】

(略)

つまり、NTP Server との時刻差が 1 秒未満の場合は、Slew モードで時刻同期が行われる結果となります。

雑感

この中だと「0.5秒ずらしておく」で丁度良い人が多そうだけどAWSGCPでも実装が異なるし、基盤をまたいで時刻を統一するのは諦めた方が良さそう。0分0秒の方をきっちり合わせたい人が多そうだから、あらかじめ最大1秒進めておくのもアリなのではと思うけど、そういう実装はないようだ。

エンタープライズ用途とか、0分0秒の厳密さが求められる場合には、マルチフィードみたいな正しくLeap Indicatorを実装したNTPサーバと同期する必要したうえで、その場合もミドルウェアやアプリケーションが正しくうるう秒(59分60秒999999)を扱えることを確認する必要がある。

追記

  • 2015-05-22 21:00 AWSについて、EC2系はAWS調整時刻ではないことを追記、AWSGCPNTPサーバ提供有無について追記
  • 2015-05-26 14:00 新しい記事によるとGCPは単純な計算式に変更されたようなので修正
  • 2015-05-29 13:42 NICTの説明資料を追加

NTPリンク

2015-05-14

VENOM(CVE-2015-3456) 影響範囲メモ


追記

  • 2015-05-14 15:00 「ゲストがホストをクラッシュさせられる」を「ゲストがホストのQEMUプロセスをクラッシュさせられる」に変更しました。

2015-03-20

脆弱性の危険度(ざっくり)

まあCVSSの解説見ろよって話なんだけど、ありがちな脆弱性の危険度は個人的にはこんなイメージです。

総合的な危険度 = 条件 × 影響

条件

脆弱性の攻撃に必要な前提条件が「狭い」のであればそれほど問題ないです。

  1. 一番ヤバイ: TCPUDP、IPによりネットワークから送られた通信で攻撃が成立
    • Slammer(しかもハンドシェークが不要なUDPのため被害が拡大)
    • Heartbleed
    • Shellshock、GHOST(ただし一部のミドルウェア)
  2. だいぶヤバイ: 通信路に割り込まないとイケない(MITM) *1
    • アクティブに通信に割り込むかどうかで度合いが変わる
    • POODLEとか
    • FREAK
  3. そこそこヤバイ: ネットワーク経由での攻撃ができるが、認証後でないと成立しない
  4. ヤバイ: ログイン後の一般ユーザーで攻撃が成立
  5. ちょっとヤバイ: 弱い設定をしている場合など限られた条件でのみ攻撃が成立
    • 当初はFREAKもここだと思われていた
  6. まあヤバイ: 物理的に接触された場合にのみ攻撃が成立
    • USB メモリに扮したキーボードデバイスみたいな奴

影響

  1. 即死級: コード実行
    • 送り込まれたプログラムコードを実行してしまう。
    • 発見次第即座にパッチを当てないと死ぬ。攻撃条件次第ではインターネット崩壊
    • Shellshock、GHOSTはここ、ただし、コード実行に至る条件がそれなりに厳しかった
    • 伝説のSQL Slammerもこれ。発生して最初の10分間で、インターネット上の条件を満たすサーバの90%に相当する75000台に感染したらしい。
  2. 超緊急: PKI基盤の毀損
    • 他の攻撃とセットでremote code送り込まれるから可能性が生まれただけでアウトなんだよ!!
    • この前のLenovoSuperfishみたいなやつ。
  3. 緊急: サーバ内容(ディスクやメモリ)の漏洩
  4. 重要: 通信内容の漏洩
    • ログイン情報などが漏れた場合は利用者対応が必要
    • あくまでサービスの機能として可能な範囲に影響は留まる (提供していないことはやられない)
    • 特定のサービスを対象に大規模にMITM等が行われた場合、リスト型攻撃などのリスト作成に使われる可能性もあるにはある。
    • FREAKやPOODLE
  5. 要対応: サービス停止(DoS)
    • サービスが止まること自体の損害のみ
    • ただし、DoSと思っていたら、後になってメモリ漏洩も可能と変身回数を残している場合があるので注意。
    • 今回のOpenSSLとか、ほとんどの環境におけるGHOST

備考

あくまで「ざっくり」なので、エンジニアであればちゃんとCVSSの解説を読んで、どういう判断軸があるか知った方が良いです。

  1. 基本評価基準 (Base Metrics)
    1. AV :攻撃元区分 (Access Vector)
    2. AC :攻撃条件の複雑さ (Access Complexity)
    3. Au :攻撃前の認証要否 (Authentication)
    4. C :機密性への影響 (情報漏えいの可能性、 Confidentiality Impact )
    5. I :完全性への影響 (情報改ざんの可能性、 Integrity Impact )
    6. A :可用性への影響 (業務停止の可能性、 Availability Impact )
  2. 現状評価基準 (Temporal Metrics)
    1. E :攻撃される可能性 (Exploitability)
    2. RL :利用可能な対策のレベル (Remediation Level)
    3. RC :脆弱性情報の信頼性 (Report Confidence)
  3. 環境評価基準 (Environmental Metrics)
    1. CDP :二次的被害の可能性 (Collateral Damage Potential)
    2. TD :影響を受ける対象システムの範囲 (Target Distribution)
    3. CR, IR, AR :対象システムのセキュリティ要求度(Security Requirements)

上では、基本評価基準のうちAV+AC+Auの例を「条件」、C+I+Aの例を「影響」として紹介しました。

実際に、脆弱性対応の緊急度(どれぐらいの間に対応が強いられているか)を判断するには、現状評価基準や環境評価基準の項目を考慮する必要があります。

*1DNSが脆弱であることが判明しているので、ドメインネームで通信を行うのが一般的な現状では攻撃の条件としてだいぶ容易になっています。