不說符合同源策略的域名,因?yàn)槟欠N有N種辦法實(shí)現(xiàn),僅說 a.com 和 b.com 的情況
一、簡單方案,瀏覽器未阻止第三方追蹤
在 c.com 下創(chuàng)建一個(gè) store.html 頁面
<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body><script>
window.addEventListener("message", (e) => {
var payload = e.data;
switch(payload.method) {
case 'set':
localStorage.setItem(payload.key, JSON.stringify(payload.data));
break;
case 'get':
var data = localStorage.getItem(payload.key);
data = data ? JSON.parse(data) : null;
window.parent.postMessage({id:payload.id||null, data}, "*");
break;
case 'rem':
localStorage.removeItem(payload.key);
break;
}
}, false);
</script></body></html>
在其他所有域名,不限于 a.com 和 b.com, 可以是任意域名下使用以下 Js
let frame = document.createElement('iframe');
frame.style.display = 'none';
frame.src = 'http://c.com/store.html';
document.documentElement.appendChild(frame);
const callbacks = {};
let store = frame.contentWindow;
const receiveMsg = (e) => {
let msg = e.data;
if (!msg.id || !(msg.id in callbacks)) {
return;
}
const cb = callbacks[msg.id];
cb(msg.data);
};
window.addEventListener("message", checkMessage);
// 設(shè)置變量
const setStore = (key, data) => {
store.postMessage({method:'set', key, data}, '*');
}
// 讀取變量
const getStore = (key, cb) => {
const id = Date.now();
callbacks[id] = cb;
store.postMessage({method:'get', id, key}, '*');
}
// 移除變量
const remStore = (key) => {
store.postMessage({method:'rem', key}, '*');
}
這種方法在 chrome 下目前是適用的,以后就不曉得了,safari 瀏覽器已經(jīng)完全禁止了這種方法。在瀏覽器中有一個(gè)阻止第三方網(wǎng)站追蹤的選項(xiàng),默認(rèn)是打開的,不曉得以后 chrome 會(huì)不會(huì)這樣
二、有點(diǎn)麻煩的方案
我們需要在 a.com 下 設(shè)置/讀取 b.com 下的一個(gè)緩存值
前提:必須是 從 b.com -> 跳轉(zhuǎn)到 a.com 才可以, 如果直接打開的 a.com, 可根據(jù) query 或 header 的 referer 判斷讓其跳到 a.com 再跳回來
沒有代碼,僅列一下實(shí)現(xiàn)過程
打開 a.com 頁面, 設(shè)置一個(gè) cookie ,然后 302 到 b.com 頁面;該步驟中必須設(shè)置 cookie,path 設(shè)置為 /
在 b.com 下加載 a.com/dym?key=x&data=d ,將追蹤 cookie 傳遞給 a.com
// 測試發(fā)現(xiàn)之后 img 可行, xmlrequest / fetch 等都不行
//即使請求了, a.com 的 cookie 也無法保存
var img = new Image();
img.src = a.com/dym?method=set&key=x&data=d
a.com 收到請求, 重置 cookie,且只能重置步驟1中設(shè)置的 cookie
那么此時(shí)訪問 a.com 就可以拿到新設(shè)置的 cookie 了,相當(dāng)于 b.com 的打點(diǎn)追蹤,同時(shí)可以在 a.com 獲取了。
該步驟有兩個(gè)必要條件:
a. 加載圖片這個(gè)函數(shù)必須由用戶觸發(fā),比如 touch 事件之類的
b. 要設(shè)置的 key 需要在步驟1中提前設(shè)置,并且這個(gè) cookie key 一旦被移除,就無法設(shè)置了
- 同理,a.com 直接設(shè)置的 cookie, 在 b.com 請求 Img 時(shí),也會(huì)生效,問題來了,在 b.com 如何獲取 cookie 值
由于我測試的應(yīng)用需要的 cookie 值為布爾類型,非常簡單,所以獲取也簡單。
a.com 收到圖片請求, 判斷 cookie, 輸出一個(gè) 1x1, 或 2x1 的圖片,在 b.com 下
var img = new Image();
img.onload = function(){
console.log(this.width === 1)
}
img.src = a.com/dym?method=set&key=x&data=d
如果是需要字符串呢?搜到了一篇文章
Hide JavaScript code into images
可以考慮這個(gè)思路,在 a.com 后端將 cookie 值寫入到 img 中,輸出給 b.com, b.com 通過 canvas 讀取圖片的二進(jìn)制值,從而解析出來 img 中隱藏的字符串,有點(diǎn)猥瑣,但這個(gè)思路應(yīng)該是可以的,時(shí)間不多,就沒仔細(xì)研究,等用到的時(shí)候再研究吧。
- 這個(gè)方法只能在 a.com 和 b.com 下互相傳值,能不能像方法一那樣,專門弄一個(gè) c.com 來存值,然后所有其他任意域名都能設(shè)置/讀取 c.com 的緩存值,這個(gè)也沒去測試
測試思路
任意域名,打開時(shí)都判斷一下是否為 c.com 跳過來的,如果不是,就跳到 c.com ,再由 c.com 跳回來,
然后再使用以上方法測試 ,這個(gè)不一定可行,safari 的阻止第三方追蹤做的很完善了,就連上面的方案就已經(jīng)很猥瑣了,說不定哪天就不能用了,所以要實(shí)測才能知曉