Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 9134

Webの勉強はじめてみた その28 〜脆弱性の対策〜

$
0
0
N予備校「プログラミング入門Webアプリ」を受講しています。 今回は第3章27〜34節です。 脆弱性 OS コマンド・インジェクション - 任意の OS のコマンドを実行できてしまう SQL インジェクション - 任意の SQL というデータベースを操作するコマンドを実行できてしまう ディレクトリ・トラバーサル - 任意のファイルを閲覧、操作できてしまう セッションハイジャック - 利用者のセッションが乗っ取られてしまう クロスサイト・スクリプティング (XSS) - スクリプトにより Web サイトの改ざんができてしまう クロスサイト・リクエストフォージェリ (CSRF) - 利用者の意図しない操作がされてしまう HTTP ヘッダインジェクション - 偽ページの表示などができてしまう クリックジャッキング - 利用者の意図しないクリックをしてしまう これを見ただけでもフレームワークの必要性がわかる。 OSコマンドインジェクション 当人ではなく、Webサービスが実行者になってしまう。 クライアントから受け取ったデータを使ってコマンドを実行しないことが重要 XSS脆弱性 Webサービスの外部からの入力で表示が変化する機能において、意図しないHTML, JavaScript, CSSの変更ができる脆弱性 posts.pug each post in posts p!= post.content p 投稿日時: #{post.createdAt} hr タグとして認識させる!=は非推奨とのこと。 今回は改行させたいだけなので、cssで工夫する。 p(style="white-space:pre; overflow:auto;") #{post.content} コンテンツセキュリティポリシー(CSP)によるXSS脆弱性の対処法 CSPとは、Web サイトにおいて信頼できるリソース(CSS や JavaScript、画像ファイルなど)の範囲を設定し、それ以外の読み込みをブラウザ側でブロックする仕組み GETメソッドが実行された時にレスポンスとしてヘッダーに記述。 res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8', 'Content-Security-Policy': "default-src 'self'; script-src https://*; style-src https://*" }); インラインスクリプトを禁止。Bootstrapなどのhttpsで始まる外部ファイルの許可。 メッセージダイジェスト 任意の長さのデータを、そのデータを代表する値に変換する関数のことをハッシュ関数、結果をハッシュ値という。 メッセージダイジェストとは、ハッシュ関数を使って作られたそのパスワードの変換結果。 ハッシュ関数とセッション よく使われるハッシュ関数のアルゴリズム ・MD5 ・SHA(SHA-1, SHA-2, SHA-3) ・bcrypt 現在は、SHA-2、bcryptを使う。 セッションとは、システムにログインまたは接続してから、ログアウトまたは切断するまでの 一連の操作や通信のこと。 セッション固定化攻撃とは、 セッションの乗っ取り(セッションハイジャック)を行うための攻撃手法の 1 つで、外部から指定可能なセッションの識別子を利用してセッションハイジャックを行う。 今回はトラッキングCookieとユーザー名とランダムな数値(secretKey)からハッシュ値を作る。 const crypto = require('crypto'); /** * ハッシュを生成 * @param {String} originalId * @param {String} userName * @returns {String} Hash値 */ function createValidHash(originalId, userName) { const sha1sum = crypto.createHash('sha1'); sha1sum.update(originalId + userName + secretKey); return sha1sum.digest('hex'); } secretKeyは、crypto.randomBytes(256).toString('hex')を実行して取得。 CSRF(シーサーフ)脆弱性 クロスサイト・リクエストフォージェリ脆弱性 偽サイトを通じて外部のサイトからリクエストを送ることで、重要な処理を誤って起こさせる脆弱性 <form action="http://localhost:8000/posts?delete=1" method="post"> <input type="hidden" name="content" value="32"> <button type="submit">ボタンを押してみてください</button> </form> 全く別のサイトから投稿や削除ができてしまう。 対策として、ワンタイムトークンを使う。 ページへアクセスする際、必ずGETメソッドが実行されている。それを利用してワンタイムトークン(CSRFトークン)を毎回発行し、一致しない場合は不正アクセスとする。 GET時 const oneTimeTokenMap = new Map(); // キーをユーザー名、値をトークンとする連想配列 const oneTimeToken = crypto.randomBytes(8).toString('hex'); oneTimeTokenMap.set(req.user, oneTimeToken); res.end(pug.renderFile('./views/posts.pug', { posts, user: req.user, oneTimeToken })); POST時 body = Buffer.concat(body).toString(); const params = new URLSearchParams(body); const content = params.get('content'); const requestedOneTimeToken = params.get('oneTimeToken'); if(!(content && requestedOneTimeToken)){ util.handleBadRequest(req, res); } else { if(oneTimeTokenMap.get(req.user) === requestedOneTimeToken){ // DataBaseへの登録 Post.create({ content, trackingCookie: trackingId, postedBy: req.user }).then(() =>{ // Token削除 oneTimeTokenMap.delete(req.user); console.info(`投稿されました: ${content}`); handleRedirectPosts(req, res); }); } else { util.handleBadRequest(req, res); } } Bootstrap どのようなデバイスでページを見ても適切なデザインとなるような HTML, CSS, JavaScript を提供する Web ページ作りのための部品集。CSSフレームワーク。 posts.pug link(rel="stylesheet", href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css", integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm", crossorigin="anonymous") script(src="https://code.jquery.com/jquery-3.4.1.slim.min.js") // 中略 script(src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js", integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl", crossorigin="anonymous") ネットワーク経由とソースをダウンロードしてくるのと方法はあるけれど、どっちがいいとかあるんだろうか。 Herokuでデータベースを使う heroku addons:create heroku-postgresql:hobby-dev hobby-devはフリープラン。 const dialectOptions = { ssl: { require: true, rejectUnauthorized: false } } const sequelize = process.env.DATABASE_URL ? // 本番環境 new Sequelize( process.env.DATABASE_URL, { logging: false, dialectOptions } ) : // 開発環境 new Sequelize( 'postgres://postgres:postgres@db/secret_board', { logging: false } ); 環境変数に値が入ってるかどうかで本番かテスト環境かを判断。 まとめ 今回で第3章は終わり。 これだけ対策してもまだまだ脆弱性があるとか言われると、ソースコードも煩雑になっていくのは目に見えていて、それをなんとかしてくれるとかもうフレームワークすごいとなるわけで。ワクワクが止まらない。

Viewing all articles
Browse latest Browse all 9134

Trending Articles