AEM開発者ブログ by YAMATO

アドビ社のデリバリーパートナー大和株式会社のAEM開発者ブログです。

HTL - Display Context 記法と出力の例

AEM Developerの皆様お疲れさまです。大和株式会社の狩野です。

前回の更新から時間が空いてしまいましたが、今回はDisplay Contextについて書こうと思います。

HTLに文字列を出力するときに、XSS対策に適切なエスケープをしたりしなかったりするために必要な引数がDisplay Contextです。
英語での情報だったり、簡単な説明はすでにあったりするのですが、日本語の情報やどういう入力でどういう出力がされるのかという実例を挙げたサイトは見つからなかったので、今回書いてみることにしました。 参考になりましたら幸いです。

記法

${properties.jcr:title @ context='html'}

この context='' の右辺を様々な文字列に変えることで出力したい文字列によってエスケープの有無を切り替えることができます。

それぞれの出力の例

html

HTMLを出力する時に使用する。
デフォルト(context=に何も設定しない場合)では、HTMLタグを出力しようとすると <>&lt;&gt; に変わります。

HTLの記載

${'<div>html</div>' @ context='html'}

実際の出力

<div>html</div>

text

テキストを出力する時に使用する。
デフォルトと同じものを出力するが、明示的に「デフォルトの状態で表示する」と示したい時や、他のcontextと条件分岐する場合に用いる。

HTLの記載

${ '<div>html & " \'</div>' @ context='text' }

実際の出力

&lt;div&gt;html &amp; &#34;&#34; &#39;&lt;/div&gt;

elementName

HTMLタグを出力(data-sly-element)する時に、XSSの可能性があるHTMLタグの出力を抑制する。
以下のHTMLタグのみを許可する。

section, nav, article, aside, h1, h2, h3, h4, h5, h6, header, footer, address, main, p, pre, blockquote, ol, li, dl, dt, dd, figure, figcaption, div, a, em, strong, small, s, cite, q, dfn, abbr, data, time, code, var, samp, kbd, sub, sup, i, b, u, mark, ruby, rt, rp, bdi, bdo, span, br, wbr, ins, del, table, caption, colgroup, col, tbody, thead, tfoot, tr, td, th

こちらも、 context='text' と同じく、data-sly-elementのデフォルトと同じ出力になるが、明示的にしたい時や、他のcontextと条件分岐する場合に用いる。

HTLの記載

<div data-sly-element="${ 'script' @ context='elementName' }"> html </div>
<div data-sly-element="${ 'h1' @ context='elementName' }"> html </div>

実際の出力

<div> html </div>
<h1> html </h1>

attributeName

HTMLタグの属性の名前を出力(data-sly-attribute)する時に、XSSの可能性がある属性の出力を抑制する。
具体的には style, on* という文字列の出力を抑制する。
onClick などの実際に効力を発揮するような on から始まる文字列だけでなく、 onAAA など意味がない文字列の出力も抑制する。

こちらも、 context='text' などと同じく、data-sly-attributeのデフォルトと同じ出力になる上、 context='unsafe' にしてもこのstyle属性やon*属性は出力されない。 だったらこれいらなくない?

HTLの記載

<!--/* foobar = {'style': 'display: none;'} */-->
<div data-sly-attribute="${ foobar @ context='attributeName' }"> html </div>
<!--/* foobar = {'onAAA': 'bar'} */-->
<div data-sly-attribute="${ foobar @ context='attributeName' }"> html </div>
<!--/* foobar = {'id': 'foo'} */-->
<div data-sly-attribute="${ foobar @ context='attributeName' }"> html </div>
<div>${ 'onClick' @ context='attributeName' }</div>

実際の出力

<div> html </div>
<div> html </div>
<div id="foo"> html </div>
<div></div>

attribute

HTMLタグの属性内で特殊な意味を持つ文字をエスケープする。
ほとんど context='text' と変わらない気がする
一応、 >< という文字列を出力する時、 < だけがエスケープされ >&lt; という出力になるという違いはある。

HTLの記載

<div>${ '\'"><&' @ context='attribute' }</div>

実際の出力

<div>&#39;&#34;>&lt;&amp;</div>

uri

URLに使われた時、XSSのリスクがある文字に対してURLエンコードを行う。

HTLの記載

<div>${ 'https://ja.wikipedia.org/wiki/&v=<script></script>' @ context='uri' }</div>

実際の出力

<div>https://ja.wikipedia.org/wiki/&v=%3Cscript%3E%3C/script%3E</div>

scriptToken

Javascriptコード上で使われると意味のある記述を出力しない。

HTLの記載

<div>${ '+-*=/{}"\'$#' @ context='scriptToken' }</div>
<div>${ '1+2' @ context='scriptToken' }</div>
<div>${ 'var a = 1;' @ context='scriptToken' }</div>

実際の出力

<div></div>
<div></div>
<div></div>

scriptString

scriptタグ内でJavascriptの文字列を出力する時に使用する。
デフォルトでは、scriptタグ内で文字列を出力しようとした場合、出力が行われない。

HTLの記載

<script>
    var a = "${ '123' }";
</script>
<script>
    var a = "${ '123' @ context='scriptString' }";
</script>

実際の出力

<script>
    var a = "";
</script>
<script>
var a = "123";
</script>

scriptComment

Javascriptのブロックコメント内で文字列を出力する時に使用する。
デフォルトではブロックコメント内で文字列の出力することは出来ない。

HTLの記載

<script>
    /* ${ 'aaa' @ context='scriptComment' } */
</script>

実際の出力

<script>
    /* aaa */
</script>

scriptRegExp

Javascriptの正規表現を出力する時に使用する。

HTLの記載

<script>
    var pattern = ${ '/^\\d{3}-?\\d{4}$/g' @context='scriptRegExp' };
</script>

実際の出力

<script>
    var pattern = /^\d{3}-?\d{4}$/g;
</script>

styleToken

CSSコード上で使われると意味のある文字列を出力しない。

HTLの記載

<div>${ 'display: none;' @ context='styleToken' }</div>

実際の出力

<div></div>

styleString

styleタグ内でCSSの文字列を出力したい時に使用する。
デフォルトではstyleタグ内で文字列を出力することは出来ません。

HTLの記載

<style>
    .abc {
        width: ${ '220px' @ context='styleString' }
    }
</style>

実際の出力

<style>
    .abc {
        width: 220px
    }
</style>

styleComment

context=scriptComment と同様に、styleタグ内でのブロックコメントを出力する時に使います。
デフォルトではstyleタグ内のブロックコメントに文字列を出力することは出来ません。

HTLの記載

<style>
    /* ${ 'aaa' @ context='styleComment' } */
</style>

実際の出力

<style>
    /* aaa */
</style>

comment

HTMLコメント内で文字列の出力を行う時に使用する。
ただし、HTMLコメント内で文字列の出力を行った場合、暗黙のうちに context=comment が使われる。

HTLの記載

<!-- ${ 'aaa!--<>\'&"' @ context='comment' } -->

実際の出力

<!-- aaa!--&lt;&gt;&#39;&amp;&#34; -->

number

出力する対象が数字ではない場合、0を出力する。

HTLの記載

<div>${ 'aaa' @ context='number' }</div>
<div>${ '12345' @ contex='number' }</div>

実際の出力

<div>0</div>
<div>12345</div>

unsafe

一切のエスケープや非表示を行わずに全てをそのまま出力する。

HTLの記載

<div>${ '<script>alert("abc")</script>' @ context='unsafe' }</div>

実際の出力

<div><script>alert("abc")</script></div>

最後に

以上となります。 この記事を書くにあたって、自分でも知らない内容が多く勉強になりました。

参考資料

HTML Template Language Specification