質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.03%

SPA・クライアントサイドレンダリングはセキュリティ的に安全なのでしょうか?

解決済

回答 5

投稿 編集

  • 評価
  • クリップ 8
  • VIEW 5,288

jimyo

score 232

最近SPAについて勉強しています。

SPAでは、クライアントサイドレンダリングが基本だと思います。
Vue.js や React を用いてビュー部分をブラウザにわたし、サーバーサイドではAPIのみを提供しページの構築を行うと思います。

例えば、「管理者なら管理用メニュー、一般ユーザーなら普通のメニューを表示する」のようなロジックを例にすると、ビュー(ここでは Vue.js を使用すると仮定)では次のような実装が考えられると思います。

<div v-if="userType === 'user'">
       <!-- 普通のメニュー -->
</div>
<div v-if="userType === 'admin'">
    <!-- 管理用メニュー -->
</div>

善良なユーザーが使う分には問題無いと思いますが、悪意あるユーザーがコンソールで「userType = 'admin';」などと入力しただけで管理用メニューが表示されてしまいます。

また、そうでなくても表示されないにしろ、HTML/JSに管理用メニューの名前、及びAPIのアクセス先が書いてあるため、API側で何かしらの認証処理をするという前提があったとしても、管理用メニューにどういうものがあるのかを見られてしまうのは脆弱性につながりかねません。

このような点に関してどのような対処をするのが一般的なのでしょうか?

[追記]
皆さん、回答ありがとうございます!
質問の仕方が悪く、自分の伝えたい本質を書くことができていませんでした。

認証周りの話というよりはユーザー(ブラウザ)がコンポーネントに対する操作が可能ということに疑問を持っています。

コンソールからコンポーネントに渡すデータを変えればそのコンポーネントの挙動を変更することとが可能だと思います。

例えば入力フォームを作る場合に特定の条件のユーザーにはフォームを表示しないといったケース、
具体的にはアンケートでユーザーの会員情報で性別が女性の場合は化粧品についてのアンケートも追加で表示させるケースを考えたいと思います。

サーバーサイドレンダリングであればサーバー側でユーザーの性別を見て生成するHTMLを変更できます。

クライアントサイドレンダリングの場合は一旦全て送り、ユーザー側で非表示にさせるといった処理が考えられそうです。

ここでユーザーがコンソールから性別データをいじった場合、男性なのに化粧品のアンケートを表示させる、女性なのに化粧品のアンケートを表示させない のようなことが可能になってしまう気がします。

回答でいただいたコードスプリッティングなどで対応はできそうですが、こんな些細なものごとにいちいち分割しているとは思えません。

[追記2]
もちろんこれはSPAに限らずJavascript自体のリスクではあると思いますが、
サーバーサイドレンダリングの場合、JSは「見た目の操作」にのみ使われてることが多いと思います。
SPAではややロジックも担当している印象を受けたためこのような質問をしました。

ユーザーからの挙動変更が可能なリスクがある中でどのような策がなされているのか、あるいはなすべきなのか 教えていただきたいです。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 5

checkベストアンサー

+9

善良なユーザーが使う分には問題無いと思いますが、悪意あるユーザーがコンソールで「userType = 'admin';」などと入力しただけで管理用メニューが表示されてしまいます。

確かに仰るとおりですね。
コマンド一撃でページの挙動を変更出来るような弱い仕組みにしてはいけません。
ただまぁ、Ajax通信をしっかり見張る仕組みにしてしまえばあまり目くじらを立てる必要がないのも事実ですね。


なぜあまり目くじらを立てる必要がないのか?

バックエンド用のWebフレームワークを使って認証機能を採用すれば良いからです。

Ajax通信は裏でJavaScriptがHTTPリクエストを発射しているだけで、
本質的には普通にブラウザでページを閲覧する行為と代わりありません。

特別な事はしなくてもCookieやセッション機能が利用出来るので、バックエンドで認証機能を実装してしまいましょう。
そしてロールを変更して不正なリクエストを投げたとしても、
毎回DBにちゃんと問い合わせて不正なリクエストは弾く作りにしてください。

つまり、ページ上で不正なJSコードを発行して見かけ上の動作を変更したとしても、
Webアプリ全体で受けられる恩恵は微々たるものであり、
有料ユーザーはプロジェクトを多く作れるみたいな感じでAjax通信に依存する箇所に付加価値をかけていけば突破されるリスクはありません。


他にはどんな視点がある?

自分のサービスの価値をどの程度守らなければならないのか検討してみるのも良いでしょう。

例えば、かの有名な秀丸エディタはパスワードを入力するだけで認証を突破出来る脆弱なシステムです。
しかし、その作者は「学生やフリーソフトウェアの開発者は無料にしてあげたい、パスワードを変えたり電話対応したりするとコストが大変なので実質黙認状態、でもまとまったライセンスを買っていただける方もいらっしゃって幸いです」というゆるい対応をしています。

JSを解析して裏でconsole叩いて変な挙動出来るような人間ならば逆にコンタクトをとっても良いかもしれませんね。
日本的ではないかも知れませんが、引き入れれば優秀なメンバーとして活躍してくれるかもしれません。


JSの裁量が大きいページは?

ロールをちょっと切り替えるだけで引き出せる量が違うから不正されると困るという話であれば、

Webpack等が吐き出すJavaScriptファイル自体をAdmin用・エンドユーザー用に分けてしまっても良いと思います。
Admin用は少しくらい不具合が出ても問題になりにくいのでそんなに問題にはならないと思います。


【追記1への回答】

そもそもブラウザの本質を理解していますか?
ブラウザはただ受け取ったHTML・CSS・JS・画像ファイルを内部的に展開して画面に表示しているだけです。
そしてWebサーバへHTTP通信を行いながらHTML・CSS・JS・画像ファイルをまた受け取る。

これがコマンドラインツールのcurlになった瞬間不正になるわけではありません。
全世界のWebサーバはHTTP通信を行う全てのクライアントが対象だからです。

コンソールからコンポーネントに渡すデータを変えればそのコンポーネントの挙動を変更することとが可能だと思います。

Chromeと普通のWebサイトでも可能です。
デベロッパーツール等を利用さえすれば現状のDOM構造を好き勝手に歪めてリクエスト飛ばせますよね。

サービス提供元がわざわざHTMLを渡して上げてるのは、
この項目に従って回答してくださいね、回答が済んだら○○URLのポストに投函してくださいねというガイドラインです。
クラッカーにはHTMLやJSでいくら頑張っても何の対策にもなりません。

クライアントサイドレンダリングの場合は一旦全て送り、ユーザー側で非表示にさせるといった処理が考えられそうです。

SPAではない既存のWebアプリで
HTML情報上にWebサイトを利用する全てのユーザーの住所や氏名をdisplay: none;の状態で埋め込んでおいて、
JavaScriptで表示・非表示を切り替える開発者がいますか?

それと同じです。
bundle.js内にはそのユーザーが閲覧しても良い情報しか内包してはいけません。
貴方が考えている「一旦全て送り、ユーザー側で非表示にさせる」というのは
上記の全ユーザーの氏名や住所をJavaScript制御でON・OFFを切り替える発想と同じです。

じゃあどうするのか?

Ajaxでそのユーザの権限下でアクセス出来る情報を別途取得してください。
bundle.jsにはAjax通信の結果(JSON)を解析して、アンケートフォームを作り出すロジックのみを埋め込んでください。
これで質問文にあった「男性に化粧品の情報を公開する」懸念は払拭されます。

「私に紐づくアンケートはある?」ということで、
example.com/api/questionnairesに向けてAjax通信を行います。

女性の場合だけ化粧品のアンケートを表示したいならば、
きっと認証情報には名前、性別、年齢等の情報はありますよね。

[
  {"name": "化粧品Aは既に利用されていますか?", "candidates": ["はい", "いいえ"]},
  {"name": "化粧品Aを5点満点で評価してください", "candidates": ["1", "2", "3", "4". "5"]},
  {"name": "化粧品Aのモニターに参加しますか?", "candidates": ["はい", "いいえ"]},
  {"name": "化粧品Bは既に利用されていますか?", "candidates": ["はい", "いいえ"]},
  {"name": "化粧品Bを5点満点で評価してください", "candidates": ["1", "2", "3", "4". "5"]},
  {"name": "化粧品Bのモニターに参加しますか?", "candidates": ["はい", "いいえ"]},
]

男性の場合は空の配列を返せば化粧品の情報は送られません。
まぁ、別に男性に化粧品名くらい教えても大丈夫かとは思いますが、認証情報と脳内補完して回答しています。


【追記2への回答】

SPAではややロジックも担当している印象を受けたためこのような質問をしました。

追記1に重複する部分がいくつかありますが、重複する部分は追記1への回答を参照してください。
ユーザーに予め渡す情報量が多いのがSPAので、たしかにそのような懸念はあります。

まずはWebサイト全体で使う全ての情報を割り出し一覧化します。
次に各情報はどのレベルでガードしなければならないかを設定します。
これは公開しても良いだろう…といった情報ならばbundle.jsに含めて表示・非表示を切り替えれば良いですし、
公開出来ない情報は全てAjax通信で別途取りに行く設計にしてください。

あれもこれも非公開にしたければ、相応の数のAjax通信用のURL(エンドポイント)が必要になります。
手間や開発コストも吟味しながら取捨選択を行ってください。

もし認証情報を利用した部分以外、
例えばJSONファイルを展開してアンケートのフォーム部品を生成するロジックを非公開にしたい。
……という意図ならば、もうSPAは諦めてください。

SPAで運営しているWebサイト・Webアプリは全て盗まれるリスクとのトレードオフで運営しています。
ですので、守るべき対象はサーバーに保存する個人情報やプロジェクト情報であり、
そこの部分でマネタイズしているから他社にbundle.jsを盗まれたとしてもダメージは軽微であるという判断を行っているからです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/03/30 12:40

    全ての疑問に答えていただきありがとうございました!
    SPAのメリット・デメリットを理解することができました。

    キャンセル

+5

「認証チェック、権限チェックをサーバーサイド側でするにしても、ログイン画面やらログイン後の画面やらログイン不要の一般ユーザー用画面に関するコードを1つのjsのbundleファイルにまとめてクライアントに返していたら、ログイン後のコンテンツは見れないにしても、ログイン後の画面のコードは見えてしまうよね、それってどうなの?」っていう質問であるならば、

(A)そもそも、最初から管理用画面、一般ユーザー用画面を分けて、jsファイルもそれらの画面用のものをクライアントに返す

(B)Code Splittingを行って、bundleファイルの分割を行い、必要なタイミングで必要なbundleファイルを動的にクライアントに返す(Code Splitting - Dynamic imports / Webpackとか、Code Splitting  / React)

と、なりますかね。

小規模のアプリケーションの場合は1つのbundleファイルにコードをまとめてクライアントに返すかもしれませんが、規模が大きくなってくると、例えば、ログイン画面を表示するだけなのに、他の画面に関わるコードをまとめて送っていては、初期読み込みも遅くなってよろしくないので、Code Splittingを行なったりします。

ただ、Code Splittingはセキュリティーというよりは、パフォーマンス向上の文脈で使われることが圧倒的に多いかと思います。

もちろんこれはSPAに限らずJavascript自体のリスクではあると思いますが、
サーバーサイドレンダリングの場合、JSは「見た目の操作」にのみ使われてることが多いと思います。
SPAではややロジックも担当している印象を受けたためこのような質問をしました。

おっしゃる通り、追記の内容からすると、もはや、spaがどうこうという話ではないと思います。

ここでユーザーがコンソールから性別データをいじった場合、男性なのに化粧品のアンケートを表示させる、女性なのに化粧品のアンケートを表示させない のようなことが可能になってしまう気がします。

そして、セキュリティーと、もはや関係ない気がします。

ユーザーからの挙動変更が可能なリスクがある中でどのような策がなされているのか、あるいはなすべきなのか 教えていただきたいです。

クライアント側では諦める、そして、サーバー側で対応。

SPAにかぎらず、例えば、通常のフォームであっても、フォームのUIからは選択出来ない選択肢を適当にユーザーが設定してサーバー側に送信することも可能なので、不正値かどうかはサーバー側で対応すべきものだと思います。クライアントサイドから送られてきたデータをそのままサーバーサイドで信用してはダメです。

回答でいただいたコードスプリッティングなどで対応はできそうですが、こんな些細なものごとにいちいち分割しているとは思えません。

そうです。そんな些細なことにコストをかける必要があるかを検討することも大事です。なので、今回の追記であったようなケースならば特に気にしないで良いかと思います。

サーバーサイドレンダリングであればサーバー側でユーザーの性別を見て生成するHTMLを変更できます。

サーバーサイドでユーザーの性別を把握出来るということは、ユーザー登録されていることが前提ですかね。
でもその場合、ユーザー登録時に本当の性別をユーザーが登録してくれているかどうかも不明ですよね。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+4

ユーザーからの挙動変更が可能なリスクがある中でどのような策がなされているのか、あるいはなすべきなのか 教えていただきたいです。

認証などは他回答がすぐれているので対策を焦点に回答しますね。

 サーバーサイドでチェックする

一昔はjavascriptが無効化されている場合を考慮する必要があると言われたものです。
例えば「hoge」と言う入力フォームがありjsで文字数10文字でないとリクエスト(get/post)制限をしてたとしてもサーバーサイドで10文字かどうかチェックします。
この場合のjsの意味は、クライアント側でリクエスト・レスポンスが無駄に生じないためのチェックです。
ユーザビリティの為であり、二重チェックしている訳ではありません。

 管理(admin)ページを隔離する

<div v-if="userType === 'admin'">などを使わずにまったくの別ページ(別ドメイン)で作成する。さらにサーバー側でアクセス制限(IPなど)を掛ければ部外者が操作するのは困難になります。
basic認証などもとりあえず有効にしておけば良いですね。basic認証は弱いセキュリティですがwebサーバ自体が弾きますのでbot攻撃などではサーバー負荷が低くなりますし。ないよりマシ程度で。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

次のような実装が考えられると思います。

すいません、考えられません。
そう実装されていたとしても、サーバ側でチェックされているべきです。

ということでサーバ側で切り分けるのが一般的です。
普通セッション使いますよね。

そもそも表示していい権限かどうかもチェックしないといけないわけですから
クライアントに全て送り付けるなんてありえません。。。
開発ツールでレスポンスみたら全て確認できちゃいます。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/03/27 18:27

    回答ありがとうございます。
    ということはユーザーのロールに合わせたjsを複数用意しておくのが定番ということでしょうか?

    キャンセル

  • 2018/03/28 11:34

    「定番」と言われると、ちょっと分からないのですが、
    複数のjsを用意しようが、APIのエンドポイントを複数用意しようが、
    サーバサイドでのチェックも必要ということです。

    クライアントサイドの処理だけだと、
    例え暗号化したとしても十中八九処理の内容を解読されます。

    他の皆さんもおっしゃっていますが、
    情報の機密性やセキュリティの関係もあるので、
    すべてをサーバサイドで、、というのは必要ないと思います。
    そういう意味だと、クライアントサイドでのロジックもありです。

    あとは、クライアントサイドで意図的に改ざんされたデータを受け付けた場合、
    その後の処理にどのような影響があるか確認するのは非常に難しいと思います。
    例えば、追記にありますが、女性なのに化粧品アンケート情報がないケース。
    DMを送付するために化粧品アンケート情報を取得する処理で
    女性なのに化粧品アンケート情報の有無チェックが必要になったりもします。

    キャンセル

0

https://stackoverflow.com/questions/20963273/spa-best-practices-for-authentication-and-session-management

このような回答があります。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.03%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる