为啥从外部来源(即 Excel、Word 等)单击链接时 cookie 无法识别

Posted

技术标签:

【中文标题】为啥从外部来源(即 Excel、Word 等)单击链接时 cookie 无法识别【英文标题】:Why are cookies unrecognized when a link is clicked from an external source (i.e. Excel, Word, etc...)为什么从外部来源(即 Excel、Word 等)单击链接时 cookie 无法识别 【发布时间】:2011-02-08 20:45:00 【问题描述】:

我注意到,当从 Web 浏览器(例如 Excel 或 Word)外部单击链接时,我的会话 cookie 最初无法识别,即使该链接在同一浏览器窗口的新选项卡中打开也是如此。

浏览器最终会识别出它的 cookie,但我不明白为什么 Excel 或 Word 的初始链接不起作用。为了使其更具挑战性,在 Outlook 中单击链接可以正常工作。

有人知道为什么会发生这种情况吗?我正在使用带有 php 5.3 的 Zend 框架。

【问题讨论】:

我认为这个问题与框架、会话甚至 php 无关。但更多的浏览器相关。您使用什么浏览器,您是否尝试过其他浏览器?它会发送任何 cookie 吗? 这发生在 IE8、Chrome 和我相信 Firefox 中。在调试时,似乎没有发送 cookie 或正在创建新的 cookie - 我无法确认。但我确信没有发送正确的 cookie。 【参考方案1】:

在 ColdFusion / Lucee 中

<cfif cgi.HTTP_USER_AGENT contains "Excel" OR cgi.HTTP_USER_AGENT contains "ms-office">
    <cfabort/>
</cfif>

【讨论】:

【参考方案2】:

nginx 解决方案如下:

if ($http_user_agent ~* Word|Excel|PowerPoint|ms-office) 
    return 200 '<html><head><meta http-equiv="refresh" content="0"/></head><body></body></html>';

您可以将其放在serverlocation 块中。 像魅力一样工作。

【讨论】:

【参考方案3】:

以下是使用 dotnet 核心中间件进行修复的示例:

public class MicrosoftOfficeLinksHandlingMiddleware

    private static readonly Regex MsUserAgentsRegex = new Regex(@"[^\w](Word|Excel|PowerPoint|ms-office)([^\w]|\z)");
    private readonly RequestDelegate _next;

    public MicrosoftOfficeLinksHandlingMiddleware(RequestDelegate next)
    
        _next = next;
    

    public async Task Invoke(HttpContext context)
    
        string userAgent = context.Request.Headers["User-Agent"].FirstOrDefault();

        if (userAgent != null && MsUserAgentsRegex.IsMatch(userAgent))
        
            // just return an empty response to the office agent
            return;
        

        await _next(context);
    

【讨论】:

【参考方案4】:

我们发现从 MS Word 中单击 URL 时会打开两个 Chrome 选项卡,并且要打开的页面有 javascript 重定向:window.location.href=blabla

通过从服务器端调试,我们确认除了 Chrome 之外,还有来自 Office 应用程序的请求。这太奇怪了。

但无论如何,通过检查请求标头“User-Agent”,并向 Office 应用返回一个空白页面,我们的两个选项卡问题得到了解决。这绝对是正确的做法!

【讨论】:

您从 Office 应用中看到了什么用户代理?【参考方案5】:

这是通过过滤器使用 Java 和 Spring 解决此问题的方法:

/**
 * To see why this is necessary, check out this page:
 * https://support.microsoft.com/en-gb/help/899927.
 */
public class MicrosoftFilter extends OncePerRequestFilter 
  @Override
  protected void doFilterInternal(final HttpServletRequest request,
      final HttpServletResponse response,
      final FilterChain filterChain) throws ServletException, IOException 
    //Serve up a blank page to anything with a Microsoft Office user agent, forcing it to open the
    //URL in a browser instead of trying to pre-fetch it, getting redirected to SSO, and losing
    //the path of the original link.
    if (!request.getHeader("User-Agent").contains("ms-office")) 
      filterChain.doFilter(request, response);
    
  


/**
 * Security configuration.
 */
@Configuration
public class SecurityConfiguration 
  @Bean
  public FilterRegistrationBean microsoftFilterRegistrationBean() 
    FilterRegistrationBean<MicrosoftFilter> registrationBean = new FilterRegistrationBean<>();
    registrationBean.setFilter(new MicrosoftFilter());
    registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
    return registrationBean;
  

【讨论】:

首先,我简直不敢相信我什至发现了这个问题...很高兴有针对这么多平台的解决方案...但是Java是我需要的...谢谢大家!【参考方案6】:

我不敢相信他们称这是一项功能。 但是,这里有一个针对 Apache 的功能修复:

RewriteEngine On

# Send a 200 to MS Office so it just hands over control to the browser
# It does not use existing session cookies and would be redirected to the login page otherwise
# https://www.wimpyprogrammer.com/microsoft-office-link-pre-fetching-and-single-sign-on/

RewriteCond %HTTP_USER_AGENT ;\sms-office(\)|;)
RewriteRule .* - [R=200,L]

可能不是最佳性能,因为整个页面被发送而不是空响应,但我不想添加另一个 Apache 模块只是为了修复这样的 idio^H^H^H^H 功能。

【讨论】:

【参考方案7】:

这是针对 Excel 的 VBA 修复程序。相同的概念可以应用于 Microsoft Word。基本上,代码不是从 Excel 中触发链接,而是从 shell 中执行链接。 代码如下:

Private Sub Worksheet_FollowHyperlink(ByVal objLink As Hyperlink)
    Application.EnableEvents = False
    Dim strAddress As String
    strAddress = "explorer " & objLink.TextToDisplay
    Dim dblReturn As Double
    dblReturn = Shell(strAddress)
    Application.EnableEvents = True
End Sub
    对于包含链接的 Excel 工作表,右键单击工作表选项卡,然后单击查看代码。出现 VBA 编辑器。 将代码粘贴到窗口中,然后关闭编辑器。 修改页面中的每个链接,使其简单地指向它所在的单元格。这样做: 右键单击链接,然后单击编辑超链接。将出现“编辑超链接”窗口。 点击置入本文档。 点击工作表名称。 对于键入单元格引用,输入单元格引用(例如 A4)。 点击确定

几点说明:

您需要将电子表格保存为启用宏的电子表格 (.xlsm)。当用户打开电子表格时,他们将被要求 启用宏。如果他们回答否,链接将不起作用。 这些说明基于 Excel 2010。大概以后的版本是类似的。

【讨论】:

大概,在 OS X 上,这需要使用 'open' 而不是 'explorer'... 或者这种方法甚至可以在 Mac 上使用?【参考方案8】:

服务器端这在 IIS 中对我有用(使用重写规则)

<rule name="WordBypass" enabled="true" stopProcessing="true">
    <match url=".*" />
    <conditions>
        <add input="HTTP_USER_AGENT" pattern="Word|Excel|PowerPoint|ms-office" />
    </conditions>
    <action type="CustomResponse" statusCode="200" statusReason="Refresh" statusDescription="Refresh" />
</rule>

【讨论】:

这对我的 MVC5 应用程序来说是快速简单的修复。我根据需要定制了图案。请注意,这需要在 Web 服务器上安装 Microsoft Url Rewrite 软件。 iis.net/downloads/microsoft/url-rewrite 在 IIS 中纠正这种行为比应用程序本身更好 这对我的 ASP.Net 4.5 Web 表单应用程序来说就像一个魅力。万分感谢! @马丁 我将代码放在应用程序的 web.config 文件中,效果很好。【参考方案9】:

使用下面给出的 microsoft 提供的修复链接。 https://support.microsoft.com/en-us/kb/218153

【讨论】:

此链接已在接受的答案中提及。此外,此处建议的解决方案对跨所有 Office 产品的链接功能产生了巨大影响。【参考方案10】:

我必须为一个 ASP.NET 网站解决这个问题,但我只想使用 javascript/jQuery:

var isCoBrowse = ('<%= Session["user"].ToString().ToLower() %>' != '0');
if (isCoBrowse && window.location.href.indexOf('ReturnUrl=') >= 0 && window.location.href.indexOf('dllCheq') == -1) 
    //redirect to the ReturnUrl & add dllCheq to the URI
    var toRedirect = decodeURIComponent(gup('ReturnUrl', window.location.href)) + '&dllCheq';
    window.location = toRedirect;

我从以下位置获得了 gup 函数: How to get the value from the URL parameter?

【讨论】:

【参考方案11】:

PHP解决方案:

这会阻止 MS 产品识别重定向。因此,MS 从所需链接启动浏览器。

if (isset($_SERVER['HTTP_USER_AGENT']))

    $http_user_agent = $_SERVER['HTTP_USER_AGENT']; 
    if (preg_match('/Word|Excel|PowerPoint|ms-office/i', $http_user_agent)) 
    
        // Prevent MS office products detecting the upcoming re-direct .. forces them to launch the browser to this link
        die();
    

.. 在这段代码之后重定向

【讨论】:

这在 2021 年仍然对我有用。我遇到了 Excel 链接问题,但 Power Point 工作正常。【参考方案12】:

这是基于上述spilliton 回答的C# ASP.NET 解决方案。在 Global.asax.cs 中,添加以下内容:

    private static string MSUserAgentsRegex = @"[^\w](Word|Excel|PowerPoint|ms-office)([^\w]|\z)";
    protected void Application_OnPostAuthenticateRequest(object sender, EventArgs e)
    
        if (System.Text.RegularExpressions.Regex.IsMatch(Request.UserAgent, MSUserAgentsRegex))
        
            Response.Write("<html><head><meta http-equiv='refresh' content='0'/></head><body></body></html>");
            Response.End();
        
    

【讨论】:

我还会在检查正则表达式之前添加一个检查请求是否经过身份验证。在每个请求上将 userAgent 与正则表达式进行匹配可能会导致性能问题。【参考方案13】:

为 VB.NET 修复:

Dim userAgent As String = System.Web.HttpContext.Current.Request.UserAgent

If userAgent.Contains("Word") Or userAgent.Contains("Excel") Or userAgent.Contains("PowerPoint") Or userAgent.Contains("ms-office") Then
       System.Web.HttpContext.Current.Response.Clear()
       System.Web.HttpContext.Current.Response.Write("<html><head><meta http-equiv='refresh' content='0'/></head><body></body></html>")
       System.Web.HttpContext.Current.Response.End()
End If

它基本上强制浏览器刷新页面,因此请求带有浏览器的用户代理和所有正确的 cookie。

【讨论】:

【参考方案14】:

1.从excel/word指向http://example.com/from_excel.php

2.在“from_excel.php”中重定向到你使用会话的页面

<script>document.location.href = "http://example.com/page_with_session.php"; </script>

【讨论】:

【参考方案15】:

我们遇到了同样的问题并编写了一个开源 gem 来帮助那些使用 Rails 的人:https://github.com/spilliton/fix_microsoft_links

您可以使用我们在任何框架上使用的相同方法:

    检测用户代理是否来自 Microsoft 产品 使用元刷新标记呈现空白 html 页面,这将导致浏览器使用正确的 cookie 刷新页面

此处的示例代码:https://github.com/spilliton/fix_microsoft_links/blob/master/lib/fix_microsoft_links.rb

【讨论】:

这个 gem 是一个很好的解决方案。 伙计,非常感谢你。我用你的代码为 express.js 构建了一个中间件github.com/auth0/fix-office-link 没问题!很高兴它被证明有用:)【参考方案16】:

我怀疑这是你如何设置 cookie 的问题。

由于网络创建方式的性质,example.com 与www.example.com 不被视为同一个域;因此:您可以在www.example.com 登录,而不是在example.com 登录。

也就是说,检查您的 word 或 excel 文件中的 URL - 它与您在浏览器中的登录方式是否相同?

此 cookie 不一致有两个修复/解决方案: 1. 重定向任何试图在没有 www 的情况下加载您的网站的人。到与 www 相同的页面。 (反之亦然),或 2. 设置 cookie 时,确保将域参数指定为“.example.com”。前导点表示 cookie 在该域的所有子域上也应该有效。

我怀疑浏览器最终识别它的原因是因为您最终可能会登陆一个与您登录方式具有相同域结构的 URL。

希望这会有所帮助。

【讨论】:

【参考方案17】:

这是我在 WordPress 中的解决方案。将此添加到您的主题或其他插件文件中的 functions.php 中。

如果您的系统(如 WP)将已注销的用户发送到登录页面并重定向到他们尝试访问的页面,这可能会有所帮助。 Word 将用户发送到此页面,但随后 WP 没有正确处理用户已经登录的情况。此代码检查是否存在当前用户和传递的 redirect_to 参数。如果是这样,它会重定向到 redirect_to 位置。

function my_logged_in_redirect_to()

global $current_user;

if($current_user->ID && $_REQUEST['redirect_to'])
           
    wp_redirect($_REQUEST['redirect_to']);
    exit;


add_action('wp', 'my_logged_in_redirect_to');

【讨论】:

【参考方案18】:

这是因为 MS Office 正在使用 Hlink.dll 组件来查找链接是否为 Office 文档或其他内容。 MS Office 希望无需外部浏览器(使用 IE6 的 Hlink.dll 组件)即可打开文档中链接的文档。

如果会话 cookie 保护网站 Hlink 自然会被重定向到登录页面并到达 HTML 页面并且无法“理解”它在外部浏览器中打开它。请注意,它打开的不是原始 URL(预期行为)而是重定向的结果,即使它是 302 重定向。

Microsoft 在不受支持的组件 (Hlink.dll) 中存在该错误,而不是识别他们 turn it over to our head 的错误(试图说服我们这是我们使用的 SSO 系统的缺陷,即会话 cookie)并拒绝对其进行升级。它提供了workaround that turns off the lookup functionality的MS Office:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\
  Office\9.0\Common\Internet\ForceShellExecute:DWORD=1

或者为我们提供服务器端的解决方法,以避免 HTTP 重定向并更改为 Javascript 重定向或 META REFRESH 重定向(即让 Hlink 在原始 URL 上获取 text/html 页面并使其运行外部浏览器来处理它)。

【讨论】:

谢谢,它帮助了我!你那里有链接,但无论如何我都会输入这个。对于 64 位版本的 Windows 上的 32 位版本的 Office,密钥是 HKLM\SOFTWARE\Wow6432Node\Microsoft\Office\9.0\Common\Internet\ ,是的,对于 MS Office 2013,它仍然是 9.0 他们多么邪恶地试图将此归咎于 SSO。 有人可以更新这个以获得最新的 Microsoft Office 吗? 所以 11 年后打破 SSO,这个问题仍然没有得到解决。我今天遇到这个问题后找到了这个答案,没有我几年前遇到过的记忆,甚至在这里留下了评论。 @AmitNaidu 我在\SOFTWARE\Microsoft\Office\\SOFTWARE\Wow6432Node\Microsoft\Office\ 都找不到这个 9.0 注册表路径,你知道它是否改变了吗?

以上是关于为啥从外部来源(即 Excel、Word 等)单击链接时 cookie 无法识别的主要内容,如果未能解决你的问题,请参考以下文章

为啥考核表用word不用excel

为啥从 Word doc 调用宏时出现错误 1004,而不是从 Excel 调用?

在网页编辑器中粘贴时如何保留WORD中的表格

为啥word文档插入图片不显示

为啥在桌面上点击右键,在新建栏里却没有word文档?

为啥打开EXCEL或PPt文档就出现下面安装project