Node.jsの色々

21.6K Views

March 13, 21

スライド概要

2020-07015 OWASP Sendai ミーティング資料

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

(ダウンロード不可)

関連スライド

各ページのテキスト
1.

2020-07-15 OWASP Sendai Node.js の色々 OWASP Kansai board member はせがわようすけ

2.

長谷川陽介 (はせがわようすけ) (株)セキュアスカイ・テクノロジー 取締役CTO [email protected] https://utf-8/jp/ 千葉大学 非常勤講師 OWASP Kansai ボードメンバー OWASP Japan ボードメンバー CODE BLUEカンファレンス レビューボードメンバー

3.

OWASP Kansai Chapter 自分たちの直面するWebセキュリティの問題を 自分たちの手で解決したい!  日本で2番目の OWASP Local Chapter  Webセキュリティの悩み事を気楽に相談し情報共有できる場  スキル、役職、業種、国籍、性別、年齢に関係なし vol.16 OWASP Kansai 森田 智彦 代表 | 地域のキーパーソンに聞く、経営課題としての セキュリティ | 2020年サイバーセキュリティ月間企画 (近畿経済産業局) https://www.kansai.meti.go.jp/2-7it/k-cybersecurity-network/interview2020/kp16.html OWASP Sendai / 2020-07-15 t #owasp_sendai

4.

OWASP Kansaiの活動 OWASP API Security Top 10の翻訳 たいがいの認証メカニズムは正しく 実装されてへんので、こすい奴は認 証トークンをパクったり、実装の欠陥 を悪用して他のユーザーIDを一時的 または恒久的に推測したりしよんねん。 OWASP Sendai / 2020-07-15 t #owasp_sendai

5.

今日のテーマ 「Node.jsなWebアプリのセキュリティ」 OWASP Sendai / 2020-07-15 t #owasp_sendai

6.

Node.jsなWebアプリケーション  V8 JavaScriptエンジンを採用したサーバーサイドのJS環境  JSは(スクリプト言語としては)速い [要出典]  非同期イベント駆動  ファイルやネットワークの入出力が非同期に行われる  Webアプリとしては多数のクライアントを効率的に処理可能  リクエストごとにプロセスやスレッドが生成されない  少し前に話題になったC10K問題へのひとつの解答 OWASP Sendai / 2020-07-15 t #owasp_sendai

7.

Node.jsなWebアプリのセキュリティ  OWASP Nodejs Security cheat sheet https://cheatsheetseries.owasp.org/cheatsheets/Nodejs_Security_Cheat_Sheet.html 他の言語やフレームワーク同様 にNode.js製アプリケーションも 増加しています。[要出典] ●Java ● PHP ● Ruby ● nodejs from Google Trends, 5years, Worldwide OWASP Sendai / 2020-07-15 t #owasp_sendai

8.

OWASP Nodejs Security cheat sheet  アプリケーションセキュリティ  非同期処理はPromiseでフラットに書こう  リクエストのサイズを制限しよう  イベントループのブロックを避けよう  入力の検証をきちんとしよう  出力のエスケープをきちんとしよう  イベントループでネットワーク帯域も監視し よう  総当たり攻撃に備えよう  CSRFトークンを使おう  不要なURLルーティングを消しておこう  HTTPパラメータ汚染に備えよう  必要な情報のみを返すようにしよう  Objectのプロパティ記述子を活用しよう  アクセスコントロールリストを使おう  エラーと例外のハンドリング  uncaughtExceptionのハンドリング  EventEmitter使用時はエラーを確認する  非同期呼び出しのエラーを捕捉する  サーバーのセキュリティ  Cookieの属性を適切に  セキュリティ関連のHTTPヘッダーを適宜つけ よう  プラットフォームのセキュリティ  パッケージの更新を維持しよう  危険な関数を使わないようにしよう  危険な正規表現を避けよう  セキュリティ検査ツールを定期的にかけよう  Strictモードを使おう  一般的なセキュリティ原則を守ろう https://cheatsheetseries.owasp.org/cheatsheets/Nodejs_Security_Cheat_Sheet.html OWASP Sendai / 2020-07-15 t #owasp_sendai

9.

OWASP Nodejs Security cheat sheet  アプリケーションセキュリティ  非同期処理はPromiseでフラットに書こう  リクエストのサイズを制限しよう  イベントループのブロックを避けよう  入力の検証をきちんとしよう  出力のエスケープをきちんとしよう  イベントループでネットワーク帯域も監視し よう  総当たり攻撃に備えよう  CSRFトークンを使おう  不要なURLルーティングを消しておこう  HTTPパラメータ汚染に備えよう  必要な情報のみを返すようにしよう  Objectのプロパティ記述子を活用しよう  アクセスコントロールリストを使おう  エラーと例外のハンドリング  uncaughtExceptionのハンドリング  EventEmitter使用時はエラーを確認する  非同期呼び出しのエラーを捕捉する  サーバーのセキュリティ  Cookieの属性を適切に  セキュリティ関連のHTTPヘッダーを適宜つけ よう  プラットフォームのセキュリティ  パッケージの更新を維持しよう  危険な関数を使わないようにしよう  危険な正規表現を避けよう  セキュリティ検査ツールを定期的にかけよう  Strictモードを使おう  一般的なセキュリティ原則を守ろう https://cheatsheetseries.owasp.org/cheatsheets/Nodejs_Security_Cheat_Sheet.html OWASP Sendai / 2020-07-15 t #owasp_sendai

10.

イベントループのブロックを避けよう OWASP Sendai / 2020-07-15 t #owasp_sendai

11.

イベントループのブロック  Node.jsは非同期型のイベント駆動  イベントループにてイベントの発生を継 続的に監視  I/Oなどは非同期に実行される  イベントループが停止するとアプリ ケーション全体が止まる  イベントループを止めないよう各処理は 速やかに処理を終えるか非同期に実行 する必要がある OWASP Sendai / 2020-07-15 Node.js イベントループ libuv / OS 出力よろしく! まかせろ! 入力きた? きたよ! コールバック関数 出力終わった? まだだよ! t #owasp_sendai

12.

イベントループのブロック  イベントループが止まるとアプリケー ション全体が止まる  CPUのみで行う処理などは同期的に実 行され他のイベントが実行されない  膨大な計算処理、時間のかかる正規表 現、巨大な配列の処理、JSON.parseな ど  攻撃者が意図的にそのような状況を 作り出すことができるとDoSを発生さ せられる OWASP Sendai / 2020-07-15 Node.js イベントループ libuv / OS 出力よろしく! まかせろ! 入力きた? きたよ! コールバック関数 出力終わった? まだだよ! t #owasp_sendai

13.

イベントループのブロック - ReDoS  正規表現によるDoS (ReDoS)  正規表現のパターンによっては内部的に膨大な照合処理が行われ る const re = /([a-z]+)+$/; re.test('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!'); //秒単位で処理時間がかかる https://gist.github.com/watson/7682ee718b9cf4aa2a5a605a3fb4a552 より  意図的にこの状態を攻撃者が作り出すことでパフォーマンスが低下 する OWASP Sendai / 2020-07-15 t #owasp_sendai

14.

イベントループのブロック - ReDoS 対策  量指定子の回数を制限する 「+」や 「*」 ではなく 「{0,20}」 など  safe-regexモジュールなどを用いて事前にパターンの検査を行う  正規表現を使わなくていい箇所では使わない String.prototype.includes や String.prototype.startWith などを 使用 OWASP Sendai / 2020-07-15 t #owasp_sendai

15.

イベントループのブロック - JSON.parse  JSON.parseは同期的に処理され、パース中は他のイベント処理は 実行されない  巨大な文字列のJSON.parseはアプリケーション全体をブロックさ せる可能性がある const text = req.body.param const obj = JSON.parse(text) OWASP Sendai / 2020-07-15 // パースが完了するまで処理がブロック t #owasp_sendai

16.

イベントループのブロック - JSON.parse 対策  JSON.parseの前にテキストのサイズを確認 1 2 3 4 5 const text = req.body.param // サイズが4k以下の時だけJSON.parseする if (typeof text === 'string' && text.length < 4096) { const obj = JSON.parse(text) }  asyncなJSONパーサーの導入  使ったことがないので何とも言えず…  他のライブラリで内部的にJSON.parseが呼び出されている場合には対応 できない OWASP Sendai / 2020-07-15 t #owasp_sendai

17.

イベントループのブロック - JSON.stringify  JSON.stringifyでも同じことはあり得る  巨大な配列を含むJSONをシリアライズするときにブロック等 参考:https://techblog.yahoo.co.jp/advent-calendar-2018/goodbyemym/#uopoo  配列を含むJSONをstringifyするときは事前に配列の長さを確認 1 function foo (obj) { 2 let text 3 // 配列の長さが1k以下の時だけJSON.stringifyする 4 if (obj.items instanceof Array && obj.items.length < 1024) { 5 text = JSON.stringify(obj) 6 } 7 ... 8 } OWASP Sendai / 2020-07-15 t #owasp_sendai

18.

OWASP Nodejs Security cheat sheet  アプリケーションセキュリティ  非同期処理はPromiseでフラットに書こう  リクエストのサイズを制限しよう  イベントループのブロックを避けよう  入力の検証をきちんとしよう  出力のエスケープをきちんとしよう  イベントループでネットワーク帯域も監視し よう  総当たり攻撃に備えよう  CSRFトークンを使おう  不要なURLルーティングを消しておこう  HTTPパラメータ汚染に備えよう  必要な情報のみを返すようにしよう  Objectのプロパティ記述子を活用しよう  アクセスコントロールリストを使おう  エラーと例外のハンドリング  uncaughtExceptionのハンドリング  EventEmitter使用時はエラーを確認する  非同期呼び出しのエラーを捕捉する  サーバーのセキュリティ  Cookieの属性を適切に  セキュリティ関連のHTTPヘッダーを適宜つけ よう  プラットフォームのセキュリティ  パッケージの更新を維持しよう  危険な関数を使わないようにしよう  危険な正規表現を避けよう  セキュリティ検査ツールを定期的にかけよう  Strictモードを使おう  一般的なセキュリティ原則を守ろう https://cheatsheetseries.owasp.org/cheatsheets/Nodejs_Security_Cheat_Sheet.html OWASP Sendai / 2020-07-15 t #owasp_sendai

19.

Objectのプロパティ記述子を 活用しよう OWASP Sendai / 2020-07-15 t #owasp_sendai

20.
[beta]
Objectのプロパティ記述子  生成したオブジェクトのプロパティの書き込みや列挙を禁止できる  Object.defineProperty / Object.defineProperties  意図しないオブジェクトの書き替えを阻止  strictモードと組み合わせることで早い段階でバグを検出できる 1 2 3 4 5 6 const user = { name: 'hasegawa' } console.log(user.name) // 'hasegawa' user.name = 'yosuke' console.log(user.name) // 'yosuke' OWASP Sendai / 2020-07-15 1 2 3 4 5 6 7 8 9 'use strict' const user = {} Object.defineProperty(user, 'name', { value: 'hasegawa', writeable: false }) console.log(user.name) // 'hasegawa' user.name = 'yosuke' // 例外発生 console.log(user.name) t #owasp_sendai
21.

Objectのプロパティ記述子  既存オブジェクトのプロパティ変更も禁止できる  Object.preventExtensions / Object.seal / Object.freeze 1 2 3 4 5 6 7 'use strict' const user = { name: 'hasegawa' }) Object.seal(user) user.name = 'yosuke' // 既存のプロパティの値は変更可能 user.mail = '[email protected]' // プロパティ追加で例外発生 1 2 3 4 5 6 'use strict' const user = { name: 'hasegawa' }) Object.freeze(user) user.name = 'yosuke' OWASP Sendai / 2020-07-15 // 既存のプロパティの値変更で例外 t #owasp_sendai

22.

OWASP Nodejs Security cheat sheet  アプリケーションセキュリティ  非同期処理はPromiseでフラットに書こう  リクエストのサイズを制限しよう  イベントループのブロックを避けよう  入力の検証をきちんとしよう  出力のエスケープをきちんとしよう  イベントループでネットワーク帯域も監視し よう  総当たり攻撃に備えよう  CSRFトークンを使おう  不要なURLルーティングを消しておこう  HTTPパラメータ汚染に備えよう  必要な情報のみを返すようにしよう  Objectのプロパティ記述子を活用しよう  アクセスコントロールリストを使おう  エラーと例外のハンドリング  uncaughtExceptionのハンドリング  EventEmitter使用時はエラーを確認する  非同期呼び出しのエラーを捕捉する  サーバーのセキュリティ  Cookieの属性を適切に  セキュリティ関連のHTTPヘッダーを適宜つけ よう  プラットフォームのセキュリティ  パッケージの更新を維持しよう  危険な関数を使わないようにしよう  危険な正規表現を避けよう  セキュリティ検査ツールを定期的にかけよう  Strictモードを使おう  一般的なセキュリティ原則を守ろう https://cheatsheetseries.owasp.org/cheatsheets/Nodejs_Security_Cheat_Sheet.html OWASP Sendai / 2020-07-15 t #owasp_sendai

23.

まとめ  OWASPにはNode.jsアプリのチートシートがある  セキュリティだけでなく堅牢なコードにするための項目も多い  イベントループのブロックがNode.jsの問題としては大きい  ReDoSはOSSの脆弱性としてもよく見つかっている  チートシートに載ってない注意点もけっこうある  NoSQLインジェクションとか(Node.jsと組み合わせてよく使われる)  const / let 、Strictモードでコードを堅牢にする  eslintでありがちなミスを減らす  TypeScriptで型を厳密にする等 OWASP Sendai / 2020-07-15 t #owasp_sendai

24.

One more thing ...

25.

prototype汚染 OWASP Sendai / 2020-07-15 t #owasp_sendai

26.

prototype汚染  __proto__経由でObject.prototypeが汚染されてしまう問題  prototype.js時代のprototype汚染とは異なる  あれは意図的にObject.prototypeに便利メソッドを追加しているが迷惑だ という問題  攻撃者が__proto__プロパティを宣言することでグローバルの Object.prototypeeを汚染する  存在しないはずのプロパティが全オブジェクトに存在してしまう OWASP Sendai / 2020-07-15 t #owasp_sendai

27.

OWASP Sendai / 2020-07-15 t #owasp_sendai

28.

prototype汚染 https://jovi0608.hatenablog.com/entry/2018/10/19/083725 より ① 外から来た文字列をJSON.parse 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 function main (source) { const x = JSON.parse(source) // 外からきた文字列 const y = clone(x) const z = {} console.log(z.polluted) } ② そのオブジェクトを複製 ③ 空のオブジェクトを生成 ④ ここで表示されるのは? function clone(obj) { return merge({}, obj) } function merge (a, b) { for (const key in b) { if (isObject(a[key]) && isObject(b[key])) { merge(a[key], b[key]) } else { a[key] = b[key] } } return a } OWASP Sendai / 2020-07-15 オブジェクトを複製する関数 プロパティを列挙して再帰的にコピーするだけ t #owasp_sendai

29.
[beta]
prototype汚染 https://jovi0608.hatenablog.com/entry/2018/10/19/083725 より ① 外から来た文字列をJSON.parse 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 function main (source) { const x = JSON.parse(source) // 外からきた文字列 const y = clone(x) const z = {} console.log(z.polluted) } function clone(obj) { return merge({}, obj) } function merge (a, b) { for (const key in b) { if (isObject(a[key]) && isObject(b[key])) { merge(a[key], b[key]) } else { a[key] = b[key] } } return a } OWASP Sendai / 2020-07-15 ② そのオブジェクトを複製 ③ 空のオブジェクトを生成 ④ ここで表示されるのは? source: '{"__proto__": {"polluted": "1"}}' 1 オブジェクトを複製する関数 プロパティを列挙して再帰的にコピーするだけ t #owasp_sendai
30.
[beta]
prototype汚染 https://jovi0608.hatenablog.com/entry/2018/10/19/083725 より {"__proto__": {"polluted": "1"}} 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 function main (source) { const x = JSON.parse(source) // 外からきた文字列 const y = clone(x) const z = {} console.log(z.polluted) } function clone(obj) { return merge({}, obj) } function merge (a, b) { for (const key in b) { if (isObject(a[key]) && isObject(b[key])) { merge(a[key], b[key]) } else { a[key] = b[key] } } return a } OWASP Sendai / 2020-07-15 __proto__の書き込み(複製)でグローバルな Object.prototypeが汚染される prototype経由で存在しないプロパティが存在 するかのようにふるまう valueOf()やtoString()なども書き替えられる可 能性。最悪の場合はコード実行につながる t #owasp_sendai
31.

prototype汚染 - 対策  外部からのJSONには__proto__のように動作に影響をあたえる キーが含まれている可能性がある  外部からのJSONのキーを列挙してそのまま使用しない  キー名が想定されているものか確認する  最低限、キーを列挙する際には __proto__ を除外する 1 function merge (a, b) { 2 for (const key in b) { 3 if (key === '__proto__') continue 4 if (isObject(a[key]) && isObject(b[key])) { 5 merge(a[key], b[key]) 6 } else { 7 a[key] = b[key] 8 } 9 } 10 return a 11 } OWASP Sendai / 2020-07-15 t #owasp_sendai

32.

prototype汚染 - 他の対策方法  オブジェクトリテラル「{}」ではなくObject.create(null)を使う  prototypeがnullのオブジェクトが生成される  ただしprototypeチェインがたどれなくなるので、hasOwnPropertyなどが直接は 呼び出せなくなる(そもそもObject.prototype.hasOwnProperty.callするほうが いい)  Object.freezeを用いてObject本体およびObject.prototypeを凍結する  副作用で動かなくなるモジュールが発生する可能性がある  JSON Schemaなどを用いて入力をより厳密に検証する  入力されるJSONのキー名や型などを厳密に検証する  ObjectではなくMapを使う  外部からのデータはObjectではなくMapに格納して使用する  MapからObjectへコピーする際には__proto__をコピーしないよう注意が必要 参考: https://techblog.securesky-tech.com/entry/2018/10/31/ OWASP Sendai / 2020-07-15 t #owasp_sendai

33.

質問? [email protected] @hasegawayosuke https://utf-8.jp/ OWASP Sendai / 2020-07-15 t #owasp_sendai