如何在 express 中处理非 UTF-8 编码的 url

How to deal with non UTF-8 encoded urls in express

我们有一个节点 js 应用程序,我们最近从 IIS 7 上的 运行(通过 IIS 节点)转移到 Linux (Elastic Beanstalk) 上的 运行。自从我们切换后,我们收到了很多非 UTF-8 url 发送到我们的应用程序(主要来自爬虫),例如:

Bj%F6rk,IIS 正在将其转换为 Björk。现在将其传递给我们的应用程序,我们的 Web 框架 (express) 最终会调用

decodeURIComponent('Bj%F6rk'); URIError: URI malformed at decodeURIComponent (native) at repl:1:1 at REPLServer.self.eval (repl.js:110:21) at repl.js:249:20 at REPLServer.self.eval (repl.js:122:7) at Interface.<anonymous> (repl.js:239:12) at Interface.emit (events.js:95:17) at Interface._onLine (readline.js:203:10) at Interface._line (readline.js:532:8) at Interface._ttyWrite (readline.js:761:14)

在发送 url 字符串到 express 之前,是否有推荐的安全方法可以执行与 IIS 相同的转换?

谨记

  1. 我们正在接收对这些编码错误的 URL 的请求,并且
  2. 有一种方法可以使用 deprecated unescape javascript function
  3. 来解码它们
  4. 这些 URL 的大部分请求来自 Bing 机器人,我们希望尽量减少对我们搜索排名的不利影响。

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

Node.js queryString library has safe implementation of escape and unescape methods. They both uses utf-8 encoding. unescape first tries decodeURIComponent and when fails it tries with a safe fast alternative implementation.

> 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 encoding 应该是 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

Should we really be doing this for all incoming URLs?

不,你不应该。发出的请求使用非 UTF8 URI 组件。那不应该是你的问题。

Are there any security or performance implications we should be concerned about?

URI 组件的编码不是安全问题。通过查询字符串或路径参数的注入尝试是。但那是另一个话题。在性能方面,每个中间件都会使您的响应时间更长一些。但我什至不会为此担心。如果你想自己解码 URI,那就去做吧。只需几毫秒。

Should we be concerned about unescape being removed in the near future?

实际上你应该。 unescape 已弃用。如果你还想使用它;先检查它是否存在。即 'unescape' in global。您还可以使用内置替代项:require('querystring').unescape(),它不会在每种情况下产生相同的结果,但不会抛出 URIError。 (虽然不推荐)。

尽量减少对搜索排名的不利影响:

确定在这些情况下您的快捷应用 return 的状态代码。它可能是 500 (INTERNAL SERVER ERROR) 看起来很糟糕,而 404 (NOT FOUND) 会告诉爬虫你没有查询的结果(可能不是真的)。

在这些情况下,我建议您改写 return 客户端错误,例如 400 (BAD REQUEST),因为问题的根源是请求格式错误的 URI 组件,它应该是 UTF-8,但不是。 crawler/bot 应该关注这一点。

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

最重要的是,尝试 return 格式错误的 URI 的结果会产生其他副作用。首先,您将允许一个错误的请求 — 不可能是好的 :)。其次,这意味着你有一个错误的 URI 结果,当 crawlers/bots 收到 200 OK 响应时,它将被存储,并且它会传播。然后你将不得不处理更多的错误请求。

总结;不要通过 unescape 解码。 Express 已经尝试通过正确的方式解码:decodeURIComponent。如果失败了,就让它过去吧。

我推荐 Nodejs decode-uri-charset,https://www.npmjs.com/package/decode-uri-charset

var url_decode = require('decode-uri-charset');
console.log(url_decode('%C7%CF%C0%CC', 'euc-kr'))