kintacoです。自社のいいね!ボタンでは、反応したユーザーの表示名をHTMLへ差し込む前にエスケープしています。この記事では実コードのescapeHtmlをそのまま取り出し、文字列とHTMLの違いを確認します。
いいねの保存処理や、kintone REST APIは含みません。APIから取得した値だから、そのままHTMLとして扱ってよいわけではない、という点に絞った解説です。
textContentで表示できるなら、まず文字列として扱う
名前を表示するだけなら、DOM要素のtextContentへ設定すると、タグを文字として扱えます。HTMLテンプレートへ差し込む構成を使う場合は、差し込む文脈に合わせた処理が必要です。
以下はHTMLのテキスト部分向けのエスケープです。スクリプト、CSS、URL、イベント属性に使う汎用的な無害化関数ではありません。
function escapeHtml(str) {
return String(str)
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
&を先に置き換える
最初に&を置き換え、そのあと<・>・ダブルクオート・シングルクオートを置き換えます。あとから生成した<などの&まで再度変換しないための順番です。
console.log(escapeHtml('<管理者 & 担当者>'));
// <管理者 & 担当者>
同じ文字列へ二度適用すると、エンティティ中の&も変換されます。加工済みかどうか曖昧な値を何度も通すのではなく、元データを保持し、表示する直前に一度だけ変換します。
ユーザー名の表示と、ユーザーの識別を分ける
いいね済みかを判断する場合には、表示名ではなくユーザーコードを比較します。同じ表示名が複数存在したり、名前が変更されたりするからです。表示用テキストのエスケープだけで、ユーザーの一意性や編集権限が保証されるわけではありません。
保存の競合も別の問題
画面へ安全に文字を表示できても、複数人が同時にいいねを保存したときの競合は解決しません。レコード更新を実装する場合には、権限、取得と更新の間の変更、リビジョン指定、失敗後の表示を別に設計します。このサンプルに保存処理はありません。
確認したことと未確認のこと
特殊文字、複数の文字が混ざる場合、日本語、二重適用をNode.jsで確認しました。実ブラウザーでの攻撃コード実行テストや、kintoneでのいいね保存テストは含みません。テンプレートへ組み込む場合は、その出力箇所が本当にHTMLテキストの文脈かも確認してください。
ボタンと保存先を設定して使いたい場合
自社のいいね!ボタンプラグインの仕様・設定画面に、設定から利用する方法もまとめています。サンプルと製品版の対応範囲は異なります。
無料利用では、非契約ドメインのPC・モバイル一覧画面に有償プランの案内バナーが30%の確率で表示されます。契約済みドメインでは表示されません。一度閉じると、同じブラウザー・同じkintoneドメインでは、全Kintacoプラグイン共通で24時間非表示になります。
参考資料
製品仕様と実コードの確認元:LikeButton/src/js/desktop.js(1.0.6)。