セキュリティキャンプとは

公式によると「セキュリティ・キャンプとは、日本における将来の高度IT人材となり得る優れた人材の発掘と育成を目的とした独立行政法人情報処理推進機構(IPA)の事業の一つ」とのことです。 参加者目線でいうと、無料で一流の講師からセキュリティ関連の技術やセキュリティを学ぶための基礎になる技術を学ぶ機会を得られる場です。また、おなじような分野に興味がある同年代の人たちと会える場でもあります。一方で、将来的には学んだ技術を社会に役立てることが求められもします。 講師やテーマは毎回変わりますが、今年度は以下のような講座がありました。

専門コース

  • IoTセキュリティクラス
  • Webセキュリティクラス
  • 脅威解析クラス
  • AIセキュリティクラス

開発コース

  • 暗号解読チャレンジゼミ
  • 暗号のままで計算しようゼミ
  • Cコンパイラゼミ
  • 分散型アプリケーション脆弱性解析ゼミ
  • リバースエンジニアリングゼミ
  • 電子回路・プリント基板を作ろうゼミ
  • ハードウェア魔改造ゼミ
  • 無線通信ハッキングゼミ
  • OS自作ゼミ
  • データベースゼミ
  • 故障を乗り越えて動くシステムのための分散合意ゼミ
  • RISC-V CPU自作ゼミ
  • BGPを実装して学ぶIPルーティング / ネットワークを自動制御して学ぶSDNゼミ
  • マルウェアサンドボックス強化ゼミ
  • WordPressから学ぶ不正アクセスの検知と対策ゼミ
  • ファイルレスマルウェアの仕組みと検知エンジンの開発ゼミ

それぞれの詳しい説明は公式ページを参照してください。 参加者は、上記のうち一つに所属し、事前学習と、 8 月にある 5 日間の講義に参加することになります。なお、今年度はオンラインで開催されました。

知ったきっかけと応募した経緯

セキュリティキャンプの名前自体は、なんかの記事を読んで知っていました。5 月ごろに技術系の記事を集めた RSS で、セキュリティキャンプ募集の記事をみて、応募期間だということを知りました。たしか、公式のセキュリティキャンプブログの記事だった気がします。 内容をみて webセキュリティクラスの講義内容に興味をもちました。そこで課題を確認したところ、課題もある程度書けそうだと思いました。他にもデータベースゼミなども面白そうだと思って見ていました。

選考課題を解いた感想

選考課題は、必答問題 3 問と選択問題 5 問で構成されていました。必答問題は、いままでの経験やモチベーションなどを答えるものです。選択問題は知識や調査結果を答えるもので、3問以上の回答が求められました。

選考課題からも学べる

選考課題を解いたあとに得た感想として、問題文の構成がとてもよいと感じました。参考にするページが問題文で示されていたため、事前知識が少なくても適切な資料を参照することが可能でした。さらにいえば、どの資料を参考にするべきかという情報を得られたので、選考課題を終えた時点で得られるものがあったと感じました。

例として、Q4 で CSRF について答えたときをあげます。問題文には「現代の Web ブラウザ・Web アプリケーションフレームワークが備える仕組みを深く考慮しながら」とあります。 自分はセキュリティといえば、開発者がどのようにコードを書くかが焦点だと思っていました。そのため、Web ブラウザの仕組みへの誘導文から、セキュリティの文脈でブラウザが果たす役割があることに気づくことができました。 そして、Q6 で HTML Living Standard が紹介されていたことで、ブラウザの仕様書ともいうべき HTML Living Standard や RFC を意識しながら解答することができました。

おそらく、選考課題を通じた学習は主催者側も意識されていて、「選考終了にあたり、竹迫講師主査から次回のセキュリティ・キャンプ全国大会を目指す方へのメッセージ」 には、「応募課題に取り組んでみた姿勢、正解にたどり着くまでのプロセスは今後も非常に役に立つと思います。」と書かれています。このメッセージは、来年以降セキュリティキャンプに応募する人は、課題を解く前に一読すると、主催者側がどのように問題に答えてほしいかのイメージがつかめると思います。

レベル感

選考課題を解き始めた時点では、セキュリティ関係の知識がほとんどない状態からのスタートでした。具体的には、CSRF がなにかもよくわかっていないような状態です。なので、自分の知識に自信がなくても、興味をもった講義には、気軽に応募してみるとよいと思います。

選考課題の公開

セキュリティキャンプは、選考課題の解答を公開する文化があるらしいです。応募中はそのことを知らず、自分がお世話になる機会はありませんでしたが、来年度以降活用してくれる人がいるかもしれないので公開しておきます。ようするに、これがこの記事を書いた目的です。

↓課題文 https://www.ipa.go.jp/files/000097399.txt

誤字脱字等は修正せずに公開します。

Q1(応募のモチベーションについて)

「Webセキュリティクラス」の講義のうち、特に受講したいと思う講義(複数可)に関して、その講義で「どのようなことを・なぜ学びたいか」を教えてください。とりわけ「なぜ学びたいか」の部分に関連して、いま応募を考えているあなたが感じておられる課題意識や、あなたの関心領域が伝わってくるような解答を歓迎します。

解答 特に、「B1 作って学ぶ、ウェブブラウザ」に興味があります。 私がプログラミングを始めたのは2年前で、ウェブアプリの領域では、既に充実した開発基盤が整備されている時期でした。 たとえば、ウェブアプリを開発しているときに、ウェブブラウザの検証画面を見れば、なんらかのエラーが表示されていたりして、エラー文をそのままググるとよくわからないコードが出てきて、それをコピペすると動くようになることが多いです。たとえば、なんらかの機能を開発しようとする前に、ライブラリがないか調べると誰かが開発したものが既に配布されていて、適当にコマンドをたたいてインストールすれば開発が終了します。たとえば、アプリを公開しようとしてホスティングサービスを調べると、GUIをポチポチと押しているだけで公開が完了します。 このような充実した開発環境が整っているのは素晴らしいことですが、「よくわからないけど適当にやったらできただけ」という感覚がありました。この感覚は、「自分は誰かが開発したツールをありがたく使わせてもらっているだけだ」という充足感の無さと、「もし何かがあったとしても十分な対応ができないだろう」という不安感に繋がりました。 私自身の課題意識は上記の二点です。そのため、まずは普段使っているものがどのような仕組みで成り立っているのか知りたいというモチベーションが高いです。 そのような点からいうと、「B5,B7 ソフトウェアサプライチェーンセキュリティのこれから」や「B6 実践Linux実行基盤セキュリティ」にも興味があります。Linux実行基盤は現在利用しており、ソフトウェアサプライチェーンは私がべったりと依存しているものだからです。 また、「B2 マイクロサービス/分散モノリス的アーキテクチャへの攻撃手法」や、「B4 モダンな開発環境のセキュリティおよびCI/CDパイプラインのセキュア化」などにも強い興味があります。これらは、大規模サービスや組織的な開発向けだと思っているため、まだ個人で使用したことはないですが、将来的によく使うものになるだろうと思うからです。 それらの中から、特に関心がある講義として、「B1 作って学ぶ、ウェブブラウザ」やを選んだのは、この課題でCSRFのことを調べていく中でブラウザが果たす役割に興味をもったからです。正直な話、この課題をやるまでCSRFは名前を聞いたことがあるくらいで、CORSのエラーが出てもとりあえずアクセスを全許可していました。CSRFの対策を調べている中で、開発者が独自に対策をしていくだけでなく、HTTPの仕様などとも連携しながら対策をしていることを知りました。そして、ブラウザがどのように実装されているかを知ることがCSRF対策をするうえで重要だと感じて、ブラウザへの興味が高まりました。

Q.2(これまでの経験について)

以下の経験について、差し支えのない範囲でできるだけ具体的に教えてください: なお、この問は「この応募課題を提出する時点での経験」を問うものです。この応募課題を見た時点での経験はなくても構いませんし、この応募課題の記入にあわせての学習を歓迎します。

(1) Web アプリケーションの設計・開発経験(※ どんな些細なものでも構いません)

解答 省略。500 字程度で、サークルやバイト、個人で開発したことを記述。

(2) 一般のプログラミングの経験(※ 使ったことのある言語や、その用途などを教えてください。レイヤは問いません)

解答

  • Typescript/nodejs.web開発(nuxtjs,nextjs,expressjsなど)
  • ruby.web開発(Ruby on Rails)
  • nginx.サーバー管理
  • bash.サーバー管理
  • dovecot/postfix.メールサーバー管理

(3) コンテナ技術の利用経験

解答 個人的にdockerを試してみたことがある程度 自分で作ったアプリをdocker環境に移植してみる程度はしたため、基本的なdockerfileやdocker-compose.ymlは書ける

(4) CI/CD 環境のセットアップ・利用経験

自分でセットアップした経験はなし 他人がセットアップしたものを利用した経験はあり

Q.3(あなたの感心・興味について)

Web に関連するサービス・プロダクトを作って提供することに関連する技術で、いまあなたが興味を持っているものがあれば、それについて自由に説明してください。少しでも Web との関連性がある技術であれば、それがハードウェア領域に近いものでも、ソフトウェア領域に近いものでも構いません。 解答 800 字程度の記述。DevOps に興味があることと、開発全体のことを把握するために低レイヤまで含めて全体的な技術について学びたいという旨を、そう思うようになった自分の体験を交えて書いた。

Q.4(Web に関する脆弱性・攻撃技術の検証 1)

Cross-Site Request Forgery (CSRF) とは何か、現代の Web ブラウザ・Web アプリケーションフレームワークが備える仕組みを深く考慮しながら、自分の言葉で説明してください。なお、関連する仕様や実際の実装例の挙動を論拠にする場合は、ぜひその出典を明記してください。 解答

CSRFとは

CSRFが何かということについて、概要、具体的な手法、対応策を紹介する。

概要

CSRFとは、攻撃者が利用者になりすました形でサーバーの副作用を伴う処理を悪用する攻撃のこと。 大まかなシナリオとしては、以下のようなものになる。 まず、ユーザーが攻撃者によって設置されたサイトを訪問する。すると、利用者のブラウザからCSRF脆弱性があるサイトやAPIにリクエストが投げられる。子のリクエストは、利用者が自分で操作しなくても投げられてしまう。 リクエストは利用者のブラウザから投げられるため、利用者のIPアドレスからCookieが付与された状態で投げられる。攻撃を受けたサーバーからは、利用者が意図して投げたリクエストかどうかがわからないため、攻撃者が利用者になりすました形でサーバーの副作用を伴う処理を悪用できてしまう。

主にCookieを利用したセッション管理が行われているサイトでの、意図しない投稿やパスワード変更などの文脈で語られる。ただし、神奈川県警の誤認逮捕事件で知られるパソコン遠隔操作事件など、Cookieを用いていないサイトでもとでも被害は発生する。

具体的な手法

原理的に考えられる最もシンプルな例を紹介し、だんだんと要素を付け足していく紹介形式をとる。 なお、実際に挙動を確かめた実装を以下から確認できる。 https://github.com/sasakiy84/CSRF-testing

Cookieを用いない場合(GET通信)

最も単純な手法。フォームの送信先などに指定されているURLをたたくことだけを考えればいい。 たとえば、特定のクエリ文字列をつけて叩くとその内容を投稿するというエンドポイントがあったとする。単純化のためにメソッドはGETでよいとする。 この場合、攻撃者が以下のようなHTMLを含むhttps://evil.com/index.htmlのリンクを掲示板などで配布するだけで、そのリンクを踏んだユーザーは意図しない投稿をしてしまうことになる。

<img src="https://example.com/post?message=fuxkyou">

これは、CSRFの最も単純なかたちである。なお、挙動の確認を以下のURLから確認可能。 http://localhost:3000/1-get.html

もし認証もせず、HTTPメソッドの区別がついておらず、GET通信で副作用を伴うような処理を実装しているエンドポイントがあれば、この攻撃は成立してしまうだろう。実際、GET通信でDBのバッチ処理を行う実装(認証無し)を個人的に見たことがあるし、GET通信でシステムの初期化を行っていたシステムもあるらしい https://qiita.com/HirotoKagotani/items/181052eb85b686783806

Cookieを用いない場合(POST通信)

副作用を伴う処理の多くはPOSTメソッドを使って実装される。そのため、後述するように、特定の条件ではブラウザレベルでCSRFの対策がとられている点がGET通信と異なる。

前節でみたimgタグのsrc属性を使った方法では、POST通信を行うことができない。POST通信の投げ方としては、主にjavascriptのXMLHttpRequestオブジェクトを使った方法とHTMLのフォームを用いた方法などがある。ここでは、HTMLのフォームを用いた方法を見る。

HTMLのフォームは、document.forms[0].submit()などを実行することでユーザーがボタンを押さなくても送信可能である。また、送信先も自由に指定できるため、ブラウザにアクセスした時点でPOSTリクエストを意図しない場所に投げさせることが可能である。 実際の挙動を以下のURLから確認できる。なお、コードは「体系的に学ぶ 安全なウェブアプリケーションの作り方 第二版」のCSRFの項を参考にした http://localhost:3000/2-post.html

この例ではパスワードが攻撃者の設定した文字列で初期化されてしまう。実際には、パスワードの変更などはセッションの確認などをするだろうが、ご意見箱のような匿名の公開されているフォームでは、検証などをしていない可能性もある。(cf. 神奈川県警の誤認逮捕事件で知られるパソコン遠隔操作事件)

Cookieを用いる場合

次に、Cookieを用いる場合を考える。Cookieはログインしていることを証明するセッション情報の管理などに使われ、ブラウザからサーバーへのリクエスト時に送信される。

Cookieを用いる場合(FORM)

たとえばhttp://127.0.0.1:4000/loginというURLをたたくとログインができ、http://127.0.0.1:4000/reset-password-with-cookieというURLをたたくと、SessionIdのCookieを検証してからパスワードを変更するシステムがあったとする。 このとき、Cookieを用いない場合と同じような攻撃者のページhttp://localhost:3000/3-cookie.htmlがあったとすると、訪れた被害者がシステムにログインしていなかった場合は、passward resetting failedというログが流れるだろう。 しかし、http://127.0.0.1:4000/loginを訪れて、ログインした状態(Cookieにsessionid=loginedがセットされている状態)で再び攻撃者のサイトを訪れると、パスワードリセットが成功してしまう。 つまり、ほかの対策を何もしていない状態では、「ユーザーがたまたま攻撃対象のシステムにログインしている」という条件が成立していればCookieを用いない場合と同じように攻撃が成功してしまうのだ。

なお、Cookieの送信先は、端的にはcookieのdomain属性とpath属性を、送信先のURLと比較して、条件に合致した場合に送信される。そのため、送信元が本物のサイトだろうと攻撃者のサイトだろうと関係がない https://httpwg.org/specs/rfc6265.html#rfc.section.4.1.2.3

Cookieを用いる場合(XMLHttpObject)

次に、XMLHttpObjectを使った方法を見ていく。javascriptを用いてPOST通信などができるもので、実際の例は以下から確認できる http://localhost:3000/4-cookie-xhr.html

基本的には、フォームで投げる通信を再現すればできる。なお、実装方法については、「体系的に学ぶ 安全なウェブアプリケーションの作り方 第二版」のCSRFの項を参考にした。

なお、server.js

api.register(fastifyCors, {
  origin: "http://localhost:3000",
  credentials: true,
});

の部分をコメントアウトするとエラーが発生して通信が送れないようになる。これは、CORSリクエストに対してAccess-Allow-*ヘッダを返す処理であり、CORSの挙動を試すことができる。

対策方法

今までで、CSRFがどのように行われているのかを見てきた。次に上記で紹介したようなCSRFを防ぐ仕組みにどのようなものがあるか、どのように実施されているか、あるいはどのように実施するべきかを見ていく。

そもそもとして

CSRFが成功してしまう要因として、以下の条件がある

  • リクエストを受け取る側から送信元の検証ができない
  • 送信元がどこでも好きなようにリクエストを送ることができてしまう

以上の点を踏まえて、現在提唱されている対策が、どちらの条件について対策しているのか、という点に気を付けながら見ていく。

同一オリジンポリシーについて

具体的な対策を説明する前に、前提知識として同一オリジンポリシーとCORSを説明する。

まず、同一オリジンポリシーとは、コンテンツをやり取りする際に、セキュリティの観点から、異なるオリジン間でのやりとりに制限をかけるというポリシーのこと。 https://www.w3.org/Security/wiki/Same_Origin_Policy

オリジンとは、スキーマとホスト、ポートで定義される部分のこと。 https://datatracker.ietf.org/doc/html/rfc6454#section-4

このポリシーがあるため、異なるオリジンからの画像ファイル読み込みなどは、原則として許可されない。 ただし、以下で説明するようなCORSを使った許可を与えればコンテンツの共有が可能となる。 注意したいのは、レスポンスが見れないだけであり、リクエストはサーバー側に届いて処理が実行されているということ。そのため、CSRFの文脈では、同一オリジンポリシーだけでは意味をなさない。

CORSについて

同一オリジンポリシーがあるとコンテンツの共有ができないため、その権限をHTTPヘッダで適切に付与する仕組み。 特に、CSRFの文脈では、プリフライトリクエストが重要となる。 前述のとおり、同一オリジンポリシーではリクエストの結果が閲覧されることは防げても、リクエストが送られること自体は阻止できない。これに対して、CORSが実装されているブラウザでは、特定のリクエストを送信するまえに、プリフライトリクエストという、サーバー側に本物のリクエストを送ってもいいかお伺いをたてるリクエストをOPTIONSメソッドで自動送信する。 プリフライトリクエストが送信される「特定のリクエスト」とは、例えば独自ヘッダが付与されたものPOSTリクエストなどだ。 これにより、サーバー側は、プリフライトリクエストについているオリジンヘッダを検証し、送信元を確かめることが可能になる。

Refererを見る

これは、「リクエストを受け取る側から送信元の検証ができない」という条件について対策したものである。 HTTPヘッダの一つに、「現在リクエストされているページへのリンク先を持った直前のウェブページのアドレス」が含まれたRefererというヘッダがある。 https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Referer

このヘッダを検証することで、自分のサイトからのリクエストかどうかを検証可能だ。 だが、Refererは直前まで閲覧していたサイトが分かるということから、プライバシーや情報漏洩などの問題が指摘され、拡張機能などを使って無効にしているユーザーもいる。RefererのRFCでも、全てのリクエストにRefererが含まれるわけではないと書いているため、これを検証用に使うことは推奨されないだろう。 https://datatracker.ietf.org/doc/html/rfc7231#section-5.5.2

originを見る

これは、「リクエストを受け取る側から送信元の検証ができない」という条件について対策したものである。 Refererヘッダのバリエーションであるオリジンヘッダを検証に使うという方法。 こちらは、CORSの基準に引っかかる(つまりクロスオリジンのリクエスト)か、POST通信のときにoriginが送られるため、そのoriginを検証すればよい。 ただし、以下のような問題点が挙げられている。 一つ目は、「valid な値が推測可能なため、もしブラウザからのリクエストに 任意のヘッダを追加できる脆弱性 が別で存在した場合には、簡単に偽装できてしまう。」という点だ。実際にそのような脆弱性が発見されたこともあるらしい。 https://blog.jxck.io/entries/2018-10-26/same-site-cookie.html

ふたつ目はoriginが信頼できる情報ではない場合だ。サーバー側が自分のoriginを知らない場合や、ユーザーが想定したoriginと違うoriginでアクセスしている場合があるらしい。これに関しては、あまり想像がつかず、理解が曖昧。 http://var.blog.jp/archives/86138542.html

独自ヘッダを入れる

これは、「リクエストを受け取る側から送信元の検証ができない」という条件について対策したものである。 HTTPヘッダにX-Requested-With: XMLHttpRequestのようなヘッダを入れて、サーバー側では指定されてた独自ヘッダがリクエストに含まれているかを確認する方法だ。 前提として、以下の二つがある。

  • フォーム送信では余分なリクエストヘッダを入れることができない
  • XMLHttpRequestなどのjavascriptの機能を用いたリクエストでは、独自ヘッダも付与可能だが、CORSがあるため、そのリクエストを受け取るかどうかをサーバー側で制御可能

一点目により、これは単純なフォーム送信では使えない。フォームを使う場合もjavascriptを用いた通信が必要だ。 二点目に関して簡単に言えば、攻撃者のサイトから独自ヘッダがついたリクエストが送信された場合、許可されていない送信元の場合はリクエストを受け取る前に拒否することが可能ということだ。

メタデータヘッダを見る

これは、「リクエストを受け取る側から送信元の検証ができない」という条件について対策したものである。 ブラウザが自動で付与するSecから始まる4種類のヘッダを検証することで、そのリクエストが行われた状況に沿った対応を行うことができる。たとえば、Sec-Fetch-Siteヘッダでは、送信元と送信先の関係によって、cross-sitesame-originなどの値が割り当てられる。また、Sec-Fetch-Destimagescriptなどの値をとり、どのような文脈でそのリクエストが呼ばれたのかが分かる。 これらを使うことで、例えばSec-Fetch-Dest=imageなのに画像を返さないAPIが呼ばれているから怪しい、というような判断ができるようになる。

なお、2022/05/22現在では、safariにおいてサポートされていない。 https://caniuse.com/?search=Sec-Fetch

W3Cのドラフトには入っているため、Safariでサポートされたら使えるようになるだろう。 https://w3c.github.io/webappsec-fetch-metadata/#framework

トークンを利用する方法

これは、「リクエストを受け取る側から送信元の検証ができない」という条件について対策したものである。 具体的な実装としては、トークンをサーバー側とクライアント側に分けて保存する方法だ。 フォームページを発行する際に、トークンを生成し、それをサーバー側のセッション情報に追加して、フォームのinput要素にも格納する。フォームが送られてきたら、その二つを検証する。攻撃者の視点に立った場合、フォームに埋め込まれたトークンは、同一オリジンポリシーにより確認することができないため、検証を突破できない。 デメリットとしては、セッション情報を使ってしまうためステートフルになってしまう点がある。つまり、これはログイン機能を使う場合に有効な対策であり、ログイン不要の掲示板やコメントフォームでは実施することができない。 また、SPAではフォームに直接トークンを埋め込むのが難しいという点がある。 後者については、後述する。

Cookieの二重送信

これは、「リクエストを受け取る側から送信元の検証ができない」という条件について対策したものである。 具体的には、トークンをクライアント側に2つとも保存する方法だ。 概要としては、一つ目と同じように、クライアント側に送信したフォームにランダムなトークンを埋め込む。またCookieにも同じトークンをセットする。すると、Cookieに保存されたトークンとともに、フォーム送信時にそのトークンがサーバー側に送られ、両者を突き合わせて検証できる。 一方で、攻撃者が作ったサイトからの送信では、Cookieのトークンは送ることができても、フォームの中身のトークンは知ることができない。Cookieには、httpOnly属性をつけておくことで、javascriptから操作することができなくなるので、Cookieのトークンをフォームデータにコピーすることもできない。 さらに、攻撃者側が生成したトークンをフォームとCookieから送信するという方法も考えられるが、Cookieはブラウザから異なるドメインに設定できない。 https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie#write_a_new_cookie

サーバー側では、送られてきた2つのトークンを検証することで、攻撃者のサイトからではなく、自分自身のサイトから送信されてきたリクエストであるとわかる。一方で、もしトークンの検証に失敗すれば、有効なトークンを知らない第三者からのリクエストであるとわかる。

なお、この方法はリスクが大きい。 たとえば、サブドメインのCookieも送信されるため、レンタルサーバーなどでより上位のドメインを他者と共有している場合にCookieの汚染が可能である。あるいは、HTTPヘッダインジェクションの脆弱性があった場合に検証を突破される点などが挙げられる。 https://blog.tokumaru.org/2018/11/csrf_26.html

サブドメインなどに対しては、HOST prefixをブラウザがサポートするようになれば解決するだろうが現在ではまだ実用はできない。 https://datatracker.ietf.org/doc/html/draft-west-cookie-prefixes-05#section-3.2

Cookieを保護する方法

これは、「送信元がどこでも好きなようにリクエストを送ることができてしまう」という問題への対処である。 この手法では、Cookieの送信に制限をかけることで、「好きなように」リクエストを投げることができないようにする。これによって、攻撃者のサイトからsessionidなどのcookieを盗用することができなくなり、ログイン状態の検証が信頼できるものになる。

具体的には、デフォルトでは送信元と送信先のドメインが異なる場合にも自動で付与されるcookieに、ドメインが異なる場合に送信しないという設定を加える。 以上のことを行えるようにしたのが、SameSite属性である。SameSite=Laxという属性を設定すると、異なるドメイン間での通信の際に、Top Level Navigation以外はCookieを送らないようにできる。 つまり、aタグを使ったリンク遷移などのときは従来通りCookieが送られるが、フォームやXMLHttpRequestなどでPOSTをする場合は、この属性がついたCookieは送られない。 なお、<link rel='prerender'>などを使ったときには送信されるようだが、副作用のある処理をGETで実行しないようにすれば問題はないはずだ。 https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-05#section-5.3.7.1

LaxのほかにStrictという、より安全な設定がある。こちらは、いかなる場合でも異なるドメイン間でのcookie送信を許可しないというものだが、ほかのページからの遷移時などにログイン状態が継続されないという問題がある。たとえば、PCのブラウザ上で、Twitterで共有するボタンを押したあとにTwitter画面に遷移しても、Cookieが送信されないため、共有する度にログインが必要になる、などが想定される。 そのため、Laxを使うか、副作用がない処理のための読み取り専用Cookieと、副作用がある処理のための書き込み用Cookieを分けて、前者にはLax、後者にはStrictをつける方法などが考えられる。 参考

ただし、これはCookieを使う場合に有効な対策であり、ログイン不要の掲示板やコメントフォームでは実施することができない。

フレームワークでの対応例

フレームワークによっては、CSRF対策をデフォルトで行っているものもある。

Ruby on Rails

Railsではコントローラーに以下のコードを追加することで、「Railsで生成されるすべてのフォームとAjaxリクエストにセキュリティトークンが自動的に含まれ」るらしい。

protect_from_forgery with: :exception

https://railsguides.jp/security.html#csrf%E3%81%B8%E3%81%AE%E5%AF%BE%E5%BF%9C%E7%AD%96

Laravel

Railsと同じようにトークン管理によるCSRF防御を実装している https://readouble.com/laravel/8.x/ja/csrf.html

SPA

UIライブラリなどが流行って、バックエンドとフロントエンド両方の責任を担うようなフレームワークの利用は減ってきている。今までフルスタックフレームワークとして使われていたものがAPIのみの用途で使われ、フロントは表現力の高いreactやvueなどのSPAが担うようになってきた。 フルスタックフレームワークではフォーム等に文字を埋め込んだ結果を返すことは簡単だったが、フロントとバックが分離するとそれも難しくなる。 代替案の一つとして、APIを使ってCSRFトークンを発行するという手法がある。フォームに埋め込まれたトークンは攻撃者のサイトから予測できず取得もできないというのが重要であった。APIでも同一オリジンポリシーにより攻撃者はトークンを取得できないため、同じ役割を果たすことが可能である。

Q.5(Web に関連する脆弱性・攻撃技術の検証 2)

「Top 10 web hacking techniques of 2021」(https://portswigger.net/research/top-10-web-hacking-techniques-of-2021) は、Web に関するセキュリティリサーチャーの投票により作成された、2021 年に報告された興味深い Web に関する攻撃テクニック 10 選です。この Top 10 中の事例の中で、興味を持てたもの 1 つに関して、以下を説明してください。 (1) 事例の概要 (2) 攻撃手法の詳細 (3) その他その事例に関して感じたこと・気がついたこと なお、本設問では、関連する仕様や攻撃の適用可能な条件についての詳細な理解が垣間見えるような記述や、理解を深めるために行ったこと(例: ローカルで行った再現実験等)に関する記述を歓迎します。

解答 「1 - Dependency Confusion」を選んだ

(1)事例の概要

ライブラリリポジトリのプライベートリポジトリとパブリックリポジトリの違いを利用した攻撃。 この攻撃によって、本物のライブラリの代わりに攻撃者が作ったライブラリをインストールさせ、コードを実行させることができる。 特にプライベートリポジトリを持つような大規模な企業が対象のため、影響が大きい。

(2)攻撃手法の詳細

攻撃の手順は以下の通り。 まず、攻撃対象が使っていそうなプライベートライブラリの名前を推測、あるいは入手する。たとえば、javascriptで用いられているライブラリの名前はクライアントサイドに送信されるため、取得が容易である。 次に、判明したプライベートライブラリと同名のライブラリをパブリックリポジトリにアップロードする。この際、バージョンを高く設定しておく。 攻撃対象がそのパッケージをインストールする際に、プライベートリポジトリよりパブリックリポジトリのライブラリが優先され、攻撃者が設定したコードが実行される。ライブラリマネージャーによっては、インストール時の処理を記述できるものなどがあるので、スクリプトの実行にそれを利用することもできる。

これは、ライブラリマネージャーがライブラリをインストールする際に、プライベートリポジトリとパブリックリポジトリで同名のライブラリがあった場合の挙動によるものである。 ライブラリマネージャーによっては、同名のライブラリが存在する場合、プライベートリポジトリのライブラリが必ず優先されるのではなく、両者のバージョンを比較して、より新しいほうのライブラリをインストールするというメカニズムになっているものがあり、その場合にこの攻撃が成功してしまう。

node系のライブラリだけでなく、rubyやpython系のライブラリでも実行可能な攻撃である。

(3)その他その事例に関して感じたこと・気がついたこと

npmのprivate registryをOSSで提供するverdaccioにおいて、攻撃が実行可能かを調べてみた。 まず、issueでdependency confusionと検索すると、以下のissueが見つかり、攻撃可能であるらしいことが分かった。 https://github.com/verdaccio/verdaccio/issues/2103

実際にどのようにダウンロードされるのかを見てみるために、ソースコードを確認すると、'/:package/:version?'で呼ばれるエンドポイントの中で実行される、mergeVersionsという関数を見つけた。 https://github.dev/verdaccio/verdaccio/blob/b8554c89353766f67221ff86e429c7a6e44a68ac/packages/api/src/package.ts#L38 https://github.dev/verdaccio/verdaccio/blob/13310814da60e7f9113347f1ab5529dcc10fd80d/packages/core/core/src/pkg-utils.ts#L46

ここでは、copy new versions to a cacheと説明される処理が書いてあり、実際に入手可能なパッケージのバージョンを比較して、リモートリポジトリに新しいバージョンがあれば、それをキャッシュしているようだった。ただ、このエンドポイントはパッケージの情報を返すだけのエンドポイントのようで、その情報がダウンロードでどのように使われているかを見つけることはできなかった。

Q.6(Web に関連する標準や実装の調査)

HTML Living Standard (https://html.spec.whatwg.org/) にはセキュリティに関する記述が各所に存在しています。同 Living Standard を読み、気になったセキュリティに関する記述について調査し、以下の 4 点について簡潔にまとめてください: (1) その記述の概要 ※ 例: 仕様の〜の箇所を読むと、〜には〜というような制限があることが分かった。詳細に述べると、これは〜という条件のもと、〜を〜として解釈するという仕様である。

(2) 気になった理由 ※ 例: この仕様は直感的にはなくても問題ないように思えるが、あえてこのような制限があるからには、意図があるはずである。その意図が気になった。

(3) その記述に関連して調査したこととその結果 ※ 例: PoC を書いて実際にブラウザでロードしてみた結果、〜という挙動だった ※ 例: 仕様にはこう書いてあるが、挙動がそれと異なる。実際 Chromium の実装を確認すると、〜となっていた。 ※ 例: 関連する Issue が https://github.com/whatwg/html に挙げられていた。ここでは〜という議論が行われていた。

(4) その他気がついたこと・思ったこと ・疑問・感想 ※ 例: この仕様は一見不合理に見えたが、調査中に見つけた〜という仕様との兼ね合いを考えると、〜という理由から合理的であるように感じた。 ※ 例: 一方調査の過程で、〜という仕様との整合性が取れているのかは気になった。実際の実装を用いて確認してみると、この点に関しては、実装間で処理結果が異なる。

解答

(1)

仕様の「4.6.7 Link types」の箇所を読むと、linkaタグといった要素にはnoopener,noreferrerといった属性が設定可能であることが分かった。 https://html.spec.whatwg.org/#linkTypes

(2)

昔、target=_blankでリンクをつけるときは、noopener,noreferrer属性を付けたほうがセキュリティ的によいというのを聞いて、今まで何も考えずにつけていた。せっかく仕様書を読むので、今まで曖昧にしていたことを理解しようと思った。

(3)

noopenerは、リンク元のページのwindowオブジェクトをリンク先が受け取れないようにするというもの。昔のブラウザでは、遷移元のwindowオブジェクトを、window.openerで受け取ることができたらしい。target=_blankを使い新しいタブを開いた場合、リンク元のページのwindow.opener.locationなどを使って、フィッシングサイトなどへ誘導されるなどのリスクがあったらしい 。なお、現代のブラウザではtarget=_blankがついている場合は問答無用でnoopenerがつくらしい。 なお、以下のサイトを参考にした https://mathiasbynens.github.io/rel-noopener/

noreferrerは、noopenerの効果に加えて、もとのサイトのURLを格納するrefererプロパティもリンク先に渡さない設定だった。 使い分けに関して、noreferernoopennerを包含して、サポートされているブラウザの数も多いため、つけるとしたらnorefererでいいと思われる。 一方、アフェリエイトなどreferer情報を使う場合は、noreferrerではなく、noopenerだけがいいという場合もある。 ただ、前述のとおり、モダンブラウザでは自動でnoopenerがつくため、noopener属性が使われることはもうあまりないと思われる。

(4)

では、なぜwindow.openerなんて危ないものが作られたのかが気になった。見つけた活用事例の一つは、複雑なフォームをポップアップウィンドウで入力してもらい、それを本画面に反映させるという使い方で、例えば岡山県立図書館の検索画面において、「分類表から選ぶ」という部分で活用されていた。 http://oudan.libnet.pref.okayama.jp/gf/cgi/start-jp

Q.8(新しい領域に関する調査)

Sigstore プロジェクト (https://sigstore.dev) について、それがどのような課題を、概ねどのような方法で解決することを目指しているのかを簡潔に説明してください。可能であればそれに加えて、以下のような調査・吟味を行い、その結果について論じてください。詳細な解答を歓迎します。

(1) どのような技術的な仕組み・理論に裏付けられているのか (2) 実社会で実際に運用可能そうなものなのか

解答

sigstoreは、ソフトウェア開発におけるサプライチェーン攻撃への対策として構築されたもの。コードやビルドファイルへの署名・検証の方法は従来から存在していた。しかし、鍵の管理の大変さなどから、気軽に使えるものではなかった。sigstoreでは、これらの認証基盤を提供して、署名・検証を容易にする。 開発者が署名をする手間や鍵を管理する手間を減らし、ユーザー側の検証の手間も減らすことで、署名・検証の普及率を上昇させ、サプライチェーン全体のセキュリティリスクを減らそうとしている。