[奇怪的Chrome行为]好比是本来想分享新闻却分享了Pxxxxxb一般的故事

Update on 2021.06.01

Chrome更改了判断链接分享的行为,如果网站以Http方式访问,将不会提取canonical meta头.同时要求canonical头必须也为https时才提取canonical头用于分享.从防御中间人攻击的角度来看,在不可保证真实性的HTTP上禁用这个feature有安全方面考量,但是个人感觉更合理的处理方式应当是判断两个URL是否在同一域中,这样可以最大限度防止滥用.

Demo

Demo
使用移动端Chrome进入Demo,选择更多菜单中的分享...功能,你会发现你分享的网址其实是.....

受影响的版本

Chrome Mobile (及开源衍生版本)截止最新版本(88.0.4324.152) iOS/Android 均受影响
Microsoft Edge Mobile 同样受影响
Chrome Desktop(似乎没有分享菜单)
Edge Desktop 有共享菜单 不受影响

Why

在Demo中,我们采用了一个很老的Meta Head,<link rel="canonical" href="">,这个在SEO优化中可用于指定本页面与某个页面链接的内容相同,但是Chrome在处理分享逻辑时,意外的选择了直接从此meta中提取URI并处理分享,导致了你可以自己定义用户分享的实际链接。翻了下源码,在Share的响应逻辑中,存在这样的逻辑:

// chromium/chrome/android/java/src/org/chromium/chrome/browser/share/ShareDelegateImpl.java
 private void triggerShare(final Tab currentTab, @ShareOrigin final int shareOrigin,
            final boolean shareDirectly, boolean isIncognito) {
   ...... 
 .......
                // Could not share as an offline page.
                if (shouldFetchCanonicalUrl(currentTab)) { //是否获取canonical的内容?
                    WebContents webContents = currentTab.getWebContents();
                    String title = currentTab.getTitle();
                    String visibleUrl = currentTab.getUrlString();
                    webContents.getMainFrame().getCanonicalUrlForSharing(new Callback<String>() {
                       //获取canonical的内容
                        @Override
                        public void onResult(String result) {
                            logCanonicalUrlResult(visibleUrl, result);

                            triggerShareWithCanonicalUrlResolved(window, webContents, title,
                                    visibleUrl, result, shareOrigin, shareDirectly, isIncognito);
                        }
                    });
                } else {//获取当前URI
                    triggerShareWithCanonicalUrlResolved(window, currentTab.getWebContents(),
                            currentTab.getTitle(), currentTab.getUrlString(), null, shareOrigin,
                            shareDirectly, isIncognito);
                }
            }
        });
    }

而在判断是否提取CanonicalUrl的语句中:

 @VisibleForTesting
    static boolean shouldFetchCanonicalUrl(final Tab currentTab) {
        WebContents webContents = currentTab.getWebContents();
        if (webContents == null) return false;
        if (webContents.getMainFrame() == null) return false;
        String url = currentTab.getUrlString();
        if (TextUtils.isEmpty(url)) return false;
        if (currentTab.isShowingErrorPage() || SadTab.isShowing(currentTab)) {
            return false;
        }
        return true;
    }

在页面内容存在且不为崩溃页面时均提取CanonicalUrl.
实际上,你还可以找到一些相关的介绍和Issue,最早可追溯到2018年:似乎这项特性被期望用于缩减跳转时加入的不必要的查询字符串,但是实际上却让服务端可能控制网页分享这项应当与服务端无关的行为:试想,如果分享链接被修改为恶意链接或广告链接呢?
https://github.com/mozilla-mobile/android-components/issues/4531
https://www.ghacks.net/2018/02/20/chrome-64-for-android-cuts-urls-automatically-when-you-share-them/

tag(s): none
show comments · back · home
Edit with markdown

仅有一条评论

  1. guest

    tql大佬

    guest June 10th, 2021 at 05:05 pm回复