如何在Express中处理非UTF-8编码的URL

12
我们有一个Node.js应用程序,最近已从运行在IIS 7(通过IIS Node)转移到Linux(Elastic Beanstalk)上。自从我们切换后,我们的应用程序(主要来自网络爬虫)一直收到许多非UTF-8的URL,例如:Bj%F6rk,而IIS将其转换为Björk。现在这些URL将被传递给我们的应用程序和Web框架(Express),最终调用了decodeURIComponent('Bj%F6rk'),导致URI错误。请问是否有安全推荐的方法,在将URL字符串发送到Express之前执行与IIS相同的转换?
记住:
  1. 我们正在收到这些编码错误的URL请求,
  2. 有一种方法可以使用已弃用的unescape javascript函数解码它们,而且
  3. 这些URL的大部分请求来自必应机器人,我们希望尽量减少对我们的搜索排名产生任何不利影响。

    • 我们真的应该为所有传入的URL做到这一点吗?
    • 是否存在任何安全或性能方面的影响需要我们关注?
    • 我们应该担心unescape在不久的将来被删除吗?
    • 是否有更好/更安全的方法来解决这个问题(是的,我们确实阅读了上面链接的MDN文章)
3个回答

12

我们真的应该为所有传入的URL做这件事吗?

不,你不应该这样做。请求使用了非UTF8的URI组件,这不应该是你的问题。

我们应该关注哪些安全或性能方面的影响?

URI组件的编码并不是一个安全问题。通过查询字符串或路径参数进行注入尝试是一个安全问题。但那是另一个主题。在性能方面,每个中间件都会使您的响应时间变长一点儿。但我甚至都不会担心这个。如果你想自己解码URI,只需这样做。它只需要几毫秒的时间。

我们应该担心unescape在不久的将来被删除吗?

实际上,你应该这样做。unescape已过时。如果你仍然想使用它,首先检查它是否存在,i.e. 'unescape' in global。你也可以使用内置的替代方法:require('querystring').unescape(),它不会在每种情况下产生相同的结果,但它不会抛出URIError。(不建议使用)。

为了最小化对搜索排名的不良影响:

确定你的Express应用程序在这些情况下返回哪个状态码。它可能是500(内部服务器错误),这将看起来很糟糕,或者是404(未找到),这将告诉爬虫你没有查询的结果(这可能并不是真的)。在这些情况下,我建议你通过返回客户端错误,如400(错误请求),来覆盖这一点,因为问题的根源是请求了一个格式不正确的URI组件,应该是UTF-8,但它不是。爬虫/机器人应该关注这个问题。

// middleware for responding with BAD REQUEST
app.use(function (err, req, res, next) {
    if (err instanceof URIError) {
        res.status(400).send();
    }
});

总之,试图针对格式错误的URI返回结果会产生其他副作用。首先,您将允许一个错误的请求 - 这不是好事:)。其次,它将意味着您有一个错误URI的结果,当网络爬虫/机器人获得200 OK响应并且它被传播时,它将被存储。然后,您将不得不处理更多错误的请求。

总而言之,不要通过unescape进行解码。Express已经尝试通过合适的方法进行解码:decodeURIComponent。如果失败了,就让它保持原样。


1
这与我们的想法相符,也是我们将要推进的方向。感谢对问题的详细回答。享受你的奖励,不要一次吃光它! :) - Raoul

1
Node.js queryString 库具有安全的 escapeunescape 方法实现。它们都使用 utf-8 编码。当 unescape 方法失败时,它首先尝试使用 decodeURIComponent,然后再尝试使用安全快速替代实现
> querystring.escape('ö')
'%C3%B6'
> querystring.unescape('%C3%B6')
'ö'

但是你有一个latin-1编码的字符串(%F6而不是%C3%B6),所以querystring.unescape会给出意外的结果,但它不会破坏你的代码:

> querystring.unescape('Bj%F6rk')
'Bj�rk'

你可能可以使用iconviconv-lite软件包将从latin1转换为utf-8,并获得正确的字符串。但URL编码应该是UTF-8。因此,我认为可以安全地忽略其他编码的字符串,只需使用querystring.unescape即可。
在 Express 4.7.x 中,您可以将 query parser 配置设置为 simple,以使用 querystring.parse,该方法内部使用 querystring.unescape
app.set('query parser', 'simple') // or 'extended' to use 'qs' module

0

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