『AngularJSリファレンス』ビルトインディレクティブ・DOM操作 の補足

AngularJSリファレンス

第2章はAngularJSに組み込みのディレクティブの解説なのだけど、ところどころ説明不足で疑問点を自分で調べる必要があったので、補足を書いてみる。

ngCloak

本書のサンプルコード(p.17)は↓のようになっているが、これだと<p ng-bind="myName"></p>との違いが分からない。

実際のところ、ngCloakはもっと汎用的に使える。たとえば、<body ng-cloak>としてやれば、AngularJSの処理が終わるまで一切画面が表示されない。より推奨される使い方としては、ngCloakを細かな単位に分割して適用し、処理が完了したところから表示していくほうが良い。たとえば、リストの描画完了に時間がかかるときに、リストにだけng-cloakを指定する等。

ngCloakの実際の処理の流れは以下のとおり。

  1. ngCloakが設定されている要素にはCSSでdisplay:noneが指定されるので、画面上には何も表示されない
  2. ngCloakを指定した要素がcompileされるタイミングでngCloakの指定が取り除かれ、画面上に要素が表示される

以下がソースだが、仕組みは超簡単。

ngCloakのソース(https://github.com/angular/angular.js/blob/master/src/ng/directive/ngCloak.js)

ng-repeat-start/end

本書(p.27)だと、

ng- repeat-start と ng-repeat-end で、明示的にループ開始と終了を宣言することも可能です

とあるのだけど、これだと何が嬉しいのか分かりづらい(私は分からなかった)。ng-repeat-start/endは、以下のように、複数要素に渡る繰り返しを実装したい時に使う(以下のコードだと、dtとddのペアが繰り返し表示される)。

ng-repeatだと、1要素の繰り返ししかできないけど、ng-repeat-start/endを使うと、dt+ddや、その他様々な組み合わせで要素を繰り返すことができる。

12/30 14:43 追記

動作確認のためjsFiddleのサンプルを追加。

クリックジャッキング対策について調べた

クリックジャッキングとは

クリックジャッキングとは、外見上は無害に見えるウェブページをクリックしている間にウェブ利用者をだまして秘密情報を露呈させる、あるいはウェブ利用者のコンピュータの支配を獲得する悪意の技術である

クリックジャッキング – Wikipedia

要はiframe等を使用してユーザーの意図したものとは異なるものをクリックさせる攻撃手法のこと。具体的な実装例は以下のサイトなどが参考になります。

http://hamachiya.com/junk/cj.html

「秘宝館A」ボタンの上には透明化されたFacebookの「いいね!」ボタンが配置されていて、「秘宝館A」を押すと「いいね!」されてしまう、というような仕組みです。

たとえば、SNSのプライバシー設定が勝手に変更されたりすると、困った事態になるかもしれません。

クリックジャッキングはiframeを利用して行うので、自分が作成しているWebサイトがクリックジャッキング対策を施していない場合、攻撃者によってiframeで表示されてしまうかもしれません。

クリックジャッキングを防ぐには

サイトのiframe内の埋め込みを制御する、「X-FRAME-OPTIONS」ヘッダを、HTTPヘッダに含めます。Microsoftが提案した、HTTPの標準にはないヘッダですが、現在の主要なブラウザであれば対応しています(IE8以降、Firefox 3.6以降、Chrome 4.1以降)。

X-FRAME-OPTIONS: DENYというHTTPヘッダを含むページは、iframe内に表示されません。また、X-FRAME-OPTIONS: SAMEORIGINを指定されたページは、「同一生成元(プロトコル・ホスト名・ポート番号が一致している)」という条件を満たす場合のみ、iframe内に表示可能です。

ちなみに、大手サイトだと、TwitterやAmazonはSAMEORIGIN、FacebookはDENY、楽天はログイン後のページ(ショッピングカート等)のみDENY、といった設定になっています。

具体的な設定方法は以下のとおりです。

1. Webサーバの設定を行う

ApacheやNginxといった、Webサーバのレベルで設定します。サイト全体で指定したい場合はこの方法が確実です。

以下はApache(2.2)の設定例です。

本ブログの場合、ブログ用のVirturlHostの設定の中で「Header always append X-Frame-Options SAMEORIGIN」を指定しています。

以下のようにiframeを使用することが可能ですが、別ドメインからiframeで表示することはできません。

DENYではなくSAMEORIGINにしているのは、使用中のWordpressプラグインの中にiframeを使用しているものがあり、DENYにすると一部プラグインが動かなくなってしまうからです。

2. (PHPの場合)header関数を使用してヘッダを出力する

プログラムでX-FRAME-OPTIONSヘッダを付け足してもOKです。1つ注意が必要なのは、X-FRAME-OPTIONSヘッダは、「厳しくするように上書きはできても、緩めることはできない」という点です。

http://ryo511.info/x_frame_options_sameorigin.phpでは、X-FRAME-OPTIONS: SAMEORIGINを指定しているサイト内で、X-FRAME-OPTIONS: DENYというヘッダを出力しています。

このページをiframeで表示しても、何も表示されません。

逆に、DENYを指定している場合に、SAMEORIGINで上書きしようとしても、DENYの方が優先されます。

参考文献

『PHP逆引きレシピ 第2版』p.782 を読んだのが、本記事を書くきっかけになりました。

PHP逆引きレシピ 第2版 (PROGRAMMER’S RECiPE)

IPAが公開している『クリックジャッキング』に関するレポート(pdf)が、クリックジャッキング関係の日本語文献としては最も充実した内容だと思います。攻撃手法から対策方法、対策を施すべきサイトの特徴から、X-FRAME-ORIGINSでは対応出来ない場合の対策まで載っています。

ちなみに、日本のPHP界では、セキュリティといえば「徳丸本」が定番ですが、本書のクリックジャッキング対策には誤りがあるので注意してください。

あの徳丸本にも間違いはある! 自分で確認することが大切です

AngularJSアプリケーション開発ガイド 第7章 その他の便利な機能 その3

AngularJSアプリケーション開発ガイド

cookie

AngularJSには$cookieと$cookieStoreというcookieを扱うためのサービスが用意されている。$cookieを使えばcookieに関する操作は全て行えるが、ほとんどの場合$cookieを直接扱う必要はない。

例えばcookieから検索履歴を取り出す場合、$cookieStoreを使うと以下のように書ける。

国際化とローカライズ

AngularJSで国際化とローカライズを行うには、以下の3ステップを行う。

  1. index.htmlの変更:AngularJSでは、サポートするロケール毎に個別のindex.htmlが必要とされる。
  2. ローカライズされたファイルの生成:サポートされるロケール毎にangular.jsを作成する。
  3. ローカライズ規則の読み込み:ローカライズされたindex.htmlがローカライズされたangular.jsを読み込むようにする。

考慮すべき点

  • 文字列の長さ
  • タイムゾーン

HTMLのサニタイズ

デフォルトの状態のAngularJSでは、HTMLのコンテンツをデータバインディングしようとするとエスケープされた上で表示される。

コンテンツをHTMLとして表示したい場合にあh、ng-bind-htmlディレクティブが利用できる。これは、ngSanitizeモジュールに含まれており、angular-sanitize.jsを読み込む必要がある。ng-bind-htmlでは、cssやjavascriptのコードは除去される。

本当にそのまま表示させたい場合には、ng-bind-html-unsafeディレクティブを使う。

linkyフィルタ

URLをリンクに変換するフィルタ。

URL部分にaタグが適用された状態で表示される。

AngularJSアプリケーション開発ガイド 第7章 その他の便利な機能 その2

AngularJSアプリケーション開発ガイド

AngularJSのモジュールのメソッド

AngularJSにはmainメソッドはない。代わりに存在するのが、モジュール。モジュールを使うと、アプリケーションの依存先や起動の手順を宣言的に指定できる。このようなアプローチが取られている理由は以下。

  • 宣言的であること。記述も理解も容易。
  • モジュール性が高いこと。開発者にコンポーネントや依存先の明確な定義を迫る。
  • テストが容易である。ユニットテストとシナリオテストが容易に実施できる。

サービス、ディレクティブ、フィルタのそれぞれについて個別にモジュールを定義することが推奨される。メインのモジュールでは、他のモジュールを依存先として指定する。こうすることで、モジュールが適度なサイズの完結したコードになり、管理やテストが用意になる。

読み込みと依存先の指定

モジュールの読み込みは、configとrunの2段階で行われる。

configブロック:すべてのプロバイダーを読み込み登録する。

runブロック:アプリケーションを起動する。

便利なメソッド

メソッド 説明
config モジュールの読み込み中に必要な処理を登録する
constant アプリケーション全体で有効な定数を宣言する
controller コントローラのセットアップを行う
directive ディレクティブを作成する
filter フィルタを作成する
run DIがセットアップされた後で、かつユーザーがアプリケーションを利用できるようになる前に行いたい処理を指定する
value アプリケーションに何らかの値を注入する

$on, $emit, $broadcastを使ったスコープ間の通信

AngularJSのスコープには階層的な入れ子構造が見られる。1つのAngularJSアプリケーションごとに、メインとなる$rootScopeが1つ用意される。他の$scopeはすべて、子のスコープを継承するか入れ子状に包含される。

$scope同士が互いに変数を共有せず、プロトタイプによる継承関係も持たない場合に、$scopeの間でやり取りを行うには、$scopeの中で発生するイベントを利用する。

イベントオブジェクトのプロパティとメソッドは以下。

名前 意味
event.targetScope イベントが発生あるいは一斉通知された元の$scope
event.currentScope 現在このイベントを処理している$scope
event.name イベントの名前
event.stopPropagation() イベントの以降の伝播を止める
event.preventDefault() defaultPreventedにtrueをセットする
event.defaultPrevented preventDefautが呼び出されている場合はtrue

次回は7.4 cookieから。

AngularJSアプリケーション開発ガイド 第7章 その他の便利な機能 1 $location

AngularJSアプリケーション開発ガイド

$location

$locationサービスは、window.locationをラップしたものである。$locationを利用する利点は以下のとおり。

  • 内部状態のグローバルな管理が不要
  • APIの提供
  • AngularJSとの統合
  • HTML5との統合

URLの変化に応答したい場合や、現在のURLを変化させたい場合にはいつでも$locationサービスを利用すべき。

$scope.apply()をいつどのように呼び出すべきかについては、ポイントが4つある。

  1. いつでも呼び出してよいというわけではない。行うべき処理がない場合に呼び出すと、例外が発生する。
  2. AngularJSの外側にあるコードがAngularJSの機能を利用している場合には、$scope.apply()を呼び出すべき。
  3. 可能なら、関数あるいはコードを実行してから$scope.apply()を呼び出すのではなく、その関数を$scope.apply()に渡すようにすべき。
  4. safeApplyなどの利用を検討する。

HTML5モードとHashbangモード

$locationサービスの設定は$locationProviderを通じて行う。$locationProviderには重要なプロパティが2つある。

  1. html5Mode
  2. hashPrefix

HTML5モードでは、HTML5のHistory APIを使ってブラウザ上のURLを操作する。$locationサービスはHTML5モードがサポートされているかどうかを自動的に判定し、未対応の場合はHashbangを使ったアプローチに切り替える。

以下の点に注意が必要。

  • サーバ側の設定:AngularJS上で使用されるURLに直接アクセスした場合のリダイレクト設定を行う
  • リンクの書き換え(以下のようなリンクの指定を行うとページが再描画される)
    • target属性が指定されている場合
    • 他のドメインへの絶対リンク
    • すでに定義されているものとは異なるベースURLからのリンク
  • 相対リンク:相対URLはHTMLの絶対URLを基準として解釈されるが、この絶対URLはアプリケーションが置かれたルートディレクトリとは異なることがある

AngularJSアプリケーションを実行する際には、ドキュメントルートを起点としてHistory APIを利用することが強く推奨される(相対リンクに関する問題がすべて解消されるため)。

次回は「AngularJSのモジュールのメソッド」から。