【问题标题】:XMLHttpRequest File Upload with NTLM - File is being uploaded twice使用 NTLM 上传 XMLHttpRequest 文件 - 文件上传两次
【发布时间】:2013-01-10 13:36:03
【问题描述】:

我目前正在开发一个涉及使用 XMLHttpRequest 进行异步文件上传的 Web 应用程序。

当使用 NTLM 身份验证(这有点必要)时,异步 POST 最终会被发送两次。第一次响应是 401,第二次是 200。由于 NTLM 的挑战/响应性质,这是我所期望的,但我想知道是否有办法避免发送文件数据两次(特别是因为上传的文件可能非常大),可能是通过某种方式先发送一个空请求以在发送实际数据之前触发 401。

【问题讨论】:

    标签: javascript post xmlhttprequest


    【解决方案1】:

    在浏览器中,由于 HTTP 和 NTLM 身份验证协议的性质,您无法避免这种情况。

    但是,我不认为整个文件的数据实际上被发送了两次。

    我将以下内容发送到 IIS 7.5 上受 NTLM 保护的文件:

    POST /test/upload HTTP/1.1
    Host: localhost
    Content-Length: 5
     
    

    请注意,我实际上并没有发送任何内容,只发送了完整的标题。然而,IIS立即回应:

    HTTP/1.1 401 Unauthorized
    Cache-Control: private
    Content-Type: text/html; charset=utf-8
    Server: Microsoft-IIS/7.5
    WWW-Authenticate: Negotiate
    WWW-Authenticate: NTLM
    Date: Thu, 10 Jan 2013 05:17:58 GMT
    Content-Length: 6277
    
    ...
    

    这意味着如果我是一个上传大文件的浏览器,在我传输很多字节之前我就会被切断。我假设(希望)任何表现良好的浏览器都会放弃文件上传并开始 HTTP 身份验证。

    也许值得你花时间去看看像 Wireshark 这样的东西,看看实际发生了什么。 (记得用不同的浏览器进行测试!)不要相信浏览器内的开发者工具,也不要使用像 Fiddler 这样的调试代理。 (事实上​​,如果您使用的是 Fiddler,这实际上可能是问题所在:它会在将 anything 发送到服务器之前缓冲 整个 请求。)

    如果您确实发现整个文件确实被完整上传了两次(也许旧版本的 IIS 没有立即发送 401?),请考虑一下事情必须如何发生:

    1. 用户提交上传,导致浏览器向服务器发出POST 请求。因为浏览器不可能知道 URL 是否需要认证,它只是发送 complete 请求。

      POST /upload HTTP/1.1
      Content-Type: mutlipart/form-data
      Content-Length: 1024
      
      ...
      
    2. 服务器可能会立即响应 401,但行为不佳的用户代理会传输整个请求。

    3. 一旦请求完成并且浏览器看到401,我们就会开始NTLM dance。客户端必须发出带有Type 1 消息的新请求,服务器以另一个401 响应,这次包含Type 2 消息,最后客户端发出带有Type 3 的第三个​​请求包含实际凭据的消息。

      由于客户端知道第二个请求在 NTLM 协商中保证是另一个401,它知道它可以跳过实体(表单数据)的传输。但是,它必须在第三次请求时再次发送 post 数据,因为我们必须假设服务器丢弃了原始请求数据。

    4. 我们的文件终于上传了! (但它必须传输两次。)

    因此,虽然我认为您不会真正看到 NTLM 身份验证的完整双重上传问题,但您可能仍希望消除这种可能性。以下是我的处理方法:

    将上传 URL 移出 NTLM 认证区域。在上传页面(经过 NTLM 身份验证)上,使用会话 cookie(在加载页面时设置)或发出令牌 - 隐藏字段中的 GUID 就足够了。

    接收上传的脚本可以拒绝任何没有有效会话和/或令牌的请求。

    如果您使用 NTLM 凭据作为授予对 NTFS 资源的访问权限的机制,则可以将上传文件写入匿名可写临时文件夹,完成后,将请求重定向到第二个受 NTLM 保护的脚本,该脚本会移动文件到它的目的地。

    【讨论】:

    • 您可能是对的,这是某种特定于 UserAgent 的问题。文件上传本身是由第三方 JS 插件通过构造 XMLHttpRequest 并上传文件来完成的。引发此讨论的原因是您可以看到进度条以相同的速度旋转两次。我将看看 Wireshark 看看会发生什么。
    • 对 Wireshark 进行了更深入的研究,这似乎是 Chrome 的一个问题。如果您访问的 URL 是受信任的站点,它会使用 GSS-API 发送 Kerberos 和 NTLM 身份验证详细信息。 Kerberos 被赋予更高的优先级,因此 IIS 决定使用它。每个请求都会发生 Kerberos 身份验证,因此通过在 IIS 上禁用 Kerberos,身份验证是使用基于连接的 NTLM 完成的,因此 401 仅发生在第一个请求上。 =)
    • 啊,完美。这是我在帖子中没有提到的——使用 NTLM 身份验证,一旦客户端成功通过身份验证,IIS 将发送(专有?)Persistent-Auth: true 标头。这表明客户端不需要为后续请求重新发送Authorization 标头通过相同的 TCP 连接
    • 另外,there's a setting that enables Persistent-Auth for Kerberos,如果您发现您确实需要它。 (Kerberos 比 NTLM 更安全,因此可能值得研究。)
    • 很遗憾,使用此软件的客户不太可能正确设置 Kerberos,因此我们至少目前需要支持 NTLM,但无论如何感谢!
    【解决方案2】:

    不确定您的实现,但看起来其他人在使用 cURL 和 NTLM 时遇到了类似的问题。根据下面的链接,您首先提出任何空请求的想法可能会奏效。

    通过 NTLM 代理两次发布文件
    http://curl.haxx.se/mail/lib-2007-01/0040.html

    我正在使用 curl_formadd 和 POST 方法通过代理发送文件 NTLM 身份验证。查看 ProgressFunction,我看到我的文件发送了两次 (可能是因为特定于 NTLM)。我说的对吗?

    你是对的。使用 NTLM 时无法避免这种情况,因为我们 传输一旦开始就无法中止。

    使用 NTLM/协商代理身份验证的不同文件上传行为
    http://curl.haxx.se/mail/archive-2012-11/0013.html

    【讨论】:

      猜你喜欢
      • 2013-06-12
      • 2012-05-15
      • 2011-09-06
      • 2013-01-17
      • 1970-01-01
      相关资源
      最近更新 更多