プロが教える店舗&オフィスのセキュリティ対策術

参考サイトを見るとHTMLElement.innerHTMLは脆弱性があるようで対策が必要なようですが、コードをどのように変更すればよいか分かりません…
アドバイスお願い致します。

※参考サイト
https://gihyo.jp/dev/serial/01/javascript-securi …

<script>
function lengthCheck() {
const left = this.dataset.maxlength - this.value.length;
if (left >= 0) {
this.nextElementSibling.innerHTML = 'あと<strong>' + left + '</strong>文字';
this.dataset.submit_disabled = this.value.length === 0;
} else {
this.nextElementSibling.innerHTML = '<strong>' + -left + '</strong>文字超過しています';
this.dataset.submit_disabled = true;
}
let disabled = false;
for (let i = 0; i < length_input.length; i++) {
if (length_input[i].dataset.submit_disabled === "true") {
disabled = true;
}
}
submit_button.disabled = disabled;
}
/* カメラ画像をファイルアップロード時に非表示にする */
const attach = document.querySelectorAll('.attach');
const del = document.querySelectorAll('.attachdel');
const clear = document.querySelectorAll('.attachclear');
const viewer = document.querySelectorAll('.viewer');
const changeImg = document.querySelectorAll('.changeImg'); // 入力されたら消す画像
for (let i = 0; i < attach.length; i++) {
attach[i].addEventListener('change', () => {
if (attach[i].files[0].size > 15 * 1024 * 1024) {
alert('ファイルサイズが 15MBバイトを超えています');
return;
}
del[i].value = "";
viewer[i].innerHTML = "";
if (attach[i].files.length !== 0) {
const reader = new FileReader();
reader.readAsDataURL(attach[i].files[0]);
}
});
clear[i].addEventListener('click', () => {
attach[i].value = "";
del[i].value = "1";
viewer[i].innerHTML = "";
changeImg[i].classList.remove('hideItems');
});
}
</script>

A 回答 (2件)

innerHTML を使う場合は、


たとえ問題のない値しか使わないと分かっていたとしても、
HTMLのエスケープ処理を行いましょう。
後の改修にて脆弱性が生まれる余地をなくすためです。

ブラウザの標準機能にエスケープ関数が無いので独自に用意しましょう
例)
function escapeHTML(値) {
_ var a = document.createElement('span');
_ a.textContent = 値;
_ return a.innerHTML;
}
要素.innerHTML = '<strong>' + escapeHTML(文字列) + '</strong>';

参考)
安全なウェブサイトの作り方 - クロスサイト・スクリプティング
https://www.ipa.go.jp/security/vuln/websecurity/ …
根本的解決
5-(i) ウェブページに出力する全ての要素に対して、エスケープ処理を施す。
    • good
    • 1
この回答へのお礼

アドバイスありがとうございます、Ogre7077さんのコードを元に調べながらコードを書いてみたのですが正しいのか分かりません、アドバイスお願い致します。
名前もコメントも同じクラス(msg_partial)内に文字数を数字で出力しているのですが、クラスはそれぞれ別である必要はありますでしょうか?

※名前
<input class="length_input" data-maxlength="<?php echo MAX_LENGTH::NAME; ?>" id="name" value="<?php echo $namae; ?>">
<div class="msg_partial"></div>

※コメント
<textarea class="length_input" data-maxlength="<?php echo MAX_LENGTH::MESSAGE; ?>" id="message"><?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;
}

お礼日時:2023/08/31 05:53

こんばんは



>HTMLElement.innerHTMLは脆弱性があるようで対策が必要なようですが、~
サイトに説明があるように、脆弱性はinnerHTMLに設定する内容が(完全には)制御できない内容である場合です。

ご提示の内容がスクリプト部分だけでなので、特に、lengthCheck関数はどのように呼び出されているのかも不明で、this値がどうなっているのか不明なので、はっきりとはしませんけれど・・

innerHTMLが使われているのは、
>this.nextElementSibling.innerHTML = '<strong>' + -left + '</strong>文字超過しています'; --①
>viewer[i].innerHTML = ""; --②
の部分だけと思います。

②はクリアしているだけなので、問題にはなりません。
①は、変数leftが数値であることが保証されているように思われますので問題ないのでは?

どうしてもinnerHTMLを避けたいのであれば、
 Document.createTextNode
を利用してテキスト化した要素をappendするように変更すれば、HTMLタグなどはエスケープされ、文字列化されますので安全でしょう。
https://developer.mozilla.org/ja/docs/Web/API/Do …
    • good
    • 1
この回答へのお礼

A.アドバイスありがとうございます、値が制御されていない場合必要ということでしょうか?メッセージは500文字、名前は50文字という数値をthis.dataset.maxlengthに当てはめております。
②は問題ないんですね勉強になりました。Document.createTextNodeを使用する方法も考えてみます。

<div class="title-partial">
<h2>名前(name)<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>
</div>
<div class="body-partial">
<h2>コメント(comment)<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>
</div>

class MAX_LENGTH
{
public const NAME = 50;
public const MESSAGE = 500;
}

お礼日時:2023/08/30 01:22

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

このQ&Aを見た人はこんなQ&Aも見ています


このQ&Aを見た人がよく見るQ&A