セキュリティキャンプ2022の経緯と選考課題
セキュリティキャンプとは
公式によると「セキュリティ・キャンプとは、日本における将来の高度 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/jinzai/security-camp/2022/zenkoku/qv6pgp0000002518-att/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
のリンクを掲示板などで配布するだけで、そのリンクを踏んだユーザーは意図しない投稿をしてしまうことになる。
これは、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
の
の部分をコメントアウトするとエラーが発生して通信が送れないようになる。これは、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-site
やsame-origin
などの値が割り当てられる。また、Sec-Fetch-Dest
はimage
やscript
などの値をとり、どのような文脈でそのリクエストが呼ばれたのかが分かる。
これらを使うことで、例えば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 リクエストにセキュリティトークンが自動的に含まれ」るらしい。
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」の箇所を読むと、link
やa
タグといった要素には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 プロパティもリンク先に渡さない設定だった。
使い分けに関して、noreferer
はnoopenner
を包含して、サポートされているブラウザの数も多いため、つけるとしたら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 では、これらの認証基盤を提供して、署名・検証を容易にする。
開発者が署名をする手間や鍵を管理する手間を減らし、ユーザー側の検証の手間も減らすことで、署名・検証の普及率を上昇させ、サプライチェーン全体のセキュリティリスクを減らそうとしている。