0

设置

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

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

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

3 回答 3

2

让我抛出我自己的想法。

我的 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 元素,但这似乎是一个可以接受的折衷方案......

于 2013-05-09T16:31:03.300 回答
1

存储您的值转义,然后:

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

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

在以下评论后编辑:

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

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

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

于 2013-05-08T16:15:03.940 回答
0

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

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

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

于 2013-05-07T11:00:15.560 回答