【问题标题】:Combo box populates a text field - JavaScript and user input组合框填充文本字段 - JavaScript 和用户输入
【发布时间】:2013-04-29 06:22:51
【问题描述】:

设置

我到底需要什么:一个组合框和一个文本字段。从组合框中选择一个项目会在文本字段中填充一个值。组合框中的项目来自用户输入。

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

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 代码注入,并且
  • 它们在填充到文本字段后看起来一样吗?

【问题讨论】:

  • 如果您的服务器端代码需要在将成为 JS 字符串的内容中包含用户输入的数据,而不是 htmlEncode(),您可以进行字符串替换以将任何 " 字符更改为 @987654328 @。如果用户输入的数据可能包含回车或换行,您也应该替换它们。那么浏览器看到的将只是一个有效的 JS 字符串。
  • 那么您如何描述这种转变?让用户输入成为有效的 JS 字符串?...
  • 只发送 JSON 编码的纯文本和 JSON 编码的 html 实体会不会过大?这会将所有编码移至服务器,从而避免任何潜在的安全问题。本土的编码方案可以而且通常会失败。保持简单...
  • 我不想使用任何非标准编码,这就是为什么我试图避免这里的大部分答案。

标签: javascript encoding combobox populate


【解决方案1】:

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

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;
}

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

【讨论】:

  • 如果我错了,请纠正我,但这不仅仅是一个(不完整的)HTML编码吗?
  • 抱歉,在回答之前应该阅读问题 - 这不会显示为在文本字段中键入的内容。代码注入的风险取决于您对字符串执行的操作。您可以使用 escape() 值来存储它,并在需要显示/使用时使用 unescape()。
  • 我需要对字符串进行编码,以便在生成的 JS 中使用它,然后将其填写到 HTML 表单中。
  • 我现在看到问题了,你能不能 escape() 存储它的值,然后在加载时调用一个函数来 unescape() 组合框中的值?
  • 这是混合了两件事。对字符串进行 HTML 转义并不意味着将其放入 JS 代码中是安全的。
【解决方案2】:

存储您的转义值,然后:

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

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

在下面的 cmets 之后编辑:

当您验证输入并将其存储为完全转义时,您最好的选择确实是在 js 中进行 escape()。然后,您只需将 unescape() 添加到“...”之外的 write() 行,如上面的代码所示。

这对大多数特殊字符进行编码[只是 google 'js escape()' 用于引用],你肯定无法摆脱“...”,如果有行就不会继续下一行中断,不需要包含在恶意代码中的字符,字符串总是作为输入结束,因为转义/取消转义是互补的,你不会忘记任何东西,也不会不小心将真正的 '\n' 编码为 [enter]目标字符串。

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

【讨论】:

  • 这里的escape() 有什么作用?它是HTML转义吗?在那种情况下,是否有 JavaScript 函数unescape()
  • escape() % 对大多数特殊字符进行编码,这将使字符串可以安全地写入(),并且在上面的代码块中可以取消转义()。
  • escape() 需要是 Java 方法。您推荐哪种确切的逃避策略? (这是这个 SO 问题的症结所在)
  • 您如何从用户那里获得价值?你需要对字符串做的就是在它到达 java 之前对其进行转义,或者用它们在 java 中的 % 编码值替换 ()'%" 和 =。 Unescape 也适用于包含未转义字符的字符串。
  • 我的意思是我不是 100% 确信 span.value 将返回与用户输入值中的间距完全相同(在某些浏览器中,多个空格可能会被截断为一个空格)。我会 100% 确信 unescape() 将准确返回 js 中的 escape('input')d,并且 escape('input')d 值不会包含 " 或中断字符(因此在这里是安全的)。如果您对span.value,或者没关系,那么我猜你有两种剥猫皮的方法。我看不出任何一种方法难以实施或造成瓶颈......
【解决方案3】:

让我提出我自己的想法。

我的 Java 代码生成隐藏的 HTML 元素(例如 spans),其中包含来自用户的 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 元素,但这似乎是一个可以接受的折衷方案……

【讨论】:

  • 将 document.getElementById(xxx).value 改为 document.getElementById(xxx).innerHTML 就可以了
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-06-18
  • 1970-01-01
  • 1970-01-01
  • 2016-04-24
  • 1970-01-01
  • 2012-02-15
  • 2019-09-26
相关资源
最近更新 更多