技術の犬小屋

Webプログラミングを餌に生きる犬のメモ帳

Posts in the JavaScript category

Javascriptのエラーチェックやデバッグの方法で覚えたことがあったのでメモしておく。
デバッグの方法に関しては,各種ブラウザによって若干の差異があるので,今回はFirefoxを例にして説明する。
 

Javascriptのエラーチェック

Javascriptのエラーを確認するには,以下の2つの方法が存在し,どちらも行うことが望ましい。
 

JSLintによるエラーチェック

JSLintと呼ばれるJavascriptの構文チェックツールが存在する。私は,エディタはVimを使っているので,syntasticというVimプラグインとJSLintを連携させることで,VimでJavascriptを編集しながら随時構文チェックを行っている。
 
HomebrewでJSLintをインストールするには以下のコマンドを実行する。

brew install jslint

 
VimにSyntasticを導入した状態で.vimrcに以下の内容を記述することで,JSLintによる構文チェックを有効化することができる。

let g:syntastic_mode_map = { 'mode': 'active',
      \ 'active_filetypes': ['javascript'],
      \ 'passive_filetypes': [] }
let g:syntastic_javascript_jslint_conf = "--white --undef --nomen --regexp --plusplus --bitwise --newcap --sloppy --vars"

 

コンソールによるエラーチェック

Firefoxを開いた状態で,MacではCommand + Alt + I,WindowsではCtrl + Shift + Iというショートカットキーを入力することで,デベロッパーツールを開くことができる。デベロッパーツールの中に,コンソールというメニューがあるので選択する。
 
Javascriptの構文にエラーがあり,Firefoxが解釈できない場合には,コンソールにエラーログが出力される。
 

Javascriptのデバッグ方法

Javascriptのデバッグには,主に以下の2つの方法が存在する。
 

console.log()によるデバッグ

console.log()というJavascriptの関数をJavascriptのソース内に記述しておくことで,Firefoxのコンソールに任意のログを出力することが出来る。
 
console.log()の使用例

console.log('犬可愛いよー!');

 

ブレークポイントによるデバッグ

FirefoxやGoogle Chromeには,Javascript実行時にブレークポイントを使用する機能が用意されている。
ブレークポイントを使用することで,Javascriptのコード上の任意の位置で処理を一時停止することができ,この状態で,一行ずつ処理を進めたり,変数の中身を監視することが出来る。
 
まずは,Firefoxを開いた状態で,MacならCommand + Alt + I,WindowsならCtrl + Shift + Iでデベロッパーツールを開く。ツールの中のデバッガを選択する。
次に,左側のペインに表示されているソースというタブの中のリストから,対象にしたいJavascriptファイルを選択する。
 
breakpoint_lecture_source_callstack
 
すると,真ん中のペインに,選択したJavascriptファイルのソースが表示される。ブレークポイントを設定するには,ブレークポイントを設定したい行の行番号をクリックする。
 
breakpoint_lecture_breakpoint
 
これでブレークポイントの設定が完了した。続いて,Command + RやF5キーなどでページの再読み込みを行う。
ページの再読み込みが完了すると,ブレークポイントを設定した行でJavascriptの処理が一時停止していることが確認できる。
 
この状態から処理を進めるには,ステップ移動を行う必要がある。ステップ移動には,ステップオーバー・ステップイン・ステップアウトの3つの移動方法が用意されており,いずれかの移動を手動で行う必要がある。
 
breakpoint_lecture_step
 
ステップオーバー・ステップイン・ステップアウトのそれぞれの意味について説明する。
 

ステップオーバー

現在の行を実行し、次の行に進める。もし現在の行に関数呼び出しがあったとしても関数へジャンプせずに関数の処理を行い、次の行に進む。
 

ステップイン

現在の行を実行し、次の行に進める。もし現在の行に関数呼び出しがあった場合、その関数にジャンプし、呼び出した関数の内部に進める。
 

ステップアウト

ステップインで,呼び出した関数の内部に進んだ場合,物凄く長い行の関数だった場合などに,その関数から抜けたいときに使用する。関数の最終行まで進める。
 
上記3つの移動方法を使って,ステップ移動を行いながら,右側のペインにて,各変数の中身を監視することが出来る。更に,変数の値をクリックすることで変数の値を書き換えることも出来る。
 
breakpoint_lecture_variables
 

コールスタックとウォッチ式について

ステップ移動と変数の監視以外に,重要な機能としてコールスタックとウォッチ式がある。長くなりそうなので,ここでは触り程度に説明する。
 
コールスタックとは,現在の関数がどこから呼ばれているかを教えてくれる機能である。ステップインやステップオーバーを多用していると,今どこにいるか分からなくなるときがある。そういったときは,これを見ることで,現在見ている行はどこから呼び出されたかを確認することが出来る。
 
ウォッチ式とは,ソース中の任意の変数をあらかじめ登録しておくことで,変数がスコープから外れてしまった場合でも監視を続けることが出来る機能である。Firefoxのデバッガは基本的には,現在の行のスコープにある変数,もしくはグローバルスコープしか監視してくれない。グローバルスコープから対象の変数を確認しても良いが,グローバルスコープ上から監視するのは非常に煩雑になっており,面倒である。なので,特定の変数を常に監視したいときには,ウォッチ式を使用する。
 
 
以上
 
 
参考
JavaScriptのデバッグ – ブレークポイントの使用 | CodeGrid

XSS脆弱性への対策方法について勉強した。サニタイズ言うなキャンペーンにも目を通した。Webアプリケーションのセキュリティに詳しい,高木浩光先生や徳丸浩先生の考え方を含めながら,まとめてみる。
 

XSSとは

ソフトウェアのセキュリティホールの一つで,Webサイトの訪問者の入力をそのまま画面に表示する掲示板などのプログラムが,悪意のあるコードを訪問者のブラウザに送ってしまう脆弱性のこと。
悪意を持ったユーザがフォームなどを通してJavaScriptなどのスクリプトコードを入力した時に,プログラム側に適切なチェック機構がないと,そのスクリプト内容がそのままHTMLに埋め込まれ,ページを閲覧したコンピュータでスクリプトが実行されてしまうことがある。
 

サニタイズとは

Webサイトの入力フォームへの入力データから,HTMLタグ,JavaScript,SQL文などを検出し,それらを他の文字列に置き換える操作のこと。「無害化」とも呼ばれ,サニタイジング操作により,入力データ中に含まれる悪意のあるHTMLタグ,JavaScript,SQL文などが解釈・実行されることを防ぐ。
 

サニタイズはするべきではない

ここまで見て,まず考えるのが「XSS対策としてサニタイズすれば良いのではないか」ということであるが,サニタイズはXSS対策の保険的なものであり,本来,サニタイズは推奨されない。
 
日本における「サニタイズ」という言葉の持つ意味やニュアンスを厳密に定義すると「入力処理で受け取ったデータに含まれる有害(別のリテラルで解釈可能)なメタ文字に対して,エスケープ処理を行うこと」となる。
ここで注意したいのは,「サニタイズ」は「バリデーション」とは全く異なるという点である。バリデーションを行うことは一般的なので,ここでは深く説明はしないが,「バリデーション」という言葉の定義は「入力処理で受け取ったデータに対して,データの妥当性をチェックすること」であり,サニタイズとは異なる。
 
では,何故サニタイズをしてはいけないのか,ということについての理由を説明する。まず,大前提として「サニタイズ」は間違った習慣が根付いてしまったものであり,本来は推奨されるべきではない,ということを念頭に置いてほしい。
 
サニタイズが推奨されないことには,以下の2つの理由がある。

  • プログラマの都合で,ユーザーが入力した内容を勝手に改変するべきではない
  • サニタイズが行われると,システムが汚染される

以下,それぞれの理由について説明する。
 

プログラマの都合で,ユーザーが入力した内容を勝手に改変するべきではない

いくらセキュリティ上の危険があるからといって,ユーザーが入力した内容を勝手に改変してよい理由はない。もし,メタ文字のエスケープが必要になる入力が行われたとしたら,それは本来はエラーにするべきである。
 

サニタイズが行われると,システムが汚染される

サニタイズは「スクリプトで受け取ったデータに含まれる,<>&"といったメタ文字を,JavaScriptのリテラルとして解釈できてしまう」という問題への付け焼刃的な対策方法である。だが,必ずしもXSSへの対策にサニタイズを行う必要はなく,出力処理で適切にエスケープ処理を行うことで,XSS脆弱性を回避することが可能である。
ここで大切なのは「サニタイズ」という言葉の定義を正しく理解することである。「サニタイズ」とは「入力処理で有害なメタ文字をエスケープ処理すること」である。「出力処理で有害なメタ文字をエスケープすること」を「サニタイズ」とは呼ばない。
 
ここで,どうして「入力処理」ではなく,「出力処理」でメタ文字をエスケープすることにこだわるのか,ということについて説明する。その理由は,メタ文字のエスケープ処理がシステムにもたらす「汚染」とも呼ぶべき影響範囲をなるべく小さくするためである。
 
ここでの「汚染」とは,入力データがエスケープ処理によって,本来のデータとは異なるデータに書き換えられることによって発生する,システムへの害のことを指す。
もし,入力処理でメタ文字のエスケープ処理を行った場合,エスケープ処理の影響は,システム内部やDBにまで波及する。つまり,システム内部やDBにて,エスケープ処理されたデータを,本来のデータに戻すための2次3次的な変更が発生することになる。
一方,出力処理でメタ文字のエスケープ処理を行った場合,エスケープ処理の影響はシステム内のどこにも波及することはない。
 
以上の理由から,XSS対策に,サニタイズ(入力処理でのメタ文字のエスケープ処理)は推奨されない。XSS対策には,出力処理でのメタ文字のエスケープ処理を行うべきである。
 

まとめ

  • サニタイズとは,「入力処理でメタ文字をエスケープすること」である
  • XSS脆弱性対策には,サニタイズは行わず,出力処理で適切にエスケープ処理を行う

 
 
以上
 
 
参考
クロスサイトスクリプティングとは 【 XSS 】 【 Cross Site Scripting 】 – 意味/解説/説明/定義 : IT用語辞典
サニタイジングとは 【 sanitizing 】 〔 サニタイズ 〕 – 意味/解説/説明/定義 : IT用語辞典
高木浩光@自宅の日記 – WASF Times版「サニタイズ言うな!」
XSS再入門
XSS: 今こそXSS対策についてまとめよう – 徳丸浩の日記(2008-08-22)

仕事でjQueryのグラフ描画に特化したプラグイン”jqplot”を使ったので、使い方を備忘録として書き留めておく。
環境としてはCakePHP2.2.2にjqplot1.0.4とjqplotに付属してきたjQueryを組み込んで使用した。
 
CakePHP2.xへの組み込み方としては、至極簡単な説明になってしまうが、jsフォルダ以下にjQueryとjqplotを配置し、Viewで以下のように読み込めば良い。

<?php echo $this->Html->script('jquery'); ?>
<?php echo $this->Html->script('jquery.jqplot'); ?>

 
jqplotはjQueryのプラグインという位置付けなので、使用する為にはjQuery本体の準備が必要である。
 

グラフを描いてみる

積み上げ棒グラフを描いてみた。これは、ゲームの継続率の詳細を表すと仮定した内容のグラフである。
棒グラフの上に継続率、棒グラフの色が継続率の分布、棒グラフの下に日付、折線が登録者数を表している。
積み上げ棒グラフ
 
以下、CakePHPに組み込んだ際のコードになる。分かり辛くなるのを避ける為に動的なコードは静的なものに置き換えてある。冒頭のjsファイルとcssの読み込みのパスさえ合っていれば、そのままコピペして使用可能である。
 

<?php echo $this->Html->css('jquery.jqplot'); ?>
<!--[if lt IE 9]><?php echo $this->Html->script('excanvas'); ?><![endif]-->
<?php echo $this->Html->script('jquery'); ?>
<?php echo $this->Html->script('jquery.jqplot'); ?>
<?php echo $this->Html->script('plugins/jqplot.barRenderer'); ?>
<?php echo $this->Html->script('plugins/jqplot.pointLabels'); ?>
<?php echo $this->Html->script('plugins/jqplot.highlighter'); ?>
<?php echo $this->Html->script('plugins/jqplot.cursor'); ?>
<?php echo $this->Html->script('plugins/jqplot.categoryAxisRenderer'); ?>
<script type="text/javascript">
$(document).ready(function() {
	//パーセンテージを表す積み重ね棒グラフの変数
	var p1 = [67, 50, 58, 40, 35, 33, 38, 2.76497]; //0%
	var p2 = [7, 5, 3, 9, 12, 12, 10, 7.83410];    //1~10%
	var p3 = [2, 3, 5, 6, 8, 6, 8, 9.67741];       //11~20%
	var p4 = [1, 7, 2, 7, 10, 8, 10, 12.90322];    //21~30%
	var p5 = [2, 6, 7, 12, 11, 14, 9, 16.12903];   //31~40%
	var p6 = [7, 5, 3, 4, 5, 2, 4, 13.82488];      //41~50%
	var p7 = [2, 3, 5, 3, 3, 4, 4, 11.98156];      //51~60%
	var p8 = [1, 7, 2, 4, 4, 3, 6, 9.67741];       //61~70%
	var p9 = [2, 6, 7, 9, 7, 9, 4, 6.45161];       //71~80%
	var p10 = [7, 5, 3, 5, 4, 4, 4, 5.52995];      //81~90%
	var p11 = [2, 3, 5, 1, 1, 5, 3, 3.22580];      //91~100%
	//日付ごとのユーザー数を表す線グラフの変数
	var sumUser = [
            [1, 40],
            [2, 21],
            [3, 820],
            [4, 60],
            [5, 80],
            [6, 90],
            [7, 100],
            [8, 110]
        ];

	// chart data 積み重ね棒グラフの継続率分布
	var dataArray = [
            p1,
            p2,
            p3,
            p4,
            p5,
            p6,
            p7,
            p8,
            p9,
            p10,
            p11,
            sumUser
        ];

	// x-axis ticks 登録日
	var xticks = [
            '12月',
            '1月',
            '02-01',
            '02-02',
            '02-03',
            '02-04',
            '02-05',
            '02-06'
        ];
	// x2-axis ticks 登録日ごとの継続率
	var x2ticks = [
            '12.65%',
            '9.82%',
            '7.65%',
            '9.2%',
            '8.4675%',
            '11.2525%',
            '12.5678%',
            '14.5432%'
        ];

	// chart rendering options
	var options = {
		stackSeries: true,
		title: '継続率',
		cursor: {
            show: true,
            zoom: false,
            looseZoom: false,
            showTooltip: false
        },
		legend: {
    		show: true,
    		location: 'ne',
    		placement: 'outsideGrid'
		},
		series: [
    		{label: '0%', useNegativeColors: false},
    		{label: '1~10%', useNegativeColors: false},
    		{label: '11~20%', useNegativeColors: false},
    		{label: '21~30%', useNegativeColors: false},
    		{label: '31~40%', useNegativeColors: false},
    		{label: '41~50%', useNegativeColors: false},
    		{label: '51~60%', useNegativeColors: false},
    		{label: '61~70%', useNegativeColors: false},
    		{label: '71~80%', useNegativeColors: false},
    		{label: '81~90%', useNegativeColors: false},
    		{label: '91~100%', useNegativeColors: false},
    		{
    			label: '登録者数',
    			disableStack : true,
    			renderer: jQuery.jqplot.LineRenderer,
    			lineWidth: 2,
    			pointLabels: {
					show: false
				},
				color: '#FF7D7D',
				markerOptions: {
					size: 5, color: 'red'
				},
				xaxis: 'x2axis', yaxis: 'y2axis'
    		}
		],
    	seriesDefaults: {
    		renderer:jQuery.jqplot.BarRenderer,
    		rendererOptions: {
                barWidth: 35,
                shadowAlpha: 0.03,
                fillToZero: true,
                highlightMouseOver: false
            },
    		pointLabels: {show: true}
    	},
    	axes: {
    		xaxis: {
    			label:"日付",
        		renderer: jQuery.jqplot.CategoryAxisRenderer,
        		labelOptions: {
                    fontSize: '20pt'
                },
        		ticks: xticks
			},
			x2axis: {
    			label:"継続率(%)",
        		renderer: jQuery.jqplot.CategoryAxisRenderer,
        		labelOptions: {
                    fontSize: '20pt'
                },
        		ticks: x2ticks
			},
			yaxis: {
				label:"継\n続\n率\n分\n布\n(%)",
				labelOptions: {
                    fontSize: '20pt'
                },
                tickOptions: {
					formatString: '%.2f%'
				},
            	min: 0,
            	max: 100,
            	numberTicks:11
            },
            y2axis: {
				label:"登\n録\n者\n数",
				labelOptions: {
                    fontSize: '20pt'
                },
                tickOptions: {
					formatString: '%d人'
				},
            	min: 0
            }
    	},
    	highlighter: {
            show: true,
            showLabel: true,
            tooltipAxes: 'y',
            sizeAdjust: 7.5 ,
            tooltipLocation : 'ne'
        }
	};

	jQuery.jqplot('graph', dataArray, options);
});
</script>
<div id="graph" style="height:600px;width:800px;margin:30px;">

 
 
以上
 
 
参考
jqPlot – jQuery プラグイン