组合框填充一个文本字段-JavaScript和用户输入

Combo box populates a text field - JavaScript and user input

本文关键字:字段 文本 -JavaScript 输入 用户 一个 填充 组合      更新时间:2023-09-26

设置

最后我需要的是:一个组合框和一个文本字段。从组合框中选择一个项目将在文本字段中填充一个值。组合框中的项目来自用户输入。

这是我目前运行良好的代码:

function fill() {
  var select = document.getElementById("select");
  var value = select.options[select.selectedIndex].value;
  var textfield = document.getElementById("textfield");
  switch (value) {
  case "1":
    textfield.value = "some user-provided text";
    break;
  case "2":
    textfield.value = "containing possibly < > & etc.";
    break;
  }
}
<select id="select" onchange="fill()">
  <option>Select something...</option>
  <option value="1">Select option 1</option>
  <option value="2">Select option 2</option>
</select>
<input type="text" id="textfield"/>

问题

如果用户提供的要填充的文本包含危险字符,我不知道该怎么办。通常,在将其写入HTML代码之前,我会对其进行HTML编码,但现在我正在将其写入JavaScript代码。

所有的JavaScript都是由Java后端生成的。我真的不能这样创建:

String value = getValueFromUser();
write("textfield.value = '"" + value + "'";");

因为有人会输入"; somethingBad(); //,而其他用户会在选择此选项时执行somethingBad()

如果我对值进行HTML编码:

String value = htmlEncode(getValueFromUser());
write("textfield.value = '"" + value + "'";");

然后(安全问题除外(在组合框中选择一个值后,文本字段将填充HTML编码的文本。

问题

如何对用户提供的值进行编码,以便:

  • 它们不能被滥用于JavaScript代码注入,并且
  • 填充到文本字段后,它们看起来是一样的

让我谈谈我自己的想法。

我的Java代码生成隐藏的HTML元素(例如跨度(,其中包含来自用户的HTML编码输入:

<span id="case1" class="hidden">some user-provided text</span>
<span id="case2" class="hidden">containing possibly &gt; &lt; &amp; etc.</span>

然后我的JavaScript代码将使用这里的值:

function fill() {
  var select = document.getElementById("select");
  var value = select.options[select.selectedIndex].value;
  var textfield = document.getElementById("textfield");
  switch (value) {
  case "1":
    textfield.value = document.getElementById("case1").innerHTML;
    break;
  case "2":
    textfield.value = document.getElementById("case2").innerHTML;
    break;
  }
}

这样,我就不需要担心在JavaScript代码中对用户输入进行编码以确保安全——这永远不在JS代码中!它就在HTML中,而且众所周知如何对HTML进行编码以确保其安全。

明显的缺点是生成隐藏的HTML元素,但这似乎是一个可以接受的折衷方案。。。

存储转义的值,然后:

String value = getEscapedValueFromUser();
write("textfield.value = unescape('"" + value + "'");");

这将从存储的字符串中删除括号、引号和"=",从而防止任何恶意代码。

在以下评论后编辑:

当您验证输入并将其完全转义存储时,您最好的选择是在js中转义((。然后,您只需要将unescape((添加到"…"之外的write((行中,如上面的代码所示。

这编码了大多数特殊的字符[只在谷歌上搜索'js escape(('以获取引用],你肯定无法离开"…",如果有换行符,就无法继续下一行,没有需要包含在恶意代码中的字符,字符串总是以输入结束,因为escape/unescape是互补的,您不会忘记任何事情,也不会意外地在目标字符串中将真正的'''n'编码为[enter]。

如果你不想这样做,因为你可能已经在数据库中收集了很多未标记的值,或者在其他地方使用它们,并且无法更改数据库以容纳额外的字段,您应该在java中复制escape函数,直到您认为需要它为止[在进一步认为安全之后,您应该对所有控制字符和"'()%=;进行编码,或者只是复制整个函数,不会太难]。

我通常使用以下函数,该函数将返回一个字符串以显示键入的任何文本:

function RemoveEntities (TextToReplace) 
{
    var ReplacedText='';
    var CurrentChar='';
    if (typeof TextToReplace=='number') {TextToReplace=TextToReplace.toString();}
    for (i=0;i<TextToReplace.length;i++)
    {
        CurrentChar=TextToReplace.substring(i,i+1);
        if (CurrentChar=="&") {ReplacedText=ReplacedText+"&amp;";} 
        else if (CurrentChar=="<") {ReplacedText=ReplacedText+"&lt;";} 
        else if (CurrentChar==">") {ReplacedText=ReplacedText+"&gt;";} 
        else if (CurrentChar==" ") {ReplacedText=ReplacedText+"&nbsp;";} 
        else if (CurrentChar=="'") {ReplacedText=ReplacedText+"&apos;";} 
        else if (CurrentChar=='"') {ReplacedText=ReplacedText+"&quot;";} 
        else if (escape(CurrentChar)=='%0A' || escape(CurrentChar)=='%0C') {ReplacedText=ReplacedText+"<br/>";}
        else {ReplacedText=ReplacedText+CurrentChar;}
    }
return ReplacedText;
}

这对于短文本输入应该很好。也可以用+=或全局替换语句缩短,但我还没有优化它(不是瓶颈(。