在工作的时候,经常要接触一些办公系统,在网页上通过机械化的操作,来完成一个简单的功能,比如某台主机权限的申请,通过一套操作一下,大概 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 信息。
cookie 信息,肯定是存储在 chrome 中,具体的存储位置未知,并且对于这么隐私的数据,应该也是会进行加密存储的,因此,我并没有去尝试通过读取 cookie 文件的方式。
想起之前用过一个模拟发请求的 chrome 插件,postman
,通过安装Postman Interceptor
拦截器,可以让我们在postman
里模拟发请求的时候,自动带上网站的 cookie 信息,但是查阅了postman
的相关资料,也没有开放接口让我们在其它地方可以拿到 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);
});
这里还需要实现一个 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 的数据也返回
COOKIE=$(wget localhost:8888/?domain=www.baidu.com -q -O -)
echo $COOKIE
curl 'https://www.baidu.com/' -H "Cookie: $COOKIE"
注意这里"Cookie: $COOKIE"
必须是双引号,不能用单引号。
cookie 信息是一个非常隐私和重要的数据,虽然通过这个方法,能够将浏览器里面这个数据导出来,但对于这个数据,是需要特别小心保存的,cookie 信息如果被别人拿到,相当于别人可以用你的身份做任何事情,这是非常危险的。因此本文只是作为一个例子,没有做任何加密,但在实际应用中,最好都做加密传输。
1
aheadlead 2019-10-07 21:55:06 +08:00 1
挺好的思路
有个建议,既然都强调 shell 了,就没必要还费大功夫请 Sprint Boot 出来了吧 “接收数据并存储”完全可以只用 netcat+grep 实现啊 |
2
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") ``` |
3
jugelizi 2019-10-07 23:27:06 +08:00
所以
shell 怎么就拿到 cookie 了 挂羊头卖狗肉? |
4
reus 2019-10-08 02:20:52 +08:00 via Android
直接打开 sqlite 文件不就得了
|
5
lalalakakaka 2019-10-08 03:08:49 +08:00
you-get 至今无法支持读取 chrome 的 sqlite 文件。大拿们快上啊!
|
6
homeway88 OP @jugelizi chrome 插导出 cookie 数据-->http 服务器--> shell 请求 http 服务器拿 cookie
|
7
homeway88 OP @aheadlead 感谢你的思路分享,我也研究一下用 nc 怎么实现。因为我本身是做 web 开发的,所以就用了最熟悉的 spring boot,有点杀鸡用牛刀了。
|
9
homeway88 OP @reus https://www.jianshu.com/p/c94363c33bae 这里有篇文章是讲打开 sqlite 文件的,但里面的数据是加密过的,需要解密,这个我还没验证过。
MacOS 下,chrome cookie 对应的 sqlite 文件是:~/Library/Application Support/Google/Chrome/Default/Cookies |
10
kingfalse 2019-10-08 08:01:21 +08:00 via Android
了解一下爬虫??
|
11
homeway88 OP @reus https://github.com/n8henrie/pycookiecheat MacOS 下实测可行,授权一下 keychain 读取权限。
|
12
rain0002009 2019-10-08 09:41:11 +08:00
为啥不用 puppeteer 呢
|
13
shingle 2019-10-08 09:49:26 +08:00 via Android
puppeteer+1 可以指定浏览器位置和 data 文件夹,打开指定域名直接读取
|
14
hanzichi 2019-10-08 09:58:19 +08:00
这么麻烦,模拟登录后,自动维护 cookie jar 就行了啊
|
15
xiaotuzi 2019-10-08 12:15:34 +08:00 via iPhone
审核元素很麻烦吗?
另外,PHP 也很容易获取 cookie 关于 cookie 存储,存到本地或者数据库都行,看个人怎么使用 爬虫都要接触这个,你这帖子着重点应该是 shell 获取 cookie,但 shell 根本没办法直接获取,需要借助 api,这就直接转到 api 帮你操作不就行了…为啥还要 shell 携带 cookie 处理事情? 趁一群爬虫大佬还没出来,赶紧结贴。🤣 |
16
locoz 2019-10-08 16:35:55 +08:00
看完了,感觉你路走偏了...办公系统应该种类不多吧?直接写模拟登录应该比这更方便?连浏览器都不用开了。而且办公系统这种东西一般不会更新,也不会有什么反爬措施,如果请求里不带加密参数的话,抓包一下、把登录的操作复制出来直接用估计都可以拿到登录 Cookie...
|
18
ochatokori 2019-10-08 17:01:45 +08:00 via Android
为什么不用 curl 登陆呢,到时候 cookie 过期了难不成还要打开浏览器更新 cookie ?
|
19
homeway88 OP @locoz 我们内部所有系统都用一个统一的登录系统,这个登录系统在外网也可以用,因此安全等级很高。并且模拟登录和爬虫我也没搞过
|
20
homeway88 OP @ochatokori 登录系统不好破
|
21
homeway88 OP @xiaotuzi 上面回复过,shell 执行 python 脚本读 cookie 的 sqlite 文件是可以的
|
22
locoz 2019-10-08 17:30:37 +08:00
@homeway88 #19 安全等级高其实并不意味着模拟登录难,最多就是要打码而已。(毕竟这种系统的安全在前端做不了太多的事情,防 XSS 之类的对搞模拟登录又没有影响。
|
23
godoway 2019-10-08 18:47:00 +08:00 via Android
这种不应该是自己发送登录请求然后持久化 cookie 就行了么,自己写一个 command line application 怎么看。
|
24
conn4575 2019-10-09 03:13:02 +08:00 via Android
感觉走了弯路,你其实想要的是登录接口返回的 cookie,直接用 python 写一个脚本的话都不需要 100 行,更不需要 spring 工程。。
|
26
astkaasa 2019-10-10 16:19:31 +08:00
curl -c -
登录的接口试下这个? |