dポイントプレゼントキャンペーン実施中!

JavascriptのXSS対策として以前アドバイス頂いたようにinnerHTMLでHTMLのエスケープ処理コードを書いてみたのですが、正しいのか分かりませんアドバイスお願い致します。

Document.createTextNodeを代用する方法もアドバイス頂いたので考えてみたのですが、使い方が難しく既存のHTMLにあっているのか心配です…

※アドバイス頂いた質問
https://oshiete.goo.ne.jp/qa/13578040.html

※名前HTML
<div class="msg_partial">あと<strong>50</strong>文字</div>

※コメントHTML
<div class="msg_partial">あと<strong>500</strong>文字</div>

※該当コード

<h2>名前<span class="required">※必須</span></h2>
<input class="length_input" data-maxlength="<?php echo MAX_LENGTH::NAME; ?>" type="text" name="namae" id="name" placeholder="未入力の場合は、匿名で表示されます" value="<?php echo $namae; ?>">
<div class="msg_partial"></div>

<h2>コメント<span class="required">※必須</span></h2>
<textarea class="length_input" data-maxlength="<?php echo MAX_LENGTH::MESSAGE; ?>" name="message" id="message" placeholder="荒らし行為や誹謗中傷や著作権の侵害はご遠慮ください"><?php echo $message; ?></textarea>
<div class="msg_partial"></div>

※エスケープ処理を追加
function lengthCheck() {
const left = this.dataset.maxlength - this.value.length;
if (left >= 0) {
const a = document.querySelectorAll('msg_partial');
return a.innerHTML;
this.nextElementSibling.innerHTML = '<strong>' + escapeHTML(left) + '</strong>文字';
this.dataset.submit_disabled = this.value.length === 0;
} else {
const b = document.querySelectorAll('msg_partial');
return b.innerHTML;
this.nextElementSibling.innerHTML = '<strong>' + escapeHTML(-left) + '</strong>文字超過しています';
this.dataset.submit_disabled = true;
}

_________________________________________________________

※Document.createTextNodeを利用したもの
<script>
function lengthCheck(text) {
const newtext = document.createTextNode(text);
msg_partial = document.querySelectorAll("msg_partial");

const left = this.dataset.maxlength - this.value.length;
if (left >= 0) {
this.nextElementSibling.innerHTML = 'あと<strong>' + addTextNode('left') + '</strong>文字';
this.dataset.submit_disabled = this.value.length === 0;
} else {
this.nextElementSibling.innerHTML = '<strong>' + addTextNode('-left') + '</strong>文字超過しています';
this.dataset.submit_disabled = true;
}

msg_partial.appendChild(newtext);
}
</script>

A 回答 (2件)

セキュリティ云々以前の問題として、動くかどうかデバッグ確認をしましょう。

いまのままでは「コードのように見えるなにか」でしかないので評価以前の問題です。

XSS の根本的解決とは、「全て」の出力をエスケープすることです。
これはつまり、入力値ではないとか仕様上不可能とかの理由でエスケープ有無を都度判断することなく、文字通り全ての出力をエスケープすることを求めています。
参考) 安全なウェブサイトの作り方 - 3.5.2 対策漏れ
https://www.ipa.go.jp/security/vuln/websecurity/ …

もしエスケープしない出力が残っていると、その時点では問題がない値だったとしても、今後の仕様変更にて問題のある値が入り込み、それなのにエスケープを忘れる単純ミスを犯した場合、脆弱性が生まれてしまいます。
そのような人為的なミスまで防止するのが、根本的解決の「全て」に込められた意味です。
参考) fool proof
https://ja.wikipedia.org/wiki/%E3%83%95%E3%83%BC …

innerHTML の代用案ですが、最近のブラウザですと createTextNode の他にも便利な API があるので活用しましょう。
https://developer.mozilla.org/ja/docs/Web/API/El …
https://developer.mozilla.org/ja/docs/Web/API/El …
これらは内部的にエスケープ処理をするので根本的解決たり得ます。
例)
ふ = document.createElement("rt"); ふ.append("うちわ");
季 = document.createElement("ruby"); 季.append("団扇", ふ);
詠 = document.createElement("small"); 詠.append("子規");
書換要素.replaceChildren("ことごとく", 季, "破れし熱さ哉", 詠);
    • good
    • 2
この回答へのお礼

回答ありがとうございます、どうしても分からないのでアドバイスお願い致します。
document.createElementをどのように使えばよいのか分からず困っているのですが、デフォルトで名前(50文字)とメッセージ(500文字)それぞれ上限にした状態で、文字を入力するたびに残り〇文字、〇文字超過と表示させるにはどうすればいいのでしょうか?

※名前HTML
<div class="msg_partial">あと<strong>50</strong>文字</div>

※コメントHTML
<div class="msg_partial">あと<strong>500</strong>文字</div>

※以前教えて頂いたエスケープ方法
function escapeHTML(値) {
var a = document.createElement('span');
a.textContent = 値;
return a.innerHTML;
}
要素.innerHTML = '<strong>' + escapeHTML(文字列) + '</strong>';

お礼日時:2023/09/03 22:06

前の質問で同様に回答されていた方がいましたがinnerHTMLで使っているのは関数内で代入した数値leftだけですよね?


それで何を心配しているのかハッキリしません。

またnewtext はtextareaの内容をそのまま設定しているように見えますが、それは意図したものでしょうか?

究極的にはブラウザはクライアント側でどうでにでも制御できるものです。
デバッガでスクリプトを一時停止して、本来あり得ない値に書き換えることも可能です。
ウェブサイトは、ブラウザ経由であろうがなかろうが、どんなリクエストをされても
サーバや他のクライアントに害を及ぼさないように作る必要があります。
そこに立ち戻って考えてはどうでしょうか。
    • good
    • 1
この回答へのお礼

A.回答ありがとうございます、innerHTML を使う場合は、問題のない値しか使わないと分かっていたとしても、HTMLのエスケープ処理を行った方がセキュリティ上良いとアドバイスを頂いたためコードを追加いたしました。

デザインを優先した際にPHPとJavascriptを使って実現可能なコードがinnerHTMLかDocument.createTextNodeになると思いますので、現在のコードに合う対策を練るのがベストだと考えております。

お礼日時:2023/09/01 14:51

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!