安全地读取查询字符串参数的最佳方法是什么?

5
我们有一个项目,可以生成代码片段,用于其他各种项目。代码的目的是从查询字符串中读取两个参数,并将它们分配给iframe的“src”属性。
例如,http://oursite/Page.aspx?a=1&b=2 URL上的页面将包含JavaScript来读取"a"和"b"参数。然后,JavaScript会根据这些参数设置iframe的“src”属性。例如,“<iframe src="http://someothersite/Page.aspx?a=1&b=2" />”。
我们目前正在使用服务器端代码执行此操作,该代码使用Microsoft的Anti Cross-Scripting库来检查参数。但是,新的要求指出我们需要使用JavaScript,并且不能使用任何第三方JavaScript工具(如jQuery或Prototype)。
我知道的一种方法是在使用参数之前替换任何"<"、单引号和双引号的实例,但我认为这不够安全。

其中一个参数始终是以字母"P"开头,后跟9个整数。另一个参数始终是15个字母数字字符。(感谢Liam建议我澄清这一点)。

有人对我们有任何建议吗?

非常感谢您的时间。


这个回答解决了你的问题吗?如何在JavaScript中获取查询字符串值? - Heretic Monkey
5个回答

12

2022年9月更新:大多数JS运行时现在都有一个URL类型,可以通过searchParams属性公开查询参数。即使您只想从相对URL中获取URL参数,也需要提供基本URL,但它比自己编写更好。

let searchParams/*: URLSearchParams*/ = new URL(
    myUrl,
    // Supply a base URL whose scheme allows
    // query parameters in case `myUrl` is scheme or
    // path relative.
    'http://example.com/'
).searchParams;
console.log(searchParams.get('paramName')); // One value
console.log(searchParams.getAll('paramName'));

.get.getAll之间的区别在于第二个返回一个数组,如果同一参数名在/path?foo=bar&foo=baz中出现多次,则该数组可能很重要。


不要使用escape和unescape,请使用decodeURIComponent。 例如:

function queryParameters(query) {
  var keyValuePairs = query.split(/[&?]/g);
  var params = {};
  for (var i = 0, n = keyValuePairs.length; i < n; ++i) {
    var m = keyValuePairs[i].match(/^([^=]+)(?:=([\s\S]*))?/);
    if (m) {
      var key = decodeURIComponent(m[1]);
      (params[key] || (params[key] = [])).push(decodeURIComponent(m[2]));
    }
  }
  return params;
}

并将document.location.search传递进去。

仅仅将<转换为&lt;是不够的,必须确保在将内容注入HTML时,不会允许脚本运行。请务必对以下字符进行转义:<、>、&和"。

这并不能保证参数没有被篡改。如果需要验证URL是由您的服务器之一生成的,请搜索URL签名。


4

我认为使用白名单方法会更好。不要只剥离“坏”东西,而是剥离除你认为“安全”的内容之外的所有内容。

此外,我强烈建议对参数进行HTML编码。应该有很多可以完成这个任务的JavaScript函数。


你应该明确定义哪些数据是可接受的,例如参数a是整数、浮点数、字符串、电子邮件地址还是仅限大写的产品代码?然后定义正则表达式,只匹配允许的数据。 - Liam
这是一个很好的观点。 其中一个参数始终是一个以“P”开头的9个整数,另一个参数始终是15个字母数字字符。 - Todd Armstrong

1

你可以使用JavaScript的escape()和unescape()函数。


0

有几件事情你应该做:

  • 根据类型、格式、范围等严格列出接受的值的白名单
  • 明确黑名单中的某些字符(即使这通常是可绕过的),如果你的白名单不是非常严格。
  • 输出之前编码值,如果你正在使用 Anti-XSS,你已经知道简单的 HtmlEncode 是不够的
  • 通过 DOM 设置 src 属性 - 而不是生成 HTML 片段
  • 仅将动态值用作查询字符串参数,而不是用于任意站点;即硬编码服务器名称、目标页面等。
  • 您的网站是否使用 SSL?如果是,则使用框架可能会导致与 SSL UI 不一致...
  • 通常使用命名框架,可以允许框架欺骗;如果在安全站点上,这可能是一个相关的攻击向量(用于钓鱼等)。

0

您可以使用正则表达式来验证是否有一个P后面跟着9个整数以及15个字母数字值。我想我桌子上的RegEx书中有一些JavaScript示例可以帮助您。

将字符集限制为仅ASCII值将有所帮助,并遵循上述所有建议(白名单,通过DOM设置src等)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接