はじめに
GAS(Google Apps Script)でWebアプリを作ると、innerHTML を使ってHTMLを動的に組み立てる場面がたくさんありますよね。
ReactやVueなら自動でエスケープしてくれますが、GASにはそういった仕組みがありません。ユーザーが入力したデータやスプレッドシートの値をそのままHTMLに埋め込むと、**XSS(クロスサイトスクリプティング)**という脆弱性が生まれてしまいます。
たとえば、スプレッドシートのセルに <script>alert('危険')</script> という文字列が入っていたら、それがそのまま実行されてしまう可能性があるということです。
この記事では、コピペですぐ使えるHTMLエスケープ関数を紹介します。GASでWebアプリを作るなら、必ずセットで用意しておきましょう。
こんな場面で使えます
- スプレッドシートのデータをHTML上にテーブル表示するとき
- ユーザーが入力したテキストを画面に表示するとき
innerHTMLで動的にHTMLを生成するすべての場面onclickなどのイベント属性に動的な値を埋め込むとき
実装コード
エスケープ関数
以下の関数をHTMLファイルの <script> タグ内に追加してください。
function escapeHtml(str) {
if (!str) return '';
return String(str)
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
やっていることはシンプルです。HTMLで特別な意味を持つ5つの文字(&、<、>、"、')を、それぞれ安全な文字参照に置き換えています。
使い方
変数をHTMLに埋め込むときは、必ず escapeHtml() で囲みます。
// NG: エスケープなし → XSS脆弱性
html += '<div>' + userData + '</div>';
// OK: エスケープあり → 安全
html += '<div>' + escapeHtml(userData) + '</div>';
onclick などの属性値に埋め込む場合も同様です。
// onclick属性にも使う
html += '<div onclick="fn(\'' + escapeHtml(value).replace(/'/g, "\\'") + '\')">';
使い方・カスタマイズ
どの変数にエスケープが必要?
基本ルールは「innerHTML に埋め込むすべての変数」です。迷ったらエスケープしておけば間違いありません。
| 場面 | エスケープ | 理由 |
|---|---|---|
| ユーザー入力値 | 必須 | 悪意ある入力の可能性がある |
| スプレッドシートの値 | 必須 | 誰がどんな値を入れるかわからない |
| 自分で定義した固定文字列 | 不要 | 内容が確定しているため |
| URLに埋め込む値 | encodeURIComponent() を使う | HTMLエスケープとは別の処理が必要 |
URLの中に値を埋め込む場合
HTMLエスケープとは別に、encodeURIComponent() を使います。
var url = 'https://example.com/search?q=' + encodeURIComponent(userInput);
html += '<a href="' + escapeHtml(url) + '">検索</a>';
URLを組み立ててから、さらにHTMLエスケープをかけるのがポイントです。
注意点・ハマりポイント
&の置換は必ず最初に行ってください。後から置換すると、<の&が&lt;に二重変換されてしまいますnullやundefinedが渡された場合に備えて、先頭でif (!str) return ''のチェックを入れています- この関数はあくまでHTML文脈でのエスケープです。SQLインジェクション対策にはなりません(GASではスプレッドシートが主なデータソースなのであまり心配はいりませんが)
まとめ
- GASのWebアプリでは自動エスケープがないため、HTMLエスケープ関数は必須
innerHTMLに埋め込む変数にはすべてescapeHtml()を適用する&の置換を最初に行う順番を守ることが重要
