web-dev-qa-db-ja.com

外部ソース(Excel、Wordなど)からリンクをクリックすると、Cookieが認識されない理由

ExcelやWordなどのWebブラウザーから外部でリンクをクリックすると、同じブラウザーウィンドウの新しいタブでリンクが開いても、セッションCookieが最初は認識されないことに気付きました。

ブラウザーは最終的にそのCookieを認識することになりますが、ExcelまたはWordからの初期リンクが機能しない理由については困惑しています。さらに難しくするために、リンクをクリックするとOutlookで正常に機能します。

なぜこれが起こっているのか知っていますか?私はZend FrameworkをPHP 5.3。

58
Nick

これは、MS OfficeがHlink.dllコンポーネントを使用して、リンクがOfficeドキュメントまたは他の何かであるかどうかを検索するためです。 MS Officeは、(IE6のHlink.dllコンポーネントを使用して)外部ブラウザの助けを借りずにドキュメント内でリンクされたドキュメントを開くことを期待しています。

セッションCookieがWebサイトを保護している場合、Hlinkはログインページに自然にリダイレクトされ、HTMLページに到達して「理解」できないため、外部ブラウザで開きます。元のURL(予期される動作)ではなく、リダイレクトの結果(302リダイレクトであっても)を開くことに注意してください。

マイクロソフトは、サポートされていないコンポーネント(Hlink.dll)にバグを抱えており、バグを認識する代わりに 頭に返して (使用しているSSOシステム、つまりセッションCookieの欠陥であると確信させようとしています。 )アップグレードを拒否します。 検索機能をオフにする回避策 MS Officeを提供します:

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

または、HTTPリダイレクトを回避し、JavascriptリダイレクトまたはMETA REFRESHリダイレクトに変更する(つまり、Hlinkに元のURLのtext/htmlページを取得させ、外部ブラウザーを実行して処理させる)ために、サーバーサイドの回避策を提供します。

75
myroslav

この同じ問題があり、Railsを使用しているユーザーを支援するオープンソースgemを作成しました。 https://github.com/spilliton/fix_Microsoft_links

ただし、どのフレームワークでも使用したのと同じアプローチを使用できます。

  1. ユーザーエージェントがMicrosoft製品からのものかどうかを検出する
  2. ブラウザーが正しいCookieでページを更新するようにするメタ更新タグを使用して、空白のhtmlページをレンダリングします

サンプルコード: https://github.com/spilliton/fix_Microsoft_links/blob/master/lib/fix_Microsoft_links.rb

17
spilliton

これは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>
12
Martin Lee

上記のスピリトンの答えに基づいた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();
        }
    }
6
Mike

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とともに受信されます。

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();
    }
}

..このコードの後に​​リダイレクト

5
Tim Smith

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>
2
Teimuraz

これがWordPressでの私の解決策です。これをテーマのfunctions.phpまたは別のプラグインファイルに追加します。

これは、WPなどのシステムが、ログアウトしようとしたユーザーを、アクセスしようとしたページへのリダイレクトを含むログインページに送信する場合に役立ちます。 Wordはこのページにユーザーを送信していましたが、WPはユーザーが既にログインしている場合を適切に処理していませんでした。その場合、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');
1
strangerstudios

彼らがこれを機能と呼んでいるとは信じられない。ただし、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]

空の応答の代わりにページ全体が送信されるため、最高のパフォーマンスではないかもしれませんが、このようなidio ^ H ^ H ^ H ^ H機能を修正するためだけに別のApacheモジュールを追加したくありませんでした。

1
tbart

MS WordからURLをクリックすると、TWO Chromeタブが開かれ、開くページにJavaScriptリダイレクトがあります:window.location.href=blabla

サーバー側からデバッグすることで、Chrome以外にOfficeアプリから送信されたリクエストがあることを確認しました。これはとても奇妙です。

しかし、とにかく、リクエストヘッダー「User-Agent」を確認し、Officeアプリに空のページを返すことで、2つのタブの問題が解決されました。それは間違いなく正しいことです!

1
hailong

Excel用のVBA修正を以下に示します。同じ概念をMicrosoft Wordに適用できます。基本的に、コードはExcel内からリンクを起動するのではなく、シェル内からリンクを実行します。コードは次のとおりです。

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
  1. リンクを含むExcelシートの場合、シートタブを右クリックし、コードの表示をクリックします。 VBAエディターが表示されます。
  2. コードをウィンドウに貼り付けて、エディターを閉じます。
  3. ページ内の各リンクを変更して、それが含まれているセルを単純に指すようにします。
  4. リンクを右クリックして、ハイパーリンクの編集をクリックします。 [ハイパーリンクの編集]ウィンドウが表示されます。
  5. このドキュメントに配置をクリックします。
  6. シート名をクリックします。
  7. セル参照を入力の場合、セル参照(A4など)を入力します。
  8. [〜#〜] ok [〜#〜]をクリックします。

いくつかのメモ:

  • スプレッドシートをマクロ対応スプレッドシート(​​.xlsm)として保存する必要があります。ユーザーがスプレッドシートを開くと、マクロを有効にするよう求められます。回答が「いいえ」の場合、リンクは機能しません。
  • これらの手順はExcel 2010に基づいています。おそらく後のバージョンも同様です。
1
Squidx3

以下のリンクからMicrosoftが提供する修正プログラムを使用してください。 https://support.Microsoft.com/en-us/kb/21815

0
Tushar Patel

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関数を次から取得しました: RLパラメーターから値を取得する方法?

0
RIanGillis

ドットネットコアミドルウェアを使用した修正の例を次に示します。

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);
    }
}

JavaとFilter経由の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;
  }
}