実現したいこと
JavascriptでDom XSSの脆弱性対策を行いたい
前提
画像、短い動画をアップロード(ファイル)、名前、メッセージを送信できる掲示板を作成していて、名前、メッセージを入力する際にヤフー知恵袋のような入力可能な文字数をカウントする機能を実装するためにHTMLElement.innerHTMLを使っていたのですが、エレメント事作る必要があり=そこでDOM要素が発生してしまうリスクがありdocument.addEventListenerを使うよう修正いたしました。
既存の文字入力が上限を超えていた場合に送信できないようにする機能とファイルアップロード箇所にデフォルトで表示されているカメラの画像をファイルアップロード時に非表示にするコードもまとめて実装する必要があるため上手くまとめることが出来ず困っております。
カメラ画像をファイルアップロード時に非表示にするコードは、イベント設定以前に要素を取得しているため、HTML解釈後に実行することが必要となっていて、window.addEventListener("load", init);でまとめたのですが、無理やりコードをつなぎ合わせた形になっております。
発生している問題・エラーメッセージ
文字入力数の条件にあわせて送信ボタンの使用権限を操作する機能を制限する機能とDOMツリー構築完了後にカメラ画像をファイルアップロード時に非表示にするコードを両立したい為、入力中の文字数チェックと、ボタン制御のための文字数チェックが別々になっている。
該当のソースコード
<script> function validation_submit(f) { const submit = document.getElementById("submit_button"); /* 判定は逆なので、逆に渡す */ submit.disabled = f ? false : true; }; function validation_text(parts) { /* このpartsグループの、inputを抽出 */ let text = parts.getElementsByClassName('input')[0]; /* 最小チェック */ if (text.value.length == 0) { return false; } /* 最大チェック */ if (text.value.length >= text.dataset.length) { return false; } return true; }; /* バリデーション条件判断部分 */ function validation() { let parts = document.getElementsByClassName('parts'); let submit = true; for (let i = 0; i < parts.length; i++) { if (validation_text(parts[i]) != true) { submit = false; } } validation_submit(submit); }; /* 例えばのチェック */ function init() { /* カメラ画像をファイルアップロード時に非表示にする */ /* カメラ画像をファイルアップロード時に非表示にする */ 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'); }); } /* 文字数表示 */ document.addEventListener('input', e => { if (!['name', 'message'].includes(e.target.id)) return; const t = e.target, m = t.nextElementSibling, n = t.value.length - (t.dataset.length | 0), c = document.createElement('span'); c.append(Math.abs(n)); m.style.color = n > 0 ? 'red' : 'black'; m.replaceChildren(n > 0 ? '' : '残り', c, `文字${n > 0 ? '超過してい' : '入力でき'}ます。`); /* 毎回判定によるボタン制御 */ validation(); }); /* 初回判定のボタン制御 */ validation(); }; window.addEventListener("load", init); </script> <body> <form method="post" enctype="multipart/form-data"> <div class=parts> <h2>名前(name)<span>※必須</span></h2> <input class=input type="text" name="name1" id="name" data-length="32" placeholder="未入力の場合は、匿名で表示されます" value=""> <div></div> </div> <div class=parts> <h2>コメント(comment)<span class="required">※必須</span></h2> <input class=input type="text" name="name2" id="message" data-length="40" placeholder="荒らし行為や誹謗中傷や著作権の侵害はご遠慮ください"> <div></div> </div> <div class="post-button"><!-- ボタンを押せなくする --> <button type="submit" id="submit_button" name="mode" value="confirm">表示画面へ進む</button> </div> </form> </body>
修正前のソースコード
<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> <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>
参考サイト
回答2件
あなたの回答
tips
プレビュー