てきとうなメモ

本の感想とか技術メモとか

DNSがよくわかる教科書

DNSの知識が足りていない気がして教科書的なものを読んでみたくなって、読んでみた。

DNSの基本的な仕組みから、DNSSECやQNAME minimisation、DNS over TLSDNS over HTTPSなどセキュリティやプライバシーを考慮した拡張仕様の話など一通り書かれてあった。 JPRSの人が書いているので、JPドメインの管理運用みたいな話も書かれているのが、特徴的な気がする。

ただ、やはり入門書であって各仕様の詳細については書かれていないので、そのあたりはRFCを読んでいかないといけないな。

ALPACA Attack

ALPACA Attack

論文ちょっと読んでみた。

サーバAへのリクエストを同じサーバ証明書を利用している別プロトコルのサーバBに流すことで、秘密情報を盗んだり、XSS攻撃をすることができるという話。攻撃者はクライアントとサーバの間にいて、TLS通信を本来のサーバAからサーバBに流すことで攻撃している。

Attack Overview

公式サイトにあるこの図を用いて説明すると、被害者は攻撃者が用意したサイト(www.atacker.com)にいる。このサイトでクロスサイトのリクエストをwww.bank.com:443に投げる。www.attacker.comは攻撃者のサイトなので、POSTの内容は攻撃者が指定することができる。

被害者のクライアントとwww.bank.com:443の間に攻撃者は存在し、リクエストをftp.bank.com:990などに流す。TLSは(SNIやAPLNを利用しないと)プロトコル、ホスト名、ポート番号が意図していたものかを確認しないため、攻撃者はリクエストを別ホスト、別ポート、別プロトコルに流すことができる。

この時点でcookie等秘密情報をftp.bank.comに流すことができている。ftp.bank.comの実装がこの情報をログに出すなどしており、攻撃者がftp.bank.comのログを見ることができるのであれば、この秘密情報を盗むことができる(Upload Attack)。

さらに、攻撃者はftp.bank.comのレスポンスをクライアントにwww.bank.comのレスポンスとして返すことができる。ここに含まれるJavaScriptがクライアント(ブラウザ)上で実行されるとXSS攻撃となる(Download Attack)。

別の方法として、www.attacker.com上でFTPとして解釈するとエラーメッセージを返すようなリクエスト「HELP 」をwww.bank.com:443に投げる。中間者攻撃をしてこれをftp.bank.com:990に流す。そうすると、ftp.bank.comはFTPのエラーメッセージとして「Unknown command: 」を返す。しかし、クライアントはブラウザなので、HTTPのレスポンスとして解釈され、スクリプトが実行される(Reflection Attack)。

図ではFTPサーバにリクエストを流して攻撃しているが、論文では他にSMTP,POP3,IMAPなどメールサーバを使っても攻撃可能としている。

攻撃条件

攻撃が可能である条件は

  • 被害者をwww.attacker.comに誘導する
  • 被害者と攻撃対象サイト(www.bank.com:443)に対して中間者攻撃ができる
  • HTTPのリクエストが来てもリクエストを流す先のサーバがエラーにしないような実装になっている必要がある
    • この条件が厳しそうに見えるが、そういう実装はそれなりにあることが論文で指摘されている
  • Download AttackやReflect Attackの場合、ブラウザがIEや古いEdge(非Chromium)のようにContent Sniffingする仕組みを持っている必要がある
    • HTTP上のHTMLではないレスポンスが返るのが、それをブラウザにHTTP上でHTMLを返していると誤解させる必要がある
  • 攻撃対象のサーバと中間者がリクエストを流す先のサーバが同じ証明書を利用している

と、かなり難しい。

HTTPのリクエストを受け入れるHTTP以外のサーバ実装

そんなになさそうに見えるのだが、調査したほとんどのSMTP/POP3/IMAP/FTP実装では「POST / HTTP/1.1」のようなリクエストラインやリクエストヘッダまでは受け入れる動作をしている。ただし、そこから先のリクエストをエラーでコネクションが切れることなく攻撃可能かとなると難しい。ただし、SendMail(SMTP)、Cyrus(IMAP)、Courier(POP3)、Microsoft IIS、vsftpd、FileZilla Server(FTP)などの有名所のサーバ実装を利用して攻撃が可能になるようだ。

対策

別のサーバには別の証明書を用いれば良いのではとなるが、実運用上はワイルドカードの証明書使いたいだろうし、難しいよねとしている。

ALPNやSNIを正しく実装することで、TLSを使っているが、そのプロトコルはHTTPなのかFTPなのか、ホスト名はwww.bank.comなのかftp.bank.comなのかを決めてから通信すれば、今回のような攻撃を防ぐことができる。ALPNはHTTP/2が広まったため実装しているHTTPクライアント/サーバは増えている。しかし、プロトコルネゴシエーションに失敗しても通信を切るような実装になっていなかったり、HTTP以外のTLS通信可能なサーバがALPNをほとんどサポートしていないという問題がある。

厚労省のCOCOA不具合調査報告書を読む

接触確認アプリ「COCOA」の不具合の発生経緯の調査と再発防止の検討について(pdf)

を読んでみたのでメモ

匿名化されている部分

事業者の名前が匿名化されているけども、委託事業者はパーソルプロセス&テクノロジー、再委託事業者Aは日本マイクロソフト、再委託事業者Cはエムティーアイと読めばよさそう。

時系列

  • 2020/09/01 COCOAソースコードGithub上で公開
  • 2020/09/24 iOS版v1.0.4リリース(問題の不具合混入)
  • 2020/09/28 Android版v1.0.4リリース(問題の不具合混入)
  • 2020/10/12 テスト環境の整備が完了
  • 2020/11/25 Github上の通知が来ないとの指摘
  • 2020/12/04 Github上の当該指摘を検討リストに追加
  • 2021/01/08〜25 SNSや報道を通じて状況を知り、事業者側でテストを実施
  • 2021/01/25 厚労省と事業者の打ち合わせで、通知が来ていない可能性を報告
  • 2021/02/18 v1.2.2(対策版)をリリース

バージョンの関係

v1.0.3で通知が必要以上に来る障害があった。で、v1.0.4でその対策をしたのだが、不要な通知だけでなく、必要な通知も来なくなった。それをv1.2.2で修正したという流れ。

v1.0.4での今回の不具合の混入について

原因については、zipperpullさんの解説の通りかと思うので省略。

基本的にテストで防ぐべき不具合だと思うが、テスト環境が用意できていないので、実際に通知が来るかどうかというようなテストはやっていなかった模様。

そのためもあり、CIO補佐官Bはリリースのためソースコードを1行1行チェックしていたらしい。CIO補佐官ってそこまで実務をするイメージなかったのだが、かなり泥臭いことまでやっていたのだなあ。

CIO 補佐官 B は、実機という意味では事業者側もテストしていたが、HER-SYS の機能を模擬するテスト環境がなく、陽性登録をして接触の検知をするという一連の流れのテストはできない状況だった旨、昨年9月頃から、COCOA 通知を受けた方の検査を公費でできるようにしたということもあり、保健所の負荷が非常に高まっている状態で問い合わせもすごい数が来ていたため、かなり急ぎで対応すべき状況であった旨、その中で、自身もソースコードを一行一行チェックし、変更想定範囲に対しての実装は正しいということを確認した上で、ある意味リスクを取って決定した旨、管理職級B に相談した上で、現場の判断としては自身がリリースを判断した旨を述べている。

まあ、ソースコード読んで気づくことのできるタイプの不具合ではないので、ここで防げなかったのは仕方ないと思う。

テストについて

時系列にあるように2020/10/12にテスト環境が整備された。テスト環境整備前はできる範囲のテスト(アプリ起動や画面遷移、デバッグモードによる動作確認など)ぐらいしかしていない。 テスト環境が整備された後に結合テストをしているが、接触通知が発生しやすいようにパラメタを調整していたので、今回の不具合は見つかっていない。 その後のバージョンアップ時のテストは、接触通知とは関係ない修正だったので、テストはしていない(リグレッションテストはしていないということだと思う)

テスト環境の整備は、エムティーアイが手が空いたときにやっていたようで、優先度は(少なくともリリースと比較して)高くなかったという認識のようだ。

Github上での指摘について

問題のissueは、2020/12/04にエムティーアイが検討リストに載せており、事業者側は認識していたが、厚労省は2021/01に初めて知ったっぽい。

Githubのissueの扱いが関係者で異なるように見える。パーソルによると、2020/09に厚労省がパーソルにGithubのissueを契約にはないが追加で管理してほしいという依頼をした。パーソルはエムティーアイにissueの検討リストへの追加と重要度の判断を依頼する。エムティーアイは検討リストへの追加はするが、重要度の判断は別のところがやるという認識で、ずれている。

体制の問題

COCOAに限らず、新型コロナ関連の仕事は激務になるので、厚労省は頻繁に人員の入れ替えを行うことにしているようだ。これは逆効果な気がする。 また、厚労省内で体制強化の依頼は上にあげていたが、新型コロナで全体的に人が足りていないので、体制強化はされなかったようだ。

あと、以下のように厚労省側にCOCOAの重要性を低めに見ている人たちがいるのがちょっと気になった。このような話もあるので、一理あるとは思う。

指定職級Nは、HER-SYS は保健所の業務の効率化のために重要だと思っていたが、COCOAにはそこまでの認識がなかった旨、国民の期待感や関心は高いという認識はあったが、保健所の積極的疫学調査の補完的役割だと認識していた旨を述べている。また、指定職級G は、COCOA は効果が分かりにくいと思う旨を述べている。

指定職級Kは、全体の中で COCOA はそれほど大きな位置づけを占めていなかった旨、順にいくと、検疫、水際があって、医療があって、保健所問題があって、ワクチンがあって、治療薬があって、もちろん生活支援とか雇用対策とかは別にあったが、その中で COCOA は確か、当面の関心が設計といったものではなく、これは非常にいいものだからどんどん入れていかなければいけない、むしろ広めるのが大事なので、ダウンロード数をとにかく早く上げるということで進捗状況を報告してもらっていた旨を述べている。

感想

テスト環境の整備やテストの実施に対する認識が甘いと思う。テスト環境を早めに構築すべきだったし、構築したならば、テストをしっかり実施すべきだった。そこで見つかった不具合で、タスクの優先順位が変化する可能性もあるわけなので。

エムティーアイもそこはしっかり認識しているようだ。

再委託事業者C は、...一番反省しているのは、何があっても検知できるようなテストを、テストができる状態になったときに、やり直しましょうというふうにできなかったことである旨を述べている。

あとは厚労省側の体制の問題が大きいかな。厚労省側の担当やCIO補佐官が頻繁に入れ替わるのが良くないし、発注者側のリソースや知識が足りないのも問題かと思う。以下のように担当が音を上げているけど、対応できていないのがつらい。

指定職級Jは、...当時の担当は「自分を支えてくれる人がいないとうまくいかない」等と陳情していたが、人を張り付けるにも張り付ける人自体がいない、全体の仕事量に対するリソースが少な過ぎるという問題から、望むとおりには人はつかなかったと思う旨を述べている。

noteで執筆者のIPアドレスが漏洩した件

note.jp
note.jp

の件について思ったことをつらつらと

IPアドレスで個人特定可能か、IPアドレスは個人情報かどうか

これについては楠さんの説明が良さげ。単体で個人特定は難しいけど、いろいろ紐付けることができると個人特定できる可能性がある。そして紐付いた状態で保存されていると個人情報保護法の対象になる。

原因

今は修正済みなので自分は解析していないのだが、以下の方によるとAPIの出力にIPアドレスが入っていて、それをHTMLに出力したっぽい。


該当のAPIの出力を今見ると、IPアドレス等は出力されていないのだが、問題発生時は以下のような属性が出力されていたようだ。

last_sign_in_ipはRails+Deviseでユーザモデルが保持する属性なので、このAPIRails+Deviseで構成されていると予想される。

Devise批判

Deviseの属性をそのまま出しているということから、以下のようなDeviseに対する批判も出てきている。

diary.app.ssig33.com


ただ、自分の意見は以下の方の意見に近いかな。

sinsoku.hatenablog.com

DeviseはRailsを深く理解しないと使ってはダメと言っているのか

深く理解というのがどのレベルなのか曖昧なのだが、README読んだ感じだと、Railsの認証周りの文書を読んで、動きを理解してから使えよというぐらいかと。

Devise使うとIPアドレスが漏洩するか

User.attributes.to_jsonするとipアドレスが含まれるようだが、User.to_jsonでは含まれない。それ以前に、モデルクラスを何も加工せずにWeb APIのレスポンスとして出力する方が問題なので、DeviseではなくWeb API仕様・設計の問題だと思う。

再発防止策

noteが示している対策はそんなに悪くないのではという気がする。

対策
・全ソースコードに対して、IPアドレス及びそれ以外のセンシティブな情報が露出するような同様の欠陥がないことを調査し、さらに対応するデータベースからIPアドレスのデータを削除しました
・CEO・CTO直轄の特別対策チームを結成して、直接の対策と構造的な課題や開発体制までを含めた徹底的な見直しを行います
ソースコードのレビューおよびテストに今回の不具合や関連するセキュリティに対する観点を追加します
・データの持ち方やセンシティブな情報にアクセスするプロセスを見直します
・外部の複数の専門企業に依頼し、noteの脆弱性を発見・対策できるよう第三者の目線からの脆弱性診断をおこなってまいります

ただ、Web API仕様・設計のセキュリティ観点のレビューもした方が良いと思う。

SQLiteのロック

ロックの種類とかは以下の説明を読めばよいのだけども、RESERVEDやPENDINGなど特殊なロックがあるので、実際にどう実装しているのか気になった

www.sqlite.org

ソースコード読むに以下のような感じ。(src/{os.h,os_win.c,os_unix.c})

  • Windowsの場合はLockFileEx()やLockFile()を使う
    • NT系はLockFileExだが、非NT系(Windows 95/98/ME)はLockFileExがないのでLockFileを使う
      • LockFileは共有ロックが存在せず、常に排他ロックであるため、SHAREDロックを取得するためには、後述する510バイトのうちランダムに1バイトをロックするようにする。
        • そのため、95/98/MEでは運が悪いとSHAREDロックしか取られていないのにSHAREDロックを取れないはず
        • NT系と非NT系からアクセスがある場合は、非NT系がSHAREDロックを取ると、NT系はロックをとろうとする510バイトのうち1バイトがロックされているのでSHAREDロックを取れないし、NT系がSHAREDロックを取った場合も、非NT系は510バイトすべてロックされているので、SHAREDロックを取れない
        • まあ、今どきWin95/98/MEはほとんど使われていないと思うけども
  • UNIX系OSの場合はfcntl(fd, F_SETLK, ...)を使う
  • ロックするバイト範囲は実際のデータを書き込まない位置(0x40000000のあたり)を使う
    • PENDINGは0x40000000から1バイト
    • RESERVEDは0x40000001から1バイト
    • SHAREDとEXCLUSIVEは0x40000002から510バイト

ターミナルで文字化け

だいたい以下をチェックすれば直る気がする

  • ターミナルの文字コード設定
  • 環境変数LANG
    • コマンドが見るのは基本これ。コマンドのエラーメッセージなど
    • LANGとターミナルの文字コードを合わせればエラーメッセージなどは文字化けしない
    • sshするとログイン元の環境変数が引き継がれる場合があるので気をつける
    • utf-8のマシンからeuc-jpのマシンにログインしたが、LANGがja_JP.utf-8のままだったなど
  • screen
  • vim
    • vim -c ':e encoding=xxx'で開く
    • 開き直すときはコマンドモードで':e encoding=xxx'

mediamarkerからブクログに移行

だいぶ書いていなかったな。

mediamarkerが終了するということで、遅れながらブクログに移行してみた。

Excel等で編集して移行している人がいたのだが、面倒なので以下スクリプト使ってみた。

メディアマーカーの CSV をブクログ形式にするやつ · GitHub

たぶんこのままだとうまくいかない部分があったので、少し修正して以下のスクリプトを実行した。

mediamarkerから全項目をexport→スクリプトを実行→sjis文字コード変更→ブクログにimportするという流れ

#  -*- coding: utf-8 -*-
#
# メディアマーカーの CSV をブクログ形式にするやつ
# 使い方
#   ruby mm2bl.rb /path/to/MediaMarkerExport.csv > output.csv
# 参考
#   http://d.hatena.ne.jp/Unicellular/20120507/1336411135

require 'csv'

path = ARGV.shift
raise SystemExit.new 1 unless File.exists? path

lines = CSV.read(path)
lines.shift
lines = lines.map do |l| 
  # 今のmediamarkerの全出力は項目が多くなっているので修正。
  # また購入日を登録日に入れていたので、登録日を利用するように修正
  _, _, _, _, category, _, _, _, _, isbn, _, _, asin, register_date, _, tag, comment, assess, _, _, _, _, _, state, read_date, _, _ = *l

  servece_id = 1 
  state = case state
          when '未読' then '積読'
          when '読中' then 'いま読んでる'
          when '読了' then '読み終わった'
          else            '読みたい'
          end 
  memo = ''
  # タグはmediamarkerでは改行だが、ブクログではカンマ
  tag = tag.split(/[\r\n]+/).join(",")
  # タグが空だと自動的に何らかの日時がタグに入ってしまうようだ。空の場合はタグにして、管理画面から削除する
  tag = "タグ" if tag.empty?
  # read_dateは年-月-日形式だったので統一した。不要だったかも。
  register_date = register_date.gsub(%r|^(\d{4})/(\d{2})/(\d{2}).*$|, '\1-\2-\3')
  [servece_id, asin, isbn, category, assess, state, comment, tag, memo, register_date, read_date]
end

# 文字コード変換は実施せずに、nkf等で実施する
puts lines.map { |l| '"' + l.map { |w| w.to_s.gsub(/"/, '\"') }.join('","') + '"' }.join("\n")