最近、片手間に書くjavascript
なるワードが流行っているような気がしています。
サーバサイドのエンジニアがフロントエンドのシステム(javascript)も兼業で書くのは無理があるよ的な意味で私は捉えております。
実際問題、無理があったとしても書かないという選択肢を選ぶことはなかなか難しくやっぱり片手間にjavascriptを書き続けるわけなのですが、それでも最低限気をつけたいことってあると思うのです。
私が出会った片手間のjavascriptの中でも最もやめて欲しかったのが、今回の投稿のタイトルに書いた__スクリプトタグの中にサーバサイドで生成したコードが書かれていること__です。
スクリプトタグの中にサーバサイドで生成したコードが埋め込まれている例
PHPを例に件のコード例を記載します。
<script>
var msg = <?=$msg?>
alert(msg);
</script>
フロントエンドのプログラムがサーバサイドのプログラムに依存する問題
先に例であげたプログラムはサーバサイドのプログラムを通さないと動作させることが出来ません。
テストを書いて実行しようものなら、わざわざサーバサイドプログラムの実行環境を用意しないといけません。
また、共通で利用出来るようなコードパターンが生まれた時に、サーバサイドのプログラムに依存しているため共通化出来ない(出来ないわけではないが、サーバサイドの依存が常につきまとう)という点も問題です。
セキュリティに関する問題
先の例のコードでは、変数に悪意のあるコードが設定された場script insertion
の攻撃が成立します。
<?php
$msg = '"hello world"; location.href = "http://example.com";'
?>
<script>
var msg = <?=$msg?>
alert(msg);
</script>
<script>
タグ内で展開されるサーバサイドの変数は直接javascriptのコードとして扱えるため、通常のエスケープ(<
や>
を置き換えるやつ)では対処することが出来ません。
対処するためには、かなり面倒なエスケープ処理が必要になります。
(めんどくさい処理については割愛…)
解決策
サーバサイドで生成されたデータはデータ提供用のタグに保存し、javascript側はそのタグを通してデータを取得するようにする。
<div id="server-data-provider"
data-msg="<?=htmlspecialchars($msg, ENT_QUOTES, 'UTF-8')?>"></div>
<script>
var server_data = document.getElementById('server-data-provider').dataset;
if (server_data && server_data.msg) {
alert(server_data.msg);
}
</script>
クライアントのコードとサーバサイドのコードの分離
クライアント側のコードはHTMLのデータを格納しているタグさえ知っていればコードが実行出来るようになります。
サーバサイドのプログラムと分離することで、クライアントのプログラムは単体のファイルとして存在することが可能になります。
単体のファイルとして切り出せるため以下のメリットを受けることが出来るようになります。
- ローカルブラウザでもテストが容易に実行出来るようになる
- 共通の処理として再利用出来るようになる
セキュリティ問題の解決が容易
HTMLのタグから取得したデータは文字列として扱われるため、通常のエスケープさえ行っていればセキュリティホールが発生することはありません。
最後に…
片手間だから可能な限りやらない方向でシステム開発を行うのは悪い選択ではないと思います。
それでも、もし必要になったらどうするか?という時のための知識は準備しておいても損は無いと思うのです。(自戒の念もこめて…)