• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:JavascriptでXSSの脆弱性対策を行いたい)

JavascriptでのXSS脆弱性対策ガイド

このQ&Aのポイント
  • JavascriptでXSS対策を施したい方の参考資料として、エスケープ処理の実装に関する具体的なアドバイスとコード例を提供します。
  • HTML要素をinnerHTMLで操作する際の安全な方法について説明し、XSS攻撃からの保護を目的としたエスケープ関数の必要性を強調します。
  • XSSの脆弱性を防ぐためのエスケープ処理の重要性と、与えられたコードを元にした実装手順について解説します。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.27

<div class="submit_button_validation submit_button_validation1">残り<span></span>文字入力できます。</div> <div class="submit_button_validation submit_button_validation2"><span></span>文字超過しています。</div> このまま代入しちゃえばいいんですよ!。 submit_button_validation1だけを使って innerHTML="残り<span>"+v+"</span>文字入力できます。"; の時と、 innerHTML="span>"+v+"</span>文字超過しています。"; の時を、ifで制御すればOKですよ。 vを「escapeHTML(文字列)」するかは、自由ですが。 手っ取り早いのは(v | 0)だけでもいいかも。 #なぜなら、vは数字を前提としてるので、それ以外を 考慮する必要はないですから。 「escapeHTML(文字列)」これを使うのは、 外部から来た情報に対してです。 だから、ユーザーが入力したものは絶対に表示しない! って言ったのです!! もう、そろそろ、完成じゃないかな?

php_learn
質問者

補足

アドバイスありがとうございます、ifで入力文字数が制限を超えているかいないかでHTML表示を分岐するように考えてみたのですが、 表示するHTML部分は空白でも問題ないのでしょうか? HTML表示で文字が入力されるまで空の状態にしておいて、入力後に表示するということで window.onload = function() {} のコードを参考にいたしました。window.onload = function() {} は動かない原因になりうるため window.addEventListener('DOMContentLoaded', function() {} を代用するように変更しております。 画像のアップロード機能が名前、メッセージの前になるので、参考サイトのどちらのコードを使えばよいのか分からず教えて頂けると助かります。 回答No.26でデバッガーでステップ実行をするようにアドバイス頂いたと思うのですが、今回はボタンの活性または非活性にする機能と文字数の表示分岐部分は分けて考えております。 (v | 0)というのがどのような意味があるのか分からないので教えて頂きたいです。 ※参考サイト https://took.jp/window-onload/ <div class="title-partial parts"> <!-- title-partial + parts --> <h2>名前(name)<span class="required">※必須</span></h2> <div class=parts> <input class=submit_button type="text" type="text" name="name1" id="name" data-length=32 placeholder="未入力の場合は、匿名で表示されます" value="<?php echo $namae; ?>"> <div class="submit_button_validation submit_button_validation"></div> </div> <div class="body-partial parts"><!-- body-partial + parts --> <h2>コメント(comment)<span class="required">※必須</span></h2> <div class=parts> <input class=submit_button type="text" name="name2" id="message" data-length=40 placeholder="荒らし行為や誹謗中傷や著作権の侵害はご遠慮ください"><?php echo $message; ?> <div class="submit_button_validation submit_button_validation"></div> </div> <script> function validation_submit(f) { const submit = document.getElementById("submit_button"); /* 判定は逆なので、逆に渡す */ /*JavaScriptの要素を活性または非活性にする */ submit.disabled = f?false:true; }; function validation_text(parts) { /* このpartsグループの、input=textを抽出 */ /* HTML要素を取得 */ let text=parts.getElementsByClassName('submit_button')[0]; /* バリデーション警告パーツを抽出 */ let validation=parts.getElementsByClassName('submit_button_validation')[0]; validation.style.display = 'none'; /* 例えばのチェック */ window.addEventListener('DOMContentLoaded', function() { let wao = document.getElementsByClassName('submit_button_validation'); const left = text.dataset.length-text.value.length; if (left >= 0) { /* ひとまずclassは複数配置できる形式なので、見つかった最初の1個目にアタッチ */ wao[0].innerHTML="残り<span>"+v+"</span>文字入力できます。"; text.value.length === 0; } else { /* そのまま、2個目にアタッチ */ wao[1].innerHTML="<span>"+v+"</span>文字超過しています。"; } }) }; /* バリデーション条件判断部分 */ 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); }; /* DOM構築が終わってから呼び出される初期化関数 */ function init() { // let text = document.getElementById('submit_button'); // text.oninput = e_text; /* ↑これを、idじゃなくてclass対応に変更↓ */ /* class=parts内の class=submit_buttonに対して設定 */ let parts = document.getElementsByClassName('parts'); for (let i=0;i<parts.length;i++) { parts[i].getElementsByClassName('submit_button')[0].oninput = validation; } validation(); }; window.onload = init; </script> ※回答No.20でv1,v2,v3をまとめたい際に教えて頂いたコード <script> window.onload = function() { let wao = document.getElementsByClassName('wao'); /* ひとまずclassは複数配置できる形式なので、見つかった最初の1個目にアタッチ */ wao[0].innerHTML="えい<span>や~</span>た~"; /* そのまま、2個目にアタッチ */ wao[1].innerHTML="はらほろひれはれ~"; } </script>

その他の回答 (26)

回答No.26

あの~。。 /* 最小チェック */ if (text.value.length==0) { v1.style.display = 'block'; return false; } ↓ここが何か?わかります? /* 最大チェック */ if (text.value.length>=text.dataset.length) { v2.style.display = 'block'; return false; ↑ returnは何をする命令ですか? } ↓ってことは、そもそもここに来ますか? /* それ以外 */ v1.getElementsByTagName('span')[0].innerText=text.dataset.length-text.value.length; v1.style.display = 'block'; return true; ↓ここに来る条件は? v2.getElementsByTagName('span')[0].innerText=text.dataset.length-text.value.length; v2.style.display = 'block'; return true; ーー アドバイスとして何ですが、 まず、各命令が何をしてるか?それと 脳内でトレースする癖をつけましょう! 書いているコードが全く意味を持たない物になっており、 実行すらされてないのです! デバッガーでステップ実行をする癖をつける事と、 それを脳内でも出来るようになってくださいね! そうすれば、ソースをちょっと見ただけで、 気持ち悪さが感じられるようになります! ってことで、今回の回答は 「そもそも正しく実行されていない事と、  実行すらもされてません」 この意味は、ブレークポイントを張ってトレースすれば わかります。 で、ここで「あ~」で終わらせたらダメです!。 それを脳内で実行して、「ん?」って感じられるように ならないと、駄目ですよ~ こちら、水商売で、暇つぶしにプログラムしてる程度ですが。 こういうのって結構、水商売と似てて、 水の流れのように、何がどこに行くのか~?って 目で見てると、結構わかるものですよ~ でまとめることも、バラバラにすることも、 簡単ですから! (なぜバラバラにしたほうがいいかは、最初の方で  教えた通りです) しかし、まとめるのがダメなわけでもないです。 a=a+1ならよくて、a++ がダメなのか?ってのと似ており、 必ずしも答えは一つではないので、 それ自体は書きたいように書いていいとは思います。 しかし、脳内で実行しないで、記載すれば この結果になるのですよ! このサンプルを使うとき 「何やってるかわからないが、なんとなくここかな?」 って気持ちで触った後がしっかり出ちゃってます。

php_learn
質問者

お礼

説明が抜けておりました、訂正いたします。申し訳ありません。 今回の質問を建てる以前に.innerHTMLを使う場合エスケープ処理 escapeHTML(文字列) を行うか、createTextNodeなどを代用するか、数値であることが保証されている必要があるとアドバイスを頂いた為コードの書き換えを考えてokwabeで質問させていただきました。

php_learn
質問者

補足

A.アドバイスありがとうございます、PHPのコードを考える際のように{}オブジェクトリテラルごとに区切って考えておりました。 申し訳ありません。 脳内で実行していくような形で考えるのですね、勉強になります。 再度教えて頂いたコードを調べてコメントアウトでメモしてみたのですが、分からない点が出てきて困っております。 アドバイスお願い致します。 window.onload = function() {}を使う事でHTMLの切り替えは実装できそうですが、 今回の質問を建てる以前に.innerHTMLを使う場合エスケープ処理 escapeHTML(文字列) を行うか、createTextNodeなどを代用するか、数値であることが保証されている必要があるためコードの書き換えを考えました。 上記の条件を考える場合、最大チェックと最小のチェックは必要になるため、div class="wao"ではなくdiv class="wao1"とdiv class="wao2"の2つのクラスを用意するので、 ※回答No.20でv1,v2,v3をまとめたい際に教えて頂いたコードは使えないことになりそうです。 ※切り替えたいHTML 残り<span></span>文字入力できます。と<span></span>文字超過しています。 ※回答No.20でv1,v2,v3をまとめたい際に教えて頂いたコード <script> window.onload = function() { let wao = document.getElementsByClassName('wao'); /* ひとまずclassは複数配置できる形式なので、見つかった最初の1個目にアタッチ */ wao[0].innerHTML="えい<span>や~</span>た~"; /* そのまま、2個目にアタッチ */ wao[1].innerHTML="はらほろひれはれ~"; } </script> <body> <!-- 後から書き換えた文章でも、CSSが反応することを検証するサンプル --> <div class="wao">ここを書き換えると仮定する</div> <div class="wao">ここを書き換えると仮定する</div> </body> _________________________ 上記の理由からv1,v2,v3を分ける際に教えて頂いたコードを元に考えてみたのですが、v1とv3の最小最大のチェック分を表示させずに文字数のカウントのみ表示させることは出来ますでしょうか? cssのdisplay:none;で見えなくする方法もあるのですが、初めから見えなくするのであればコードそのものに問題があるのではないかと思い、どう対応すべきか悩んでおります… ※変更後のHTML <div class="title-partial parts"> <!-- title-partial + parts --> <h2>名前(name)<span class="required">※必須</span></h2> <div class=parts> <input class=submit_button type="text" name="name1" id="name" data-length=32 placeholder="未入力の場合は、匿名で表示されます" value="<?php echo $namae; ?>"> <div class="submit_button_validation submit_button_validation1">残り<span></span>文字入力できます。</div> <div class="submit_button_validation submit_button_validation2"><span></span>文字超過しています。</div> </div> <div class="body-partial parts"><!-- body-partial + parts --> <h2>コメント(comment)<span class="required">※必須</span></h2> <div class=parts> <input class=submit_button type="text" name="name2" id="message" data-length=40 placeholder="荒らし行為や誹謗中傷や著作権の侵害はご遠慮ください" value="<?php echo $message; ?>"> <div class="submit_button_validation submit_button_validation1">残り<span></span>文字入力できます。</div> <div class="submit_button_validation submit_button_validation2"><span></span>文字超過しています。</div> </div> ※変更前のHTML <div class="uso_input_validation uso_input_validation1">タイトルを入力してください。</div> <div class="uso_input_validation uso_input_validation2">あと<span></span>文字入力できます。</div> <div class="uso_input_validation uso_input_validation3">長すぎます。</div> <script> function validation_submit(f) { const submit = document.getElementById("submit_button"); /* 判定は逆なので、逆に渡す */ /*JavaScriptの要素を活性または非活性にする */ submit.disabled = f?false:true; }; function validation_text(parts) { /* このpartsグループの、input=textを抽出 */ /* HTML要素を取得 */ let text=parts.getElementsByClassName('submit_button')[0]; /* バリデーション警告パーツを抽出 */ let v1=parts.getElementsByClassName('submit_button_validation1')[0]; let v2=parts.getElementsByClassName('submit_button_validation2')[0]; let v3=parts.getElementsByClassName('submit_button_validation3')[0]; v1.style.display = v2.style.display = v3.style.display = 'none'; /* 例えばのチェック */ /* 最小チェック */ if (text.value.length==0) { v1.style.display = 'block'; return false; } /* 最大チェック */ /* data属性の取得・追加・更新といった操作を簡単に実行 */ /* valueプロパティ HTML要素の値を操作する */ /* lengthで文字列の長さを取得する */ /* イベント伝播を止める */ /* data属性の値が操作する値以上だった場合 */ if (text.value.length>=text.dataset.length) { v3.style.display = 'block'; return false; } /* それ以外 */ /* HTML要素を取得 */ /* innerText、内部の文字情報 */ /* data属性の値-操作する値 */ /* return true; はその関数が正常に終了(期待した結果)することを示す */ v2.getElementsByTagName('span')[0].innerText=text.dataset.length-text.value.length; v2.style.display = 'block'; return true; };

回答No.25

>vi,v2,v3をまとめたいとお伝えしたのは、submit_button_validation1とsubmit_button_validation2を1つにする方法があるのではないかという意図でお聞きいたしました。 回答No.20を参照! 同じInnerHTMLに入れてしまえばOKですよ。

php_learn
質問者

補足

回答ありがとうございます、vi,v2,v3をまとめてInnerHTMLで使うのは難しかった為、シンプルに初めから考えてみたのですが、青で数字が表示されません…どうすれば良いでしょうか? 文字制限を超えていた場合に長すぎます。と表示させずにオーバーしている字数を青で表示させたい為、InnerHTMLでまとめずにv1,v2で分ける方法で考えました。 ※前提としてデフォルトでは何も表示せずに、文字を名前とメッセージ欄に入力後からカウント、文字が制限以内(最小)なら残り<span></span>文字入力できます。と表示する。 文字が制限を超えていた場合(最大)は、<span></span>文字超過しています。と表示する。 ※該当HTML <div class="title-partial parts"> <!-- title-partial + parts --> <h2>名前(name)<span class="required">※必須</span></h2> <div class=parts> <input class=submit_button type="text" type="text" name="name1" id="name" data-length=32 placeholder="未入力の場合は、匿名で表示されます" value="<?php echo $namae; ?>"> <div class="submit_button_validation submit_button_validation1">残り<span></span>文字入力できます。</div> <div class="submit_button_validation submit_button_validation2"><span></span>文字超過しています。</div> </div> <div class="body-partial parts"><!-- body-partial + parts --> <h2>コメント(comment)<span class="required">※必須</span></h2> <div class=parts> <input class=submit_button type="text" name="name2" id="message" data-length=40 placeholder="荒らし行為や誹謗中傷や著作権の侵害はご遠慮ください"><?php echo $message; ?> <div class="submit_button_validation submit_button_validation1">残り<span></span>文字入力できます。</div> <div class="submit_button_validation submit_button_validation2"><span></span>文字超過しています。</div> </div> ※変更コード https://wandbox.org/permlink/6m6E3UD4C2IoNI0x ※表示画面 http://www.irasuto.cfbx.jp/%e9%9b%91%e8%ab%87%e6%8e%b2%e7%a4%ba%e6%9d%bf/

回答No.24

>同じ変数が2度宣言されているようですが、どの部分が問題となっているのか分かりますでしょうか? その前に、例えば function validation_text(parts) { って書いたらその次のラインは、タブまたはスペースで 段組みする癖をつけましょ! function validation_text(parts) { ␣abc(); ␣if (なにか?) { ␣␣def(); ␣} } みたいに階層を! で、エラーの原因もこれですので! ソースをパッと見た時の、気持ち悪さを感じられるように なってくると、、割と簡単に気が付くのですが。 ってことで、回答は 「基本は大事にね!」 かな。。

php_learn
質問者

補足

申し訳ありません、閉じタグを確認したところfunction validation_text(parts) {}が抜けておりました。 submit_button_validation1,submit_button_validation2,submit_button_validation3を 残り<span></span>文字入力できます。と<span></span>文字超過しています。の2つで実装したい場合、下記のような形になると思うのですが、それ以外はどのように書けば良いのでしょうか? AsarKingChangさんから教えて頂いたように組んでみたのですが、残りの字数を計算して表示したい為innerHTMLで字数の計算が必要だと思われます。 上手く説明できず申し訳ありません… vi,v2,v3をまとめたいとお伝えしたのは、submit_button_validation1とsubmit_button_validation2を1つにする方法があるのではないかという意図でお聞きいたしました。 <div class="title-partial parts"> <!-- title-partial + parts --> <h2>名前(name)<span class="required">※必須</span></h2> <div class=parts> <input class=submit_button type="text" type="text" name="name1" id="name" data-length=32 placeholder="未入力の場合は、匿名で表示されます" value="<?php echo $namae; ?>"> <div class="submit_button_validation submit_button_validation1">残り<span></span>文字入力できます。</div> <div class="submit_button_validation submit_button_validation2"><span></span>文字超過しています。</div> </div> <div class="body-partial parts"><!-- body-partial + parts --> <h2>コメント(comment)<span class="required">※必須</span></h2> <div class=parts> <input class=submit_button type="text" name="name2" id="message" data-length=40 placeholder="荒らし行為や誹謗中傷や著作権の侵害はご遠慮ください"><?php echo $message; ?> <div class="submit_button_validation submit_button_validation1">残り<span></span>文字入力できます。</div> <div class="submit_button_validation submit_button_validation2"><span></span>文字超過しています。</div> </div> <script> /* 最小チェック */ if (text.value.length==0) { v1.style.display = 'block'; return false; } /* 最大チェック */ if (text.value.length>=text.dataset.length) { v2.style.display = 'block'; return false; } /* それ以外 */ v1.getElementsByTagName('span')[0].innerText=text.dataset.length-text.value.length; v2.getElementsByTagName('span')[0].innerText=text.dataset.length-text.value.length; v1.style.display = 'block'; v2.style.display = 'block'; return true; }; </script> ※変更コード https://wandbox.org/permlink/6KDSqVvypXyrqp4b

回答No.23

>ユーザーが入力したものは使わないということはエスケープ処理した文字列を使うということでしょうか? ちょっと違います。そもそも表示させてはならない! ただ、今回の議題からは外れるので、今回はこれでOK >目的のもの以外は入力制限することですね。 これも違います。 JSは外部から書き換えられるので、制限部分も無視できてしまいます。こちらも、議題からは外れるので、今回はこれでOK >新規でのエレメントを作り出すJavaScript命令は気を付けるように覚えておきます。display:none;で見えなくすると外部からコードを書き換えられないのですね。 これも違う。。displayは隠してるだけで、書き換えに対する能力は全く関係してないです。それで、隠されるものが、書き換えできるのか?だけが重要。 >コードを1つにまとめた場合のコードについてお聞きしたかったのですが、下記のような感じで良いのでしょうか? テスト問題じゃないので、答えは複数あるので、 動いているのであれば、そこは私は口出しませんよ。 ひとまず、init()がjqueryで言う所の$(で始まってるのが わかってもらえて、その中でリスナーが設定され リスナーがclassの複数の入力を同時に担当している (つまり何個でも指定できて)それに対して 全部が、OKならSUBMIT出来るよ?っていう 基本的な流れがわかれば何でもいいんですよ~ サイトによっては、「SUBMIT」を押したときだけ バリデーションが働くところも多いですよ。 後は、好きに書き換えてもらって!全然OKですよ^^

php_learn
質問者

補足

A.回答ありがとうございます、ユーザーが入力したものを表示させるのも駄目なんですね。 新規でのエレメントを作り出すJavaScript命令で書き換えできるものを隠すということでしょうか? v1,v2,v3をまとめたコードを動かしてみたのですが、エラーが出ております… 同じ変数が2度宣言されているようですが、どの部分が問題となっているのか分かりますでしょうか? ※single-input.phpの138~200行目まで変更 https://wandbox.org/permlink/QlQPEUYqqdAbUyAk ※表示ページ http://www.irasuto.cfbx.jp/%e9%9b%91%e8%ab%87%e6%8e%b2%e7%a4%ba%e6%9d%bf/

回答No.22

>JavaScriptはクライアントサイドなのであくまでバリデーションの役割のみにしかならないため、PHP側でXSS対策をしておけば問題ないという認識で良いでしょうか? 結局最後はそうなりますね。 JavaScriptは、簡単にブラウザのデバッガー起動して、 ブレイクポイント引っ掛けて変数書き換えが出来ちゃうので、 本気で考えれば、何しても無駄じゃないの?って意味で あと、この手のインナー書き換えに 「ユーザーが入力したものを絶対に使わない」 これが大事! 事前に用意した、固定メッセージのON/OFFで 警告メッセージや使い方を教えたり。 後「何文字」=これは、数字しか対象にしない。 など、悪意がある文章=この場合スクリプトが 外部から入り込まないようにする。 それだけで良いかと。 それと、新規でのエレメントを作り出すJavaScript命令は ちょっと危険! 通常のJavaScriptは「後から書き換えても実行されない」 なので、悪意がある人が実行中にそれ自体を書き換えても 何も起こらないのだが、createElementは、 新規のJS空間を生み出せてしまうので、私的に危険関数!。 なので、私がやろうとしてる原点でのサンプル 用意されているテキストを「消しておいて」 条件で、表示と非表示を切り替えて バリデーション結果をユーザーがわかる程度。 が、一番理想なんですよね。 でもま~今回! バリデーションの効果的な伝え方は サンプルかけたのでよかったかなっと^^ あれ、リアルタイムでもいいですし、 SUBMITにフックして、「バリデーションチェック」 結果、入力必須なのに空白な所に「入力してください」 などの赤文字とか。 全部がOKだったら、SUBMITするなど、 そういう使い方に持っていけるので、 よく使うテクニックですよ。

php_learn
質問者

補足

A.アドバイスありがとうございます、ユーザーが入力したものは使わないということはエスケープ処理した文字列を使うということでしょうか? 目的のもの以外は入力制限することですね。 新規でのエレメントを作り出すJavaScript命令は気を付けるように覚えておきます。display:none;で見えなくすると外部からコードを書き換えられないのですね。 コードを1つにまとめた場合のコードについてお聞きしたかったのですが、下記のような感じで良いのでしょうか? ※v1,v2,v3をまとめる場合のコード function validation_text(parts) { /* このpartsグループの、input=textを抽出 */ let text=parts.getElementsByClassName('submit_button')[0]; /* バリデーション警告パーツを抽出 */ let validation=parts.getElementsByClassName('submit_button_validation')[0]; validation.style.display = 'none'; /* 例えばのチェック */ /* 最小チェック */ if (text.value.length==0) { validation.innerHtml="タイトルを入力してください。"; validation.style.display = 'block'; return false; } /* 最大チェック */ if (text.value.length>=text.dataset.length) { validation.innerHtml="長すぎます。"; validation.style.display = 'block'; return false; } /* それ以外 */ validation.innerHtml="あと<span>"+(text.dataset.length-text.value.length)+"</span>文字入力できます。"; validation.style.display = 'block'; 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); }; /* DOM構築が終わってから呼び出される初期化関数 */ function init() { // let text = document.getElementById('submit_button'); // text.oninput = e_text; /* ↑これを、idじゃなくてclass対応に変更↓ */ /* class=parts内の class=submit_buttonに対して設定 */ let parts = document.getElementsByClassName('parts'); for (let i=0;i<parts.length;i++) { parts[i].getElementsByClassName('submit_button')[0].oninput = validation; } validation(); }; window.onload = init;

回答No.21

>表示HTMLを変更するためには、教えて頂いたv1,v2,v3をまとめる必要があると思ったのですが、字数のカウントはどのように書けばよいのでしょうか? 特にまとめる必要はないとは思いますが。(仕事でやる場合むしろまとめるべきではないので) ただ、今回の質問としてまとめたいのであれば、 let validation=こいつにバリデーションタグの位置があるとして。 /* 例えばのチェック */ /* 最小チェック */ if (text.value.length==0) { validation.innerHtml="タイトルを入力してください。"; validation.style.display = 'block'; return false; } /* 最大チェック */ if (text.value.length>=text.dataset.length) { validation.innerHtml="長すぎます。"; validation.style.display = 'block'; return false; } /* それ以外 */ validation.innerHtml="あと<span>"+(text.dataset.length-text.value.length)+"</span>文字入力できます。"; validation.style.display = 'block'; return true; なのですが、これだと、バリデーション文字が常に出てるんじゃない? って矛盾にぶつかるので、出っ放しで、文字だけ書き換えるか、 不要な物を削除するために、 validation.style.display = 'block'; これが意味を持つという感じです。 こんな感じにすればOKですよ。 validationこいつに、書き換えする文字の親エレメントを与えればOK <div>あいうえお</div> なら、DIVタグの位置。idやclassでセレクトすればOK

php_learn
質問者

補足

回答ありがとうございます。もし1つにまとめたい場合は下記コードのようになるのでしょうか? innerHTMLの値をエスケープして確認しておかないとXSSに対して脆弱性が生まれてしまう可能性があるという事だったのですが、 AsarKingChangさんにアドバイス頂いたようにJavaScriptはクライアントサイドなのであくまでバリデーションの役割のみにしかならないため、PHP側でXSS対策をしておけば問題ないという認識で良いでしょうか? おっしゃる通りバリデーション文字が常に出ていることになるため、v1,v2,v3はまとめないほうが良い方法で安全になるのではないかと悩んでおります… ※現在のコード https://wandbox.org/permlink/rE8xteU9y4BYSeOg ※v1,v2,v3をまとめる場合のコード function validation_text(parts) { /* このpartsグループの、input=textを抽出 */ let text=parts.getElementsByClassName('submit_button')[0]; /* バリデーション警告パーツを抽出 */ let validation=parts.getElementsByClassName('submit_button_validation')[0]; validation.style.display = 'none'; /* 例えばのチェック */ /* 最小チェック */ if (text.value.length==0) { validation.innerHtml="タイトルを入力してください。"; validation.style.display = 'block'; return false; } /* 最大チェック */ if (text.value.length>=text.dataset.length) { validation.innerHtml="長すぎます。"; validation.style.display = 'block'; return false; } /* それ以外 */ validation.innerHtml="あと<span>"+(text.dataset.length-text.value.length)+"</span>文字入力できます。"; validation.style.display = 'block'; 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); }; /* DOM構築が終わってから呼び出される初期化関数 */ function init() { // let text = document.getElementById('submit_button'); // text.oninput = e_text; /* ↑これを、idじゃなくてclass対応に変更↓ */ /* class=parts内の class=submit_buttonに対して設定 */ let parts = document.getElementsByClassName('parts'); for (let i=0;i<parts.length;i++) { parts[i].getElementsByClassName('submit_button')[0].oninput = validation; } validation(); }; window.onload = init;

回答No.20

まとめたければ、まとめてもOKですよ。 <html> <head> <style> .wao span { color: red; font-size: 64px; } </style> <script> window.onload = function() { let wao = document.getElementsByClassName('wao'); /* ひとまずclassは複数配置できる形式なので、見つかった最初の1個目にアタッチ */ wao[0].innerHTML="えい<span>や~</span>た~"; /* そのまま、2個目にアタッチ */ wao[1].innerHTML="はらほろひれはれ~"; } </script> </head> <body> <!-- 後から書き換えた文章でも、CSSが反応することを検証するサンプル --> <div class="wao">ここを書き換えると仮定する</div> <div class="wao">ここを書き換えると仮定する</div> </body> </html> 見ての通り、後からタグ付きエレメントを生み出せるので、 それごと送り出せばいいだけです。

php_learn
質問者

補足

回答ありがとうございます、説明不足で申し訳ありません。 表示HTMLを変更するためには、教えて頂いたv1,v2,v3をまとめる必要があると思ったのですが、字数のカウントはどのように書けばよいのでしょうか? ※現在表示されているHTML <div class="title-partial parts"> <!-- title-partial + parts --> <h2>名前(name)<span class="required">※必須</span></h2> <input class=submit_button type="text" type="text" name="name1" id="name" data-length=32 placeholder="未入力の場合は、匿名で表示されます" value=""> <div class="submit_button_validation submit_button_validation1">タイトルを入力してください。</div> <div class="submit_button_validation submit_button_validation2">あと<span></span>文字入力できます。</div> <div class="submit_button_validation submit_button_validation3">長すぎます。</div> </div> <div class="body-partial parts"><!-- body-partial + parts --> <h2>コメント(comment)<span class="required">※必須</span></h2> <input class=submit_button type="text" name="name2" id="message" data-length=40 placeholder="荒らし行為や誹謗中傷や著作権の侵害はご遠慮ください"><div class="submit_button_validation submit_button_validation1">本文を入力してください。</div> <div class="submit_button_validation submit_button_validation2">あと<span></span>文字入力できます。</div> <div class="submit_button_validation submit_button_validation3">長すぎます。</div> </div> ※表示させたいHTML <div class="title-partial parts"> <!-- title-partial + parts --> <h2>名前(name)<span class="required">※必須</span></h2> <input class=submit_button type="text" type="text" name="name1" id="name" data-length=32 placeholder="未入力の場合は、匿名で表示されます" value=""> <div class="msg_partial">あと<span></span>文字入力できます</div> </div> <div class="title-partial parts"> <!-- title-partial + parts --> <h2>名前(name)<span class="required">※必須</span></h2> <input class=submit_button type="text" type="text" name="name1" id="name" data-length=32 placeholder="未入力の場合は、匿名で表示されます" value=""> <div class="msg_partial"><span></span>文字超過しています</div> </div> ※最新コード https://wandbox.org/permlink/rE8xteU9y4BYSeOg ※現在のページ http://www.irasuto.cfbx.jp/%e9%9b%91%e8%ab%87%e6%8e%b2%e7%a4%ba%e6%9d%bf/

回答No.19

>下記のように残り入力可能な文字数を表示させたいのですが、v1,v2,v3をまとめることは難しいでしょうか? 別に簡単です。 このスレッドの趣旨は、元々の質問 <div class="msg_partial">あと<strong>50</strong>文字</div> ここからきてます。 それを、タグ付きでやりたいという、 this.nextElementSibling.innerHTML = '<strong>' + escapeHTML(-left) + '</strong>文字超過しています'; この議題が出発点だったので、エレメントを固定にした上で中身を 書き換えているのが、ポイントでしたから。 業務の場合などでは、カンプを作った段階では 「全表示パターン」が出ている状態でそれを JSでマスクして、必要な時出す!という流れを取ります。 そうすることで、事前に文言チェックが出来るので、 検収しやすいのです! それをやらないと、導入後に「こんな文字は知らない!」だとか 「意図していない文字が入っている」などの損害賠償を 受けることがあり、最初は全パターンを固定で埋め込む方が ビジネスとしては、役に立つのです!。 なぜなら、検収する人はプログラマではないので! ソース側に文言が書いてあっても無効なのですよ! ただ、今回は、遊び?なのでしょうから、 別に好きにやってもいいんじゃなと思いますよ。 別にルールはなく、動けばいいわけなので!。 ってことで、バリデーション文字を プログラム内=つまりハードコートにすれば、 3個作らなくても1個で行けます。 ただ、要件定義はXSSについてなので、 タグは発生させず、インナーテキストだけで、 済ませれば、問題は出ないかと思います。 (というか、趣味なら、  それ自体もあまり気にはしないでしょうけど) ってことで、今回の捕捉の回答は 「難しいわけではなく、簡単です。  やるべきか?って問題だけの話です」

php_learn
質問者

補足

A.アドバイスありがとうございます、v1にコードをまとめたい場合最少と最大のチェックはどうすれば良いのでしょうか? v1,v2,v3に分けていた時は役割を分担できていたのですが、1つにまとめる際はどうチェックすべきかアドバイスお願い致します。 /* 最小チェック */ if (text.value.length==0) { v1.style.display = 'block'; return false; } /* 最大チェック */ if (text.value.length>=text.dataset.length) { v1.style.display = 'block'; return false; } ※v1,v2,v3をまとめてみたコード(single-input.php) https://wandbox.org/permlink/f2kv1EJgWaImzzYv

回答No.18

>それぞれHTMLクラスを変更してみたのですが、また文字数カウントが表示されなくなってしまいました。 >条件判断部分はpartsから変更が必要でしょうか…? そもそも、JavaScriptからエラー出てますよ。。 エラーなしにしてから、やってみるのがよいかと。 元々のサンプルは動くわけなので、 動かなくなったら、元に戻しましょう! ちなみ、簡単なミスが原因でしたが、JavaScriptで その部分エラー出てるので、エラーを見る癖をつけてほしいので、 今回の回答は 「エラーログを見て、単純ミスは、治せるようになる!」 こっちの方が、スキルアップしそうなのでね。。 他の部分に問題があるかは、詳しく見てませんが。 ともあれ、もう少しで、完成しそうですね。

php_learn
質問者

補足

A.アドバイスありがとうございます、元に戻してエラー原因を探ったところ原因を見つけることが出来ました。 https://wandbox.org/permlink/rE8xteU9y4BYSeOg 下記のように残り入力可能な文字数を表示させたいのですが、v1,v2,v3をまとめることは難しいでしょうか? ※比較したもの https://difff.jp/7ja25.html ※名前HTML <div class="msg_partial">あと<strong>50</strong>文字</div> ※コメントHTML <div class="msg_partial">あと<strong>500</strong>文字</div> ※v1,v2,v3をまとめてみたコード(single-input.php) https://wandbox.org/permlink/f2kv1EJgWaImzzYv

回答No.17

><div class=parts>を追加することも考えたのですが、上から順にHTMLクラス構成を考えた為、 追加せずに対応することが可能であれば<div class=parts>を<div class="title-partial">と<div class="body-partial">に分けて実装したいと考えておりました。 いや、 <div class="title-partial">と<div class="body-partial"> これに足すんですよ。 <div class="title-partial parts">  この中は、title-partial + parts です。 </div> <div class="body-partial parts">  この中は、body-partial + parts です。 </div> partsはCSSセレクタではなく、JSのセレクタとして使ってるだけなので、 >上から順にHTMLクラス構成を考えた為、 この構成は変わりません。 名前が増えただけです。 JSのセレクタは階層ではなく、単なるラベルだと思っていいですよ。 タグを探すためだけにあり、確かに同名のCSSにも 反応はするが、CSSを作らなければ単なるラベルでしかないので、 その他に影響は元々ないですよ。 <div class=parts>の下に追加すると、CSSが必須になります! (デフォルトのDIVのCSSを相殺するために別途CSSが必要になるので、面倒が増えるだけだよね?って事で) だったら、CSSを持たないJSセレクタを追加した方が、 .title-partial {} .body-partial {} この二つが生きるので、意味があるんじゃないかな~って

php_learn
質問者

補足

A.説明ありがとうございます、クラスがなぜ複数付けられているのか疑問だったのですが、ラベルとして使えるんですね勉強になりました。 それぞれHTMLクラスを変更してみたのですが、また文字数カウントが表示されなくなってしまいました。 条件判断部分はpartsから変更が必要でしょうか…? ※現在のコード https://wandbox.org/permlink/buIwm0wmQAokA9CY ※表示画面 http://www.irasuto.cfbx.jp/%e9%9b%91%e8%ab%87%e6%8e%b2%e7%a4%ba%e6%9d%bf/ ※HTMLクラス名 <div class="title-partial parts"></div> <div class="body-partial parts"></div> /* バリデーション条件判断部分 */ 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); };

関連するQ&A