日本初開催JSConf!「JSConf JP 2019」参加レポート[後編:2日目]

2019年11月30日、12月1日の2日にわたり開催された、JSConf JP 2019。その模様をピックアップしてレポートします。後編の今回は2日目のレポートです。

「Webの自重」

はじめに、JxckさんのセッションWebの自重(じじゅう)を取り上げます。

画像

Jxckさんはまずこのセッションの背景から話を始めました。最初に、半年前に会長(古川さん)から、ブラウザの多様性が減っていることについて問題提起をしてほしいとの無茶ぶりがあったこと。これは重いテーマで30分ではとても話せないと考えて、ぎゅっと縮めたら「自重」の話になったと語ります。

Webとは何か?

はじめに、⁠Webとは何か?」という問いは避けて通れないと話しました。ティム・バーナーズ=リーが最初にハイパーメディアシステムを作ったころから考えると、いま我々が作ったり使ったりしているWebはその技術の延長だけで全部は説明できなくなっているとの認識を示します。

「Webはこうである」という仕様はRFCにもWHATWGにもないと言及し、仕様策定の場ではWebが何をするものか、何をしてはいけないかではなく、その提案が「今のWebのモデル上で正しく設計できるか」にフォーカスして議論されていると説明しました。そして互換性を壊さないか、新しく追加したときにセキュリティイシューにならないかに焦点があてられるそうです。また、仕様を考えるコアの人たちは、誰もユースケース自体を否定しようとはしません。

そのため、⁠我々は仕様ではなくユースケース自体をWebであると言っていると考えても、あながち間違いではない」と言います。

ブラウザが減ってしまう不安の正体

続けて、ブラウザが減ってしまうことへの不安について、Jxckさんは次のように見解を示しました。

「ユースケースは、みんな欲張りなので時代とともに増えていきます。Webのモデル上で実現できるのであれば、ユースケースが増えれば仕様も増えるのがHTML5以降のWebの流れです。そうしてユースケースがどんどん増えていき、我々はブラウザに実装しろと言います。実装しないとモダンブラウザと認められなくなるため、ブラウザベンダーは頑張ってキャッチアップしなければならないし、互換性も壊してはいけません。すごい無茶なことをやり続けていて、ブラウザは肥大化するしかありません。

もはや、ブラウザをゼロから作れません。メジャーブラウザーが4つあったとして、どれかが体力尽きて消えて、失われていく以外にはありません。EdgeがChromiumがベースになったことから分かったことは、問題なのはUIを持つブラウザの多様性ではなく、その下にあるブラウザエンジンの多様性がなくなることだったということです。

多様性が減っても作れば良いのですが、それが新しく作れないことのほうが問題だと思います。つまり、新規参入ができない、今あるものをなんとかかんとかメンテナンスして走り続けなくければなりません。体力がなくなった人から減っていくだけだとしたら、それはWebが自重で潰れてしまう、ということを意味するのではないかと思います。

だから漠然とした不安の正体はこちらだったのです」⁠Jxckさん)

Webを小さくするための方法

ではWebを小さくするためにどうすれば良いかについて、2つの方法を提示しました。

  1. 「ユースケースを減らし、仕様を減らす」こと。しかし、これは今のWebの流れからはできないと言います。
  2. 「仕様を低レイヤーに下げることで、ブラウザエンジンの責務を減らす」こと。この考え方が、もう動き出しています。

例えばborderのスタイルをいろいろ規定するのではなく、替わりにCanvasを用意して好きなように引くことにすれば、borderのスタイルの仕様策定は終わったと考えることができます。このようにユーズケースを分解して低レイヤー化することでワークするかもしれません。これがExtensible Webと言っていたものの本質的な部分ではないかと語ります。

仕様のレイヤーを下げることは、ユーザーランドで自分で実装するように、相対的にアプリに責務を移すことになります。これで、Webの仕様つまりブラウザエンジンが持つべき部分はある程度小さく保てる可能性があります。ただ、単に減らしてあとは自分でやってくださいだと困る場面があます。パフォーマンスやセキュリティの考え方も変わってきます。そういうプリミティブもAPIとして外に出してあげるブリッジを用意すれば、アプリ側が責務を担えると説明しました。

レイヤーをどこまで下げるか?

さらにJxckさんは、今はどこまで下げるのが良いのかをハイレイヤーからちょっとずつ下げながら探っている時期だと、続けました。

そもそも開発者は今のスタックに満足しているのかを考えてみようと言います。例として、ドキュメントから派生したユースケースの対極にあるものとしてゲームを取り上げ、ゲームをやるためには今のスタックは全然足りていないことを最近議論していると紹介しました。

また、ゲームに付随して、もっと下のレベルのデバイスのアクセスも対象になっています。およそWebでやると思っていなかったところまで下がってきていて、今本当に必要なのは、任意のデータ/バイナリーを任意のトランスポートで好きなように転送して、それがCanvasに展開できて、そしてこれらを好きな言語からコンパイルしたWASMを使って制御し、必要に応じでデバイスにアクセスすることです。そうすることで、コントローラーをつないでゲームができるようになります。

デバイスにアクセスするとなると、既存のモデルの上でユーザーが安全にアクセスできるようにするためにFeature Policyによる制御だったり、ユーザによるパーミッションなどが必要になることを指摘しました。

Jxckさんは、次のようにここまでの話をまとめました。

「最初はハイパーメディアとして始まったシステムが、Ajaxが発見された以降から、みんながアプリケーションを作るようになりました。その上でさらにゲームがしたいしデバイスにもアクセスしたい、みたいになっています。それぞれが全部互換性を保った状態で先に進んで行き、包含関係になっているのが今のWebの全体像なのではないかという気がしています。

もしWebがOSのレイヤーまで下がっていくとしたら、真ん中のところは使っても使わなくても良いです。DOMが使いにくければ、Canvasの上に自分でUI Toolkitを作って描画すればよいでしょう。

またJavaScriptが気に入らない場合は、好きな言語でコンパイルしてWASMを使うことができます。そうすれば、アプリケーション側に責務を委譲できます。その責務の一端をSDKやUI Toolkitで担保し、そのうえで自分がやりたいユースケースを実現できるかもしれません」⁠Jxckさん)

画像

Webの多様性問題の本質

そして多様性の問題の本質について、Jxckさんは次のようにまとめました。

  • Webが肥大化していて、⁠ブラウザエンジンを)新しくゼロから作ることができなくなってしまった
  • 今のようにユースケースを提案して仕様に落とすというやり方では、肥大化は続くので無視できない問題
  • (ブラウザエンジンの)レイヤーを下げることで、責務をアプリに移せば緩和する、ということを今のWebはやっている
  • それによってWebはWebではなくなるのかというと、そんなことはない。今までのWebの使い方もできる、互換を保っているのも重要なところ
  • 低レイヤーの上で(アプリが)自分でやるというのが、この肥大化を止めるカギになる

最後に、この真ん中のSDKはだれが作るのか、あったらどうなるのかについて、Jxckさんの想像する可能性を語りました。

「例えばFlutterはUnityみたいなことをやろうとしているらしいです。

自分でUI Kitを作って、全部のプラットフォームに展開するので、どこでも同じようにみえる。それが最近Webでも使えるようになりました。もしそういったSDKが本当にワークするなら、WebTransport、Canvas、WASMがあって、OSのデバイスマネージメントの橋渡しだけをするブラウザだったら、今から作れるのではないか、という気がしませんか?

OSがあってSDKがあってどんなユースケースも展開できるのなら、既存のスタックで作られたWebをここで展開することもできる。ならばブラウザをWASMにしてこの上で動かす、なんてこともできるのではないか? そういう世界もあるのではないかと考えると、Webを小さくするヒントはそこにありそうです。そんなことを考えると楽しいですよね」⁠Jxckさん)

そう言ってJxckさんは発表を締めくくりました。

「Analysis of an exploited npm package」

Jarrod OversonさんのセッションAnalysis of an exploited npm packageでは、npmパッケージに仕掛けらた攻撃について、詳細な分析を紹介しました発表スライド⁠。

サプライチェーンアタックとは

Jarrodさんはまずサプライチェーンアタックについて、次のように説明しました。

「我々はアプリケーションを作るときに大抵、自分自身の書いたコード以外の、一緒に読み込まれるコードのことを無視したり考えに入れなかったりします。直接/間接の依存関係、バンドル、プリプロセッサー、CSS、その他いろいろ読み込まれますが、気にしていません。サプライチェーンアタックは、この依存関係のどこか1箇所が傷つけられて、その結果システム全体が傷つけられることを指します」⁠Jarrodさん)

event-streamに対する攻撃の準備

この発表では、昨年11月にevent-streamパッケージでおこった、サプライチェーンアタックを取り上げました。

event-streamは、node streamを抽象化した古くからあるパッケージです。この当時1,600ものパッケージがevent-streamに依存していました。そして毎週120万もダウンロードされていました。その後11月に悪用されてから、800万ダウンロードされました。ダウンロードした人たちは、悪用されていることを知らずに動かしてしまっただろうと言います。

事の発端は、event-streamの開発者が、2018年9月にright9ctrlというユーザーにevent-streamの所有権(オーナーシップ)を与えたところから始まります。right9ctrlは、何回か問題のないコミット(変更)を行い、コミュニティの信頼を獲得しました。

そして9月9日に新しい依存flatmap-streamを追加して、新しいバージョン3.3.6をリリースしました。この時はまだ問題はありませんでした。package.jsonの依存関係には、"flatmap-stream": "^0.1.0"と記述されました。これは0.x.xに自動でアップデートする指定になります。次にevent-stream v4.0.0がリリースされ、この最新版ではflatmap-streamへの依存は削除されました(その結果、最新版ではflatmap-streamに対する依存は隠されました⁠⁠。それ自体は普通の行いで、特におかしなところはありません。ここまで12日間です。

画像

悪意のあるコードのリリース

そして、10月5日に悪意のあるflatmap-stream v0.1.1がリリースされました。event-stream 3.3.6を新しくインストールした人は、この悪意のあるflatmap-stream v0.1.1がインストールされるようになりました(package.jsonの"^0.1.0"の効果です⁠⁠。

今まで実績のあるevent-stream v3.3.5に依存していた他のパッケージも、次にインストールするときにはevent-stream v3.3.6を読み込み、その結果として悪意のあるflatmap-stream v0.1.1を読み込んでしまいました。

発見は幸運

Jarrodさんによると、今回のアタックが発見できたのは純粋に幸運によるものだとのことです。

悪意のあるコードが、Node.js v11.0.0では非推奨となったメッソドを使っていたため、8日後にリリースされたNode.js v11.0.0で実行すると、event-stream v3.3.5に依存しているプロジェクトでは(実際にはevent-stream v3.3.6を読み込んだため⁠⁠、コンソールに非推奨の警告が出るようになりました。

この非推奨の警告はcryptoに関するもので、event-stream v4にバージョンアップすると、⁠flatmap-stream v0.1.1の依存はなくなっているため)警告は消えます。この発見をevent-streamの所有者交代を結びつけて考える人が出てきて、flatmap-streamで何かおかしなことが行なわれていることが分かったのです。

3段階の攻撃

実際に、どのように攻撃が行われたのかを説明しました。

flatmap-stream v0.1.0からv0.1.1の変更では、382バイトが追加され(Payload A⁠⁠、これが攻撃を読み込むブートストラップとして機能していると言います。この部分を見やすく変換すると、./test/dataというファイルを読み込んでいることが分かります。

./test/dataというファイルには暗号化されたJavaScriptが含まれており、新しいモジュールを動的に作って、その暗号化されたJavaScript(Payload B)を復号化してコンパイルします。その際、復号のための鍵として、環境変数からnpmモジュールの説明を取得して利用しています。

これはnpm scirptから実行され、説明(description)に特定の文字列を含んでいる場合に限って発動します。

次に狙われたモジュールを探すために、すべてのモジュールのpackage.jsonをひっくり返す必用があります。この目的には、幸運なことにall-the-packagesというモジュールが使えます。all-the-packagesを使えばnpmに登録されたすべてのモジュールを順番にたどることができます。

まとめると、ターゲットを探すプランは次のとおりです。

  1. すべてのパッケージを辿りながら、メタデータを集める
  2. 各パッケージのメタデータに含まれるdescriptionを鍵にして、testData[0](Payload B)を復号化できるか試す
  3. もし復号化できたら、JavaScriptパーサーにかける
  4. もしJavaScirptとしてパースできたら、そのパッケージがターゲット

このような試みは実際には上手く行かないことも多いのですが、やってみたら20秒で該当するパッケージが見つかったそうです。それはcopayというビットコインのセキュアウォレットでした。

copayはOSSだったので詳しく調べることができました。復号化されたJavaScriptのPayload Bの役割は、⁠build:*-release⁠というスクリプトの実行を見つけた場合に、さらなる攻撃(Payload C)をしかけることでした。それはJavaScriptを使ったモバイルアプリのリリース版をビルドする処理において発動し、差し込まれたPayload Cのコードは、アプリからウォレットのパスワードを盗もうとしていました。

このように、ターゲットのnpmモジュールは、誰も想像していなかったモバイルアプリで動くものだったのです。

今回の教訓

今回の攻撃を振り返って、これがnode/npm特有の問題ではなく、すべての公開されたレポジトリは影響を受ける可能性があると強調しました。このケースではコミュニティは素早く対処できたことを良いニュースとしながら、悪いニュースとして同様なことはこれまで何度も起きていると話します。

今回は大きな被害にはならなかったがもっと酷い事態になった可能性があったと説明し、最後に、開発者ができる対策として、次のことを挙げました。

  • audit your dependency:自分が何に依存しているかを把握し
  • lock your dependency:依存をロックし、安易にパターンマッチを使わない
  • cache/check your deependency:依存対象を(企業内のレポジトリーに保持して)キャッシュしたり、チェックする
  • think twice before add dependency:依存を追加する前によく考える

そして、⁠疑わしい時は、賭けをせずに依存は追加しないことです。リスクが小さく価値が大きい時だけ賭けをしよう」と話しました。

また、DevSecOpsとしてできることとして、次のことを挙げました。

  • subresource integrity:サブリソース完全性(SRI)の仕組みを使って、ハッシュ値でリソースが意図せず改ざんされていないかをチェックする
  • contents security policy:コンテンツセキュリティポリシー(CSP)ヘッダーの仕組みを使って、どこから来たリソースに何の実行許可を与えるかを定める

Jarrodさんは「リリース前にアプリと依存先をスキャンをして、怪しい・知らない変更が加わっていないことを確認しよう」と述べ、発表を締めくくりました。

スポンサーセッション

2日目にもスポンサーセッションがあり、Yahoo! Japan、リクルート、ドワンゴ、DMM、Twilloの5社から発表がありました。

クロージングキーノート「points at random」

最後のセッションはMariko Kosakaさんのクロージングキーノートpoints at randomです。

画像

Marikoさんは、実は今回の会場には11年前に来たことがあるそうです。アーツ千代田ができる前にここでアートフェアをおこなったことがあり、その時に広報のインターンとして参加していたそうです。そのようなバックグラウンドをもつMarikoさんは、アートの話を織り交ぜながら、どんな経緯でJavaScriptと関わるようになったのか、そして大事にしたいことについて発表しました。

Sol Lewitt:コンセプチュアルアートの先駆者

はじめに、コンセプチュアルアートの先駆者の一人、Sol Lewittを取り上げて、その作品の特徴を説明しました。

Wall join collectionはギャラリーの壁に直接描かれる作品群です。Solはインストラクションだけを作り、実際に壁に書くのは別の人たちに任せます。違う場所では違う人たちが描くので、それぞれの場所では異なる結果が残ります。

Solのインストラクションは、コードにとても似ています。例えばCode drawing #118では、⁠壁にランダムに50個の点を散りばめ、すべてを直線でつなげる」という指示を与えています。この作品はdemocratic handsによって作られています。誰がどこを描いたか・誰の線がきれいかではなくて、参加者全員がその一つの作品に貢献していると考えます。ちょうど、仕様書や設計書がそれ自体ではソフトウェアにならず、我々も多くの人の手をかけてそのプロジェクトを実行するのと同じではないか、と話しました。

Lillian F. Schwartz:コンピューターアートの先駆者

さらに、コンピューターを利用した最初のアーティストとして知られるLillian F. Schwartzを紹介しました。

Lillianはベル研究所のLeon Harmonに誘われ、多くの研究者たちと出会いともに活動し、たくさんの作品を手掛けています。ここでは、大事なのはツールだけではなく、周りの人々が重要であることを指摘しました。いつでもいろんな科学者と話ができる環境がありました。

ランダムな出会い

Marikoさんは、創造的活動をするのに周りの人々が重要だとし、自分のキャリアを引き合いに出しました。

「私のエンジニアとしての最初の2年間は、社内ツールの開発でほぼ1人で働いていました。しかし、ラッキーにも私の質問に何でも答えてくれるプロダクトのエンジニアのすぐ隣の席でした。私は文字どおり『すべて』について質問しました。

その後、BrooklynJSに参加しました。ここでおそらく「もっとも騒がしくて、もっとも協力的」な人たちに出会い、最初の技術的なトークをする機会となりました。そして、このBrooklynJSでMikeal Rogersと話したことがきっかけで、io.jsの翻訳コミュニティを手伝うことになり、古川さんをはじめ日本のコミュニティーのみなさんと繋がることになりました」⁠Marikoさん)

こうした人たちとの出会いがあって、色々なカンファレンスで話す機会ができ、新しい仕事を見つけ、想像もしていなかったポジティブな影響があったと語りました。

特権を忘れずに

Marikoさんは、Sol Lewittの言葉「ランダムは本当にランダムではありません」を引用し、偶然いろんな人と出会い・繋がってきたと言うのは簡単だとし、実際には自身の背景には次の要素があったと語りました。

  • 様々な団体がアクティブに活動している場所であるニューヨークに住んでいて
  • コードを学ぶ時間がたっぷりあり
  • 最初に留学できる家庭に生まれて、お金の心配をせずに英語を学ぶ時間をもつことができた

そして、次のように述べて今回の発表を結びました。

「つまり、私の偶然は、とても大きな「特権」の上になりたっています。もちろん、一生懸命学んだし、コミュニティを良くするために努力もしたけど、それはすべて『特権』があってのものです。

大きいか小さいかはともかく、だれもが何らかの『特権』を持っています。それを忘れなければ、もっと気軽に、その特権をお互いに貸し合うことができるのではないかと、希望を持っています。

(Lillian F. Schwartzwが経験したように)自分のオフィスにちょっと遊びにおいでよと声をかけるように、みんなの手でランダムな点々のつながりが広がったらいいなと思っています。

Thanks JSConf!」⁠Marikoさん)

画像

クロージング

クロージングでは代表理事の古川さんが登壇して、挨拶をおこないました。

古川さんはJSConf JPについて、みんながやろうとしてしたけどできなかったイベントだと言います。今回はJSConf主催者にメンターになってもえて実現しましたと経緯を語り、そしてスタッフ、参加者、スピーカー、スポンサー、メンターのJSConfコロンビアのジョアンさんへの感謝の言葉を述べていました。

なお、次回のJSConf JPは2020年9月に開催予定であることを発表し、TC39とコラボレーションも考えているということです。

最後に古川さんは「来てくれてありがとう。来年会いましょう。Hooo!」と述べ、その後、参加者全員の記念撮影で幕を閉じました。

イベントを終えて

東京Node学園祭ではバックエンド中心のトピックが多かった記憶がありますが、近年はTypeScriptやReactといったビルドを行うツールチェーンが主流になっていて、フロントエンドの話題も増えてきていました。今年はJSConfとなり、フロントエンドもバックエンドも含む、Web全体をテーマとしたカンファレンスに生まれ変わった印象を強く受けました。

同時に、これからもっと海外からの参加者と日本の参加者の橋渡しをしたいという主催者の願いを強く感じられるイベントでした。来年のJSConf JP 2020の開催が今から楽しみです。

おすすめ記事

記事・ニュース一覧