【ServiceNow】HTMLサニタイジング関連のシステムプロパティをまとめてみた

:::note info
この記事は [ServiceNow アドベントカレンダー 2024](https://qiita.com/advent-calendar/2024/servicenow) の12月17日分の記事として執筆しています。
:::

https://qiita.com/advent-calendar/2024

## はじめに
### この記事の目的
- ServiceNowの中で、クロスサイトスクリプティング（以下、XSS）対策に利用されている、いくつかのプロパティの意味を備忘も兼ねてまとめます

### 対象読者
- ServiceNow開発に携わる人
- ServiceNow開発に興味がある人

## XSSのざっくりとした説明
前段として、XSSを画像付きでざっくりと説明します。

XSSの被害例として例えば「不特定多数のユーザーが利用する掲示板やブログのコメント欄でのXSSの埋め込み」が挙げられます。

以下のコメント欄は私が[codepen.io](https://codepen.io)というサイトで適当に作ったものなのですが、ここではHTMLタグのエスケープ処理は全くしていないため`HTMLインジェクション`攻撃が可能です。

したがって、このコメント入力欄に第三者が**悪意のあるスクリプト**を投稿することで、ページ内の過去コメント欄に**悪意のあるスクリプト**が残り続け、次にこのページを訪問した人に**悪意のあるスクリプト**を実行させることが可能となります。

▼何もセキュリティ対策がされていない、XSSに対して脆弱性のあるコメント欄
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3866035/2d32a6d3-7feb-bbc0-98e6-1bee8fe25f37.png" width=50%>

▼第三者が悪意のあるスクリプトをコメント欄に入力した結果、スクリプトが読み込まれる
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3866035/9cbb690b-5977-404b-17ef-04acfde4b892.png" width=50%>

▼さらに、挿入された`onload`イベントハンドラが起動して別の危険なURLに飛ばされる
![スクリーンショット 2024-12-16 18.36.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3866035/df377a8b-f8dd-2a60-1916-aa0f65baef2b.png)

上図の例だと、コメント欄で`iframe`タグを利用して、**悪意のあるスクリプト**の実行と**危険なURL**への自動遷移の処理をさせられているのがわかります。XSSには種類があり、こうしたタイプのXSSを **格納型XSS(Stored-XSS)** と呼びます。他にも色々種類があるので、興味のある方は調べてみてください。

<br>

これで、XSSに馴染みのない方もこの記事がどういうトピックなのかが大体わかったかなと思います。
ServiceNowでもあらゆるXSS対策が行われているのですが、システムプロパティ化されXSS対策の強度や対象範囲をユーザー側で定義できるものもあります。
この記事では、そのシステムプロパティの一部をできるだけわかりやすく紹介したいと思います。

## 本編
:::note warn
この記事は2024年12月（Xanaduバージョン）時点のものです。
:::

|#| プロパティ名 | 説明 |
|:--|:--|:--|
|1| glide.ui.security.allow_codetag | [埋め込み HTML コードを許可する](https://www.servicenow.com/docs/ja-JP/bundle/xanadu-platform-security/page/administer/security/reference/allow-embedded-html-code.html)  |
|2| glide.ui.security.codetag.allow_script  | [埋め込み HTML で JavaScript タグを許可する](https://www.servicenow.com/docs/ja-JP/bundle/xanadu-platform-security/page/administer/security/reference/allow-javascript-tags-in-embedded-html.html)  |
|3| com.glide.security.check_unsanitized_html   | [サニタイズされていない HTML の確認](https://www.servicenow.com/docs/ja-JP/bundle/xanadu-platform-security/page/administer/security/reference/check-unsanitized-html.html)|
|4| glide.ui.escape_html_list_field  | [リストビューでの HTML をエスケープ](https://www.servicenow.com/docs/ja-JP/bundle/xanadu-platform-security/page/administer/security-center/reference/sc-escape-html.html)  |
|5| glide.html.escape_script  | [JavaScript のエスケープ](https://www.servicenow.com/docs/ja-JP/bundle/xanadu-platform-security/page/administer/security/reference/escape-javascript.html)  |
|6| glide.html.sanitize_all_fields  | [HTML サニタイザー](https://docs.servicenow.com/ja-JP/bundle/xanadu-platform-security/page/administer/security/reference/html-sanitizer.html)  |

### 1. glide.ui.security.allow_codetag
- デフォルト値：`true`
- 推奨値：`false`（デフォルト値と異なります）
- 公式ドキュメント：[埋め込み HTML コードの許可 (インスタンスセキュリティ強化)](https://www.servicenow.com/docs/ja-JP/bundle/xanadu-platform-security/page/administer/security/reference/allow-embedded-html-code.html)

#### プロパティの説明
このプロパティを`true`にすると、作業メモや追加コメントで`[code]`タグを利用してHTMLを埋め込むことができます。試しに、プロパティ値`true`で以下のテストケースを入力してみます。
- ケース１：`[code]`タグ**なし**で`<b>`タグを打ち込み
- ケース２：`[code]`タグ**あり**で`<b>`タグを打ち込み
- ケース３：`[code]`タグ**あり**で`<a>`タグを打ち込み
- ケース４：`[code]`タグ**あり**で`<script>`タグを打ち込み

▼作業メモで以下のテストケースを入力
![スクリーンショット 2024-11-16 18.42.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3866035/421bef90-e300-6784-0731-8329a2a0bbe7.png)

すると、以下のような挙動となります。

▼プロパティ値`true`の場合での表示
![スクリーンショット 2024-11-16 18.43.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3866035/91e07e30-96f4-c585-83ab-4a8a4ad7ea13.png)

一方で、プロパティ値`false`に変更すると以下のような挙動となります。

▼プロパティ値`false`の場合での表示
![スクリーンショット 2024-11-16 18.44.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3866035/220b1e8c-0051-edc8-7a69-4f0f999b9a68.png)

このように、`glide.ui.security.allow_codetag`のプロパティ値を`true`に設定することで **[code]タグで囲われたHTMLタグはエスケープされなくなり、`b`タグでテキストを太字にしたり、`a`タグでリンクを貼り付けたりすることが可能**となります。
ただしケース４を見ての通り、 **`script`タグはXSSに悪用されるリスクが非常に高いため、本プロパティと併せて`glide.ui.security.codetag.allow_script`も`true`に設定しないと利用できません。** （後者のプロパティは`true`設定できないように制限がかかってるんですけどね。）

<br>

他にも、このプロパティによって影響を受けるケースがいくつか存在します。
例えば、問題管理のOOTB$^※$ UIアクション「Communicate Workaround」が一例として挙げられます。
$^※$OOTB（Out-of-the-Box）：インスタンス購入時のベースライン機能のこと

▼問題管理フォームの「Workaround」フィールドにHTMLテキストを記載して、関連リンクの「Communicate Workaround」を押下
![スクリーンショット 2024-11-16 19.09.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3866035/ad861a85-c040-3eb3-9a69-f4d7a6d20ba5.png)
![スクリーンショット 2024-11-16 19.12.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3866035/900513ce-4383-9e53-031b-51369848b4e8.png)

▼プロパティ値`true`の場合での表示（インシデント管理に連携された画面）
![スクリーンショット 2024-11-16 19.15.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3866035/92020632-c9f1-3d25-6c55-0473719d9c1d.png)

▼プロパティ値`false`の場合での表示（インシデント管理に連携された画面）
![スクリーンショット 2024-11-16 19.13.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3866035/59517853-e312-36a0-a56a-815c46c7578d.png)

この挙動は、HTMLテキストを作業メモに転記する他のUIアクションにも共通します。

HTMLタグをそのまま表示させることは、利用者のUI/UXを大きく損なう可能性があります。前述の通り、危険性の高い`script`タグは本プロパティを`true`にするだけではレンダリングされないので、それほどセキュリティを厳密にする必要がない限りはUI/UXを優先して本プロパティを`true`に設定しておくのがよいかもしれません。

### 2. glide.ui.security.codetag.allow_script
- デフォルト値：`false`
- 推奨値：`false`
- 公式ドキュメント：[埋め込み HTML で JavaScript タグを許可する](https://www.servicenow.com/docs/ja-JP/bundle/xanadu-platform-security/page/administer/security/reference/allow-javascript-tags-in-embedded-html.html)

#### プロパティの説明
このプロパティを`true`にすると、作業メモや追加コメントで`[code]`タグを利用して`script`タグを埋め込むことができます。
とはいえ、Xanaduバージョンのインスタンスでこのプロパティ値を`true`にしようとしても、以下のようにアラートが表示され変更できないようになっています。また、プロパティレコードの削除もできないようになっています。

▼システムプロパティ定義にて、プロパティ値を`true`に変更しようとした画面
![スクリーンショット 2024-11-16 19.38.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3866035/cf7ff61a-bb6b-b0f4-81c9-a9d844c98885.png)

推奨値も`false`となっています。
業務で作業メモや追加コメントに`<script>`タグを埋め込む必要性は普通ないですし、あくまで「こういうプロパティがあるんだ」とご理解いただくだけでよいかと思われます。

### 3. com.glide.security.check_unsanitized_html
- デフォルト値：`enforce`
- 推奨値：`enforce`
- 公式ドキュメント：[サニタイズされていない HTML の確認 (インスタンスセキュリティ強化)](https://www.servicenow.com/docs/ja-JP/bundle/xanadu-platform-security/page/administer/security/reference/check-unsanitized-html.html)

#### プロパティの説明
このプロパティを`enforce`にすると、「翻訳されたHTML」タイプのフィールドにおいて、特定のHTMLタグにサニタイズが適用され使用できなくなります。

▼「翻訳されたHTML」タイプのフィールドの一例（「cmdb_ci_service」テーブルの「Service level requirement」フィールド）
![スクリーンショット 2024-11-16 20.27.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3866035/5b354343-b304-09e8-091c-e35d42ada2e6.png)

こちらも`glide.ui.security.codetag.allow_script`同様に、Xanaduバージョンのインスタンスでこのプロパティ値を`true`にしようとしても、以下のようにアラートが表示され画面から変更できないようになっています。また、プロパティレコードの削除もできないようになっています。

▼システムプロパティ定義にて、プロパティ値を`disable`に変更しようとした画面
![スクリーンショット 2024-11-16 19.48.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3866035/f79360b9-018a-eb3e-a54b-96e8e6d6a242.png)

公式ドキュメントを読む限り、利用の少ない「翻訳されたHTML」フィールドでのみ適用されるプロパティであり、インスタンスユーザーがプロパティ値を変更することもできないのであまり気にしなくてもよいものと思われます。
よりわかりやすい説明が[コミュニティサイト](https://www.servicenow.com/community/now-platform-forum/is-the-quot-check-unsanitized-html-quot-feature-mentioned-in/m-p/1051747)にありましたので、気になった方はご参照ください。

### 4. glide.ui.escape_html_list_field
- デフォルト値：`true`
- 推奨値：`true`
- 公式ドキュメント：[リストビューでの HTML をエスケープ](https://www.servicenow.com/docs/ja-JP/bundle/xanadu-platform-security/page/administer/security-center/reference/sc-escape-html.html)

#### プロパティの説明
このプロパティを`true`にすると、リストビュー画面で強制的にHTMLがエスケープされます。

▼問題のリストビュー画面にて、ワークアラウンド（HTMLフィールド）の内容を表示
![スクリーンショット 2024-12-16 15.36.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3866035/0ab4859e-1b18-007b-fe77-f794883462ed.png)

なお、こちらも画面から変更・削除できないようになっていました。

▼システムプロパティ定義にて、プロパティ値を`false`に変更しようとした画面
![スクリーンショット 2024-11-16 20.42.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3866035/5c704eb7-5627-ef49-7217-493895ab0804.png)

### 5. glide.html.escape_script
- デフォルト値：`true`
- 推奨値：`true`
- 公式ドキュメント：[JavaScript のエスケープ](https://www.servicenow.com/docs/ja-JP/bundle/xanadu-platform-security/page/administer/security/reference/escape-javascript.html)

#### プロパティの説明
このプロパティを`true`にすると、リストビュー画面でHTMLフィールドの`<script>`タグがエスケープされます。
`glide.ui.escape_html_list_field`の効果を`script`タグに絞ったものというイメージです。

なお、こちらも画面から変更・削除できないようになっていました。

▼システムプロパティ定義にて、プロパティ値を`false`に変更しようとした画面
![スクリーンショット 2024-11-29 20.21.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3866035/3d852977-8ed5-ade1-d8a1-07614fa8d11b.png)

### 6. glide.html.sanitize_all_fields
- デフォルト値：`true`
- 推奨値：`true`
- 公式ドキュメント：[HTML サニタイザー](https://docs.servicenow.com/ja-JP/bundle/xanadu-platform-　　　/page/administer/security/reference/html-sanitizer.html)

#### プロパティの説明
このプロパティを`true`にすると、すべてのHTMLフィールドでHTMLタグのサニタイズ評価がされます。サニタイズ評価の基準は、`HTMLSanitizerConfig`スクリプトインクルードにて **ホワイトリスト** と **ブラックリスト** の形式でユーザー側で定義することが可能です。当該スクリプトインクルードにて、ホワイトリストは`HTML_WHITELIST`クラス、ブラックリストは`HTML_BLACKLIST`クラスで定義します。

▼`HTMLSanitizerConfig`スクリプトインクルード画面
![スクリーンショット 2024-11-29 21.08.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3866035/e76f06d3-244a-446a-78cc-bcf26c0e9107.png)

<br>

具体例を見てみましょう。
まずはOOTBの設定で問題管理の「Workaround」（HTMLフィールド）に`iframe`タグを埋め込んでみます。

▼OOTBの設定でHTMLフィールドに`iframe`タグを埋め込んでみる（保存前）
![スクリーンショット 2024-12-16 16.21.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3866035/38dc1029-1103-0489-4f8b-9f6a7ecce0d3.png)
![スクリーンショット 2024-12-16 16.21.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3866035/381f6d74-add7-a075-8681-927b05cbbecc.png)


どうやらServiceNowのHTML Sanitizeスクリプトインクルードはレコードの保存・更新時に実行されているらしく（[ソース](https://www.servicenow.com/community/developer-forum/help-with-html-sanitization/m-p/2750962)）、保存前は`iframe`で外部のページが参照できるようなのですが、保存後は以下の通り`src`属性がサニタイズされ、`iframe`の枠だけ残っている状態となります。

▼OOTBの設定でHTMLフィールドに`iframe`タグを埋め込んでみる（保存後）
![スクリーンショット 2024-12-16 16.21.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3866035/93803cf2-56e2-46b6-1e6b-5674b4140d37.png)
![スクリーンショット 2024-12-16 16.22.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3866035/d21c6e39-71b8-adfa-68e3-749e79c75796.png)

次に、**`iframe`をタグをブラックリストに入れるとどうなるのか** 検証をしましょう。
下図のようにHTML Sanitize スクリプトインクルードのブラックリスト設定を変更します。

▼`HTMLSanitizerConfig`スクリプトインクルード画面
![スクリーンショット 2024-12-16 17.13.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3866035/afe07c87-afff-fdb1-11c1-e9cf73496c2a.png)

そうすると、`iframe`タグを打ち込んで保存した時の挙動が先ほどとは異なり、`src`属性だけではなく`iframe`タグが丸ごとサニタイズされます。

▼`iframe`タグをブラックリストに登録した上でHTMLフィールドに埋め込んでみる（保存後）
![スクリーンショット 2024-12-16 16.24.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3866035/8ae9d685-84f9-522b-84b6-cbfac23ac159.png)
![スクリーンショット 2024-12-16 16.24.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3866035/dc3d119f-1e59-5988-3562-d63ad07fbb24.png)


以上の検証で、確かに本プロパティおよび`HTMLSanitizerConfig`スクリプトインクルードが期待通りに動くことが確認できました。`strong`タグなどの無害なタグはブラックリストに入れてもそのまま利用できたり、`src`属性はブラックリストに入れてなくてもサニタイズされたりと気になる点はあるのですが、それらは別で管理するプロパティがあるか、内部でよしなに設定されているのでしょう。これ以上の深掘りは一旦やめておきます。（奥が深すぎて時間がいくらあっても足らない）

なお、サニタイズの履歴は`https://[インスタンス名].service-now.com/syslog_list.do?sysparm_query=source%3DHTMLSanitizer`にレコードとして残っておりいつでも内容を確認できます。

<br>

変更・削除についてはこちらも画面からはできないようになっていました。

▼システムプロパティ定義にて、プロパティ値を`false`に変更しようとした画面
![スクリーンショット 2024-11-29 21.00.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3866035/1fed69be-7921-3ff7-a8c9-c600b9e54de3.png)

完全に余談ですが、個別のHTMLフィールドにサニタイズする/しないを設定したい場合、本プロパティを`false`に設定した上で、サニタイズしたい特定のフィールドにのみ`html_sanitize`属性を`true`に設定する必要があります。[公式ドキュメント](https://www.servicenow.com/docs/ja-JP/bundle/vancouver-platform-security/page/administer/security/task/t_EnSanitizIndFlds.html)

▼辞書レコードで`html_sanitize`属性を設定できる
![スクリーンショット 2024-12-16 16.50.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3866035/e6c9cdfd-93a1-c2c1-fa5a-b398f7990771.png)


## おわりに
ServiceNowアドベントカレンダー大会は初参加なので、もし分かりにくいところあれば申し訳ありません。SNUGユーザー会にてオンサイトでお会いした方々はありがとうございました^-^
もし間違い等あれば、ぜひコメントで教えてください。


## 参考文献（公式Docsやコミュニティサイト以外）
・XSS（クロスサイトスクリプティング）とは？攻撃手法と5つの対策を紹介

https://www.gmo.jp/security/cybersecurity/cyberattack/blog/xss/

・XSSと、XSSの種類について

https://qiita.com/miya_zato/items/7ea57326c86a198fcf08