如何在 shell 中动态获取 chrome 浏览器的 cookie 信息

2019-10-07 21:15:39 +08:00
 homeway88

0. 背景

在工作的时候,经常要接触一些办公系统,在网页上通过机械化的操作,来完成一个简单的功能,比如某台主机权限的申请,通过一套操作一下,大概 7、8 个步骤,花费 30 秒的时间,虽然不长,但是要脱离终端,到浏览器去操作,打断了心流,就感觉很烦人了。 我们在网页的操作,其实就是往这个网站的后台发起一个 API 请求,这个动作,我们在终端里面,通过 curl 命令也能完成,比如我们打开百度的首页,通过 chrome 的控制台 -> Network -> 找到对应的请示,右键,Copy -> Copy as cURL,我们就能得到如下的一条命令:

curl 'https://www.baidu.com/' -H 'Connection: keep-alive' -H 'Cache-Control: max-age=0' -H 'Upgrade-Insecure-Requests: 1' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36' -H 'Sec-Fetch-Mode: navigate' -H 'Sec-Fetch-User: ?1' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3' -H 'Sec-Fetch-Site: none' -H 'Accept-Encoding: gzip, deflate, br' -H 'Accept-Language: zh-CN,zh;q=0.9,en;q=0.8' -H 'Cookie: BIDUPSID=A10629EBE8B29EBEE170B7E4E405; PSTM=1520729161; BDUSS=pMV2FGNlNaUUdB134asdfCOVU5cHFCR0p2SzBtY0Q2OWlNZlhORHdhN1ZjQVFBQUFBJCQAAAAAABBBBBGHAAaG9tZXdheQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPDejVzw3o1cck; ' --compressed

在终端执行这条命令,和你浏览器发起的这个请求,其实是等同的,但是这里面,有一个最重要的参数,就是你的 Cookie 信息,这个信息可以代表你当前在这个网站上的登录用户,如果我们要写一些自动化的网站操作脚本,或者写爬虫什么的,第一步就是怎么拿到 cookie 信息。

1. 获取 chrome 浏览器里的 cookie

cookie 信息,肯定是存储在 chrome 中,具体的存储位置未知,并且对于这么隐私的数据,应该也是会进行加密存储的,因此,我并没有去尝试通过读取 cookie 文件的方式。

想起之前用过一个模拟发请求的 chrome 插件,postman,通过安装Postman Interceptor拦截器,可以让我们在postman里模拟发请求的时候,自动带上网站的 cookie 信息,但是查阅了postman的相关资料,也没有开放接口让我们在其它地方可以拿到 cookie 信息。

1.1 通过 chrome 插件获取 cookie 数据

既然在浏览器插件里能拿到 cookie,那么我们自己实现一个不就行了吗,拿到数据之后,再想办法把数据传出来就可以了。参考 chrome api 文档,我们可以通过添加一个 cookies 的监听器,来拿到变化的 cookie,以及拿到某个 domain 域下的所有 cookie,但是 chrome 也是运行在浏览器环境之上,无法直接往本地存储写数据,只能通过对外发起 ajax 请求来把数据传出去了。核心代码如下:

function refreshDomain(domain) {
	chrome.cookies.getAll({domain: domain}, function (cookies) {
		// 这里就能拿到这个域下所有 cookie 了
		let all_cookies = cookies.filter(item => item.domain === domain)
			.map(item => item.name + "=" + item.value).join("; ");

		console.log("Report Cookie:domain=" + domain + ",cookies=" + all_cookies);
		$.ajax({
			 //这里需要一个 http 服务来接收数据
			url: "http://localhost:8888",
			method: "POST",
			data: {
				domain: domain,
				cookies: all_cookies
			},
			dataType: "json",
			success: function(data) { console.log("Report success:" + data) },
			failure: function (data) {
				console.log("Report failure:" + data)
			}
		})
	});
}

chrome.cookies.onChanged.addListener(function (event) {
	const cookie = event.cookie;
	refreshDomain(cookie.domain);
});

1.2 接收数据并存储

这里还需要实现一个 http 服务来接收插件发出来的 cookie 数据,这里我用 spring boot 初始化出来一个 spring mvc 的工程,再添加两个 api,一个用于接收 cookie 并存储,一个用于对外再接供获取 cookie 信息的接口。代码如下:


@SpringBootApplication
@EnableWebMvc
@Controller
public class CookieManager {
	private static Map<String, String> domainCookies = new HashMap<>(1024);

	@RequestMapping(value = "/", method = RequestMethod.GET)
	@ResponseBody
	public String getCookie(@RequestParam("domain") String domain) {
		return domainCookies.entrySet().stream()
			.filter(e -> domain.endsWith(e.getKey()))
			.map(Entry::getValue)
			.collect(Collectors.joining("; "));
	}

	@RequestMapping(value = "/", method = RequestMethod.POST)
	@ResponseBody
	public String setCookie(@RequestParam("domain") String domain,
							@RequestParam("cookies") String cookies) throws IOException {

		domainCookies.put(domain, cookies);

		return domain;
	}

	public static void main(String[] args) {
		SpringApplication.run(CookieManager.class, args);
	}
}

这里在获取 cookie 的时候做了一个处理,自动把父域的 cookie 带上。比如获取 domain=www.baidu.com 的 cookie,会把 domain=.baidu.com 的数据也返回

1.3 在 shell 中的用法

COOKIE=$(wget localhost:8888/?domain=www.baidu.com -q -O -)
echo $COOKIE

curl 'https://www.baidu.com/' -H "Cookie:  $COOKIE"

注意这里"Cookie: $COOKIE"必须是双引号,不能用单引号。

特别注意

cookie 信息是一个非常隐私和重要的数据,虽然通过这个方法,能够将浏览器里面这个数据导出来,但对于这个数据,是需要特别小心保存的,cookie 信息如果被别人拿到,相当于别人可以用你的身份做任何事情,这是非常危险的。因此本文只是作为一个例子,没有做任何加密,但在实际应用中,最好都做加密传输。

参考文档

8814 次点击
所在节点    程序员
26 条回复
aheadlead
2019-10-07 21:55:06 +08:00
挺好的思路

有个建议,既然都强调 shell 了,就没必要还费大功夫请 Sprint Boot 出来了吧
“接收数据并存储”完全可以只用 netcat+grep 实现啊
undefind
2019-10-07 23:00:29 +08:00
写过一个在 Windows 下获取 chrome 浏览器中 httponly 的 cookie 信息,供你参考。
```
"""
import os
import sqlite3
from win32.win32crypt import CryptUnprotectData


def getcookiefromchrome(host):
cookiepath = os.environ['LOCALAPPDATA'] + r"\Google\Chrome\User Data\Default\Cookies"
sql = "select * from cookies where host_key like " + "'%" + host + "';"
try:
with sqlite3.connect(cookiepath) as conn:
cu = conn.cursor()
cookies = {name: CryptUnprotectData(encrypted_value)[1].decode() for host_key, name, encrypted_value in
cu.execute(sql).fetchall()}
return cookies
except Exception as e:
pass

getcookiefromchrome("example.com")
```
jugelizi
2019-10-07 23:27:06 +08:00
所以
shell 怎么就拿到 cookie 了
挂羊头卖狗肉?
reus
2019-10-08 02:20:52 +08:00
直接打开 sqlite 文件不就得了
lalalakakaka
2019-10-08 03:08:49 +08:00
you-get 至今无法支持读取 chrome 的 sqlite 文件。大拿们快上啊!
homeway88
2019-10-08 07:31:48 +08:00
@jugelizi chrome 插导出 cookie 数据-->http 服务器--> shell 请求 http 服务器拿 cookie
homeway88
2019-10-08 07:33:42 +08:00
@aheadlead 感谢你的思路分享,我也研究一下用 nc 怎么实现。因为我本身是做 web 开发的,所以就用了最熟悉的 spring boot,有点杀鸡用牛刀了。
homeway88
2019-10-08 07:35:12 +08:00
@undefind 谢谢你的分享。我用的是 MacOS,不知道是否也能用 sqlite 的方法。
homeway88
2019-10-08 07:57:02 +08:00
@reus https://www.jianshu.com/p/c94363c33bae 这里有篇文章是讲打开 sqlite 文件的,但里面的数据是加密过的,需要解密,这个我还没验证过。
MacOS 下,chrome cookie 对应的 sqlite 文件是:~/Library/Application Support/Google/Chrome/Default/Cookies
kingfalse
2019-10-08 08:01:21 +08:00
了解一下爬虫??
homeway88
2019-10-08 09:24:40 +08:00
@reus https://github.com/n8henrie/pycookiecheat MacOS 下实测可行,授权一下 keychain 读取权限。
rain0002009
2019-10-08 09:41:11 +08:00
为啥不用 puppeteer 呢
shingle
2019-10-08 09:49:26 +08:00
puppeteer+1 可以指定浏览器位置和 data 文件夹,打开指定域名直接读取
hanzichi
2019-10-08 09:58:19 +08:00
这么麻烦,模拟登录后,自动维护 cookie jar 就行了啊
xiaotuzi
2019-10-08 12:15:34 +08:00
审核元素很麻烦吗?
另外,PHP 也很容易获取 cookie
关于 cookie 存储,存到本地或者数据库都行,看个人怎么使用
爬虫都要接触这个,你这帖子着重点应该是 shell 获取 cookie,但 shell 根本没办法直接获取,需要借助 api,这就直接转到 api 帮你操作不就行了…为啥还要 shell 携带 cookie 处理事情?
趁一群爬虫大佬还没出来,赶紧结贴。🤣
locoz
2019-10-08 16:35:55 +08:00
看完了,感觉你路走偏了...办公系统应该种类不多吧?直接写模拟登录应该比这更方便?连浏览器都不用开了。而且办公系统这种东西一般不会更新,也不会有什么反爬措施,如果请求里不带加密参数的话,抓包一下、把登录的操作复制出来直接用估计都可以拿到登录 Cookie...
sunziren
2019-10-08 16:54:44 +08:00
@kingfalse 你这个头像 like 威震天
ochatokori
2019-10-08 17:01:45 +08:00
为什么不用 curl 登陆呢,到时候 cookie 过期了难不成还要打开浏览器更新 cookie ?
homeway88
2019-10-08 17:18:14 +08:00
@locoz 我们内部所有系统都用一个统一的登录系统,这个登录系统在外网也可以用,因此安全等级很高。并且模拟登录和爬虫我也没搞过
homeway88
2019-10-08 17:19:29 +08:00
@ochatokori 登录系统不好破

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/606799

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX