web-dev-qa-db-fra.com

Pourquoi les cookies ne sont pas reconnus lorsqu'un clic sur un lien provient d'une source externe (Excel, Word, etc.)

J'ai remarqué que lorsqu'un cookie est cliqué en externe à partir du navigateur Web, tel que Excel ou Word, mon cookie de session est initialement non reconnu, même si le lien s'ouvre dans un nouvel onglet de la même fenêtre de navigateur.

Le navigateur finit par reconnaître son cookie, mais je ne comprends pas pourquoi ce lien initial d'Excel ou de Word ne fonctionne pas. Pour rendre la tâche encore plus difficile, cliquer sur un lien fonctionne bien à partir d'Outlook.

Est-ce que quelqu'un sait pourquoi cela pourrait se produire? J'utilise le Zend Framework avec PHP 5.3.

54
Nick

En effet, MS Office utilise le composant Hlink.dll pour rechercher si le lien est un document Office ou autre chose. MS Office s’attend à ouvrir le document lié dans les documents sans l’aide d’un navigateur externe (à l’aide du composant Hlink.dll de IE6).

Si le cookie de session protège le site Web, Hlink est naturellement redirigé vers la page de connexion et ayant atteint la page HTML sans pouvoir le "comprendre", il l'ouvre dans un navigateur externe. Notez qu'il n'ouvre pas l'URL d'origine (comportement attendu) mais le résultat de la redirection, même s'il s'agissait d'une redirection 302.

Microsoft a ce bogue dans le composant non pris en charge (Hlink.dll), au lieu de reconnaître le bogue, il le renvoie à notre tête (essayant de nous convaincre que c’est la faille du système SSO que nous utilisons, c’est-à-dire les cookies de session) et refuse pour le mettre à niveau. Il offre une solution de contournement qui désactive la fonctionnalité de recherche de MS Office:

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

Ou offrez-nous de contourner le problème côté serveur, afin d'éviter les redirections HTTP et de passer aux redirections Javascript ou META REFRESH (c'est-à-dire que Hlink obtienne la page text/html de l'URL d'origine et le fasse exécuter un navigateur externe pour le gérer).

67
myroslav

Nous avons eu le même problème et avons écrit une gem open source pour aider les utilisateurs de Rails: https://github.com/spilliton/fix_Microsoft_links

Vous pouvez utiliser la même approche que nous avons utilisée sur n’importe quel framework:

  1. Détecter si l'agent utilisateur provient d'un produit Microsoft
  2. Rendre une page HTML vierge avec une balise meta refresh qui obligera le navigateur à actualiser la page avec les cookies appropriés

Exemple de code ici: https://github.com/spilliton/fix_Microsoft_links/blob/master/lib/fix_Microsoft_links.rb

16
spilliton

Côté serveur, cela fonctionnait pour moi dans IIS (à l'aide d'une règle de réécriture)

<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

Voici une solution pour C # ASP.NET basée sur la réponse de spilliton ci-dessus. Dans Global.asax.cs, ajoutez les éléments suivants:

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

Correction pour 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

Fondamentalement, il oblige le navigateur à actualiser la page. La demande est donc envoyée avec l'agent utilisateur du navigateur et tous les cookies appropriés.

Solution PHP:

Cela empêche le produit MS de reconnaître la redirection. MS lance donc un navigateur à partir du lien requis.

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

.. rediriger après ce code

4
Tim Smith

1.Dans Excel/Word, pointez sur http://example.com/from_Excel.php

2.Dans "from_Excel.php" redirige vers la page où vous utilisez la session

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

Voici ma solution pour cela dans WordPress. Ajoutez ceci à functions.php dans votre thème ou dans un autre fichier plugin. 

Cela peut être utile si votre système, tel que WP, envoie les utilisateurs déconnectés à une page de connexion avec une redirection vers la page à laquelle ils essayaient d'accéder. Word envoyait des utilisateurs à cette page, mais WP ne gérait pas correctement le cas où un utilisateur était déjà connecté. Ce code vérifie si un utilisateur actuel et un paramètre redirect_to sont passés. Si c'est le cas, il redirige vers l'emplacement 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

Nous constatons un problème lorsque deux onglets Chrome sont ouverts lorsque vous cliquez sur une URL à partir de MS Word et que la page à ouvrir comporte une redirection JavaScript: window.location.href=blabla

En déboguant du côté des serveurs, nous avons confirmé qu'il y avait des demandes envoyées à partir de l'application Office, en plus de Chrome. C'est tellement bizarre.

Quoi qu'il en soit, en vérifiant l'en-tête de la requête "User-Agent" et en renvoyant une page vide aux applications Office, notre problème DEUX onglets a été résolu. C'est définitivement la bonne chose à faire!

1
hailong

Voici un correctif VBA pour Excel. Le même concept peut être appliqué à Microsoft Word. Fondamentalement, plutôt que de déclencher le lien à partir d'Excel, le code exécute le lien à partir d'un Shell . Voici le code:

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. Pour la feuille Excel contenant les liens, cliquez avec le bouton droit de la souris sur l’onglet Feuille et cliquez sur Afficher le code. L'éditeur VBA apparaît.
  2. Collez le code dans la fenêtre et fermez l'éditeur.
  3. Modifiez chaque lien de la page pour qu'il pointe simplement vers la cellule dans laquelle il se trouve. Pour ce faire:
  4. Cliquez avec le bouton droit sur le lien, puis cliquez sur Modifier le lien hypertexte. Une fenêtre Modifier un lien hypertexte apparaît.
  5. Cliquez placer dans ce document.
  6. Cliquez sur le nom de la feuille.
  7. Pour Tapez la référence de cellule, entrez une référence de cellule (par exemple, A4).
  8. Cliquez sur OK.

Quelques notes:

  • Vous devrez enregistrer la feuille de calcul sous forme de feuille de calcul prenant en charge les macros (. Xlsm). Lorsque les utilisateurs ouvrent la feuille de calcul, il leur sera demandé d'activer les macros S'ils répondent non, les liens ne fonctionneront pas. 
  • Ces instructions sont basées sur Excel 2010. Il est probable que les versions ultérieures soient similaires.
1
Squidx3

Utilisez le correctif fourni par Microsoft avec le lien ci-dessous. https://support.Microsoft.com/en-us/kb/218153

0
Tushar Patel

Je devais résoudre ce problème pour un site ASP.NET mais je voulais seulement utiliser 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;
}

J'ai eu la fonction gup de: Comment obtenir la valeur du paramètre d'URL?

0
RIanGillis

Je ne peux pas croire qu'ils appellent cela une fonctionnalité . Cependant, voici une fonctionnalité pour 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]

Les performances ne seraient peut-être pas optimales, car toute la page était envoyée au lieu d'une réponse vide, mais je ne voulais pas ajouter un autre module Apache uniquement pour corriger une telle fonctionnalité. 

0
tbart

Voici un exemple de solution utilisant un middleware de base 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);
    }
}
0

Voici comment résoudre ce problème avec Java et Spring via un filtre:

/**
 * 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;
  }
}
0