[Golang] 自动健康上报
Charles http.Client mailx crontab
- Charles
- Golang 1.14
- CentOS 7
- 健康上报APP
1. Charles
1.1 基本配置
本身的功能还是很多的,由于健康信息上报在手机APP中,无法正常通过浏览器来分析请求信息,所以此处用Charles进行抓包。
Charles为收费软件,自行决定下载源,安装完成后:
- 系统代理端口:菜单栏
Proxy - Proxy Settings - Proxies - HTTP Proxy
设置为8888(默认值); - 确保手机和电脑在同一局域网下;
- 手机修改Wi-Fi配置,一般在“无线网络选项”或“高级选项”中,可以设置HTTP代理,将其设置为
PC_ADDR: 8888
,此时手机的所有流量都会通过电脑的8888
端口,由Charles截获; - 包乱码问题:
- 以上仅针对http请求,而我们需要截获的APP请求是通过HTTPS进行的,因此要求电脑端和手机端都有相同的证书,便于伪装(我猜的)
- 菜单栏:
Help - SSL Proxing - Install Charles Root Certificate
- 手机打开网址
http://www.charlesproxy.com/getssl
,获取电脑上的证书 - 菜单栏:
Proxy - SSL Proxying Settings - SSL Proxying
,Location Include中添加*:443
,即匹配任意站点的HTTPS请求
1.2 抓包
完成配置之后,抓包是很简单的,手机打开相应页面,电脑截获请求,由于这个APP用的是WebView,甚至可以直接将请求的网址提取出来,利用Chrome浏览器进行分析。
根据相关信息找到服务器的地址,在uc/wap/
路径中,找到了目标login
,我们关注的主要在Contents中,上下两部分分别是Request与Response。
至此,手机可以丢到一旁了。关于Charles使用的详细信息,可以参考这篇文章.
1.3 分析
在信息上报的流程中,通常我们需要完成两步操作“登陆-提交信息”,尽管我们知道提及信息对应的路径ncov/wap/default/save
,但是直接访问这个地址会被重定向到登陆页面,因此我们需要登陆获取Cookies。
伪造请求:请求中需要包括与Request中相同的
Headers
,使我们的data
可以顺利的被服务器认可、读取并返回需要的response。读取返回:response通常为返回的
HTML
或者关于操作成功/失败的status
,按照Response - Header
中可能存在的Content-Encoding
类型对返回值进行解码,并通过正则表达式提取出文本中我们需要的内容。绕过合法性校验:通过分析网页的源码,针对所处地理位置、身体状况、是否已提交等信息的校验几乎都是在前端完成的,这也为我们之后的工作提供了便利。
定位信息:定位是通过请求百度地图的API完成的,源码中就包含相应的token。但使用API定位收到的限制比较大:1.最终部署服务器的位置;2.大公司API可能存在的一些安全限制。不过网页js中就包含了“上次提交”的信息
oldInfo
,可以直接针对上次信息作出提取,修改几个值就可以作为新的信息进行提交了。
2. 伪装请求
基于上述的分析,我们可以将程序分成三个步骤:
- 首先向
POST uc/wap/login/check
发送信息,成功登陆并获取cookies; GET /ncov/wap/default/index
向信息上报页面请求信息,并且对所需信息进行匹配;- 之后绕过信息上报的页面,直接将包装好的信息通过
POST /ncov/wap/default/index/save
。
2.1 Golang的几种请求方式
2.1.1 GET
1 | func Get(url string) (resp *Response, err error) { |
Get请求可以直接用http.Get(url string)
方法进行,如下:
1 | func httpGet() { |
2.1.2 POST
http.Post()
接收string
类型的url
与请求头bodyType
,最后一个参数接收io.Reader
类型的主体内容,可以通过strings.NewReader()
进行转换
1 | func Post(url string, bodyType string, body io.Reader) (resp *Response, err error) { |
例:
1 | func httpPost() { |
http.PostForm()
支持表单的请求:
1 | func httpPostForm() { |
2.1.3 复杂请求
对于一些复杂的请求,可以用http.NewRequest()
和&http.Client{}
进行构建。
事实上,http.Get()
http.Post()
http.PostForm()
都是对http.Client{}
的封装,在执行请求的时候,都是用了client.Do()
方法,因此要设置更详细的请求信息,可以直接首先对http.Client{}
进行初始化:
1 | jar, _ := cookiejar.New(nil) |
cookiejar
为保存cookie的容器,Timeout
用于设置超时时间。对于client
我们需要详细设置其Headers
1 | req.Header.Set("Host", "example.com") |
这一步的内容取决于你捕获的包的请求头。之后我们需要自己定义一个请求http.NewRequest()
1 | // GET |
注意及时关闭resp.Body
,防止资源占用导致的阻塞。
2.2 内容提取
通过http.Client.Get("https://example.com/ncov/wap/default/index")
可以获取页面信息,当然由于在headers
中设定了Accept-Encoding: gzip
,此处需要对response.Body
进行解码操作,否则看到的是一堆乱码:
1 | //解决Content乱码问题 |
截取内容中的一段。
1 | # ----HTML ABOVE------ # |
简单粗暴一点,直接用正则表达式匹配我们需要的信息oldInfo
realname
number
1 | func GetInfo(str string) (string, error) { |
2.3 数据序列化json
显然oldInfo
为一段json文本,通过GetInfo(str string) (string, err)
我们得到了一段string
,将其转为map[string]interface{}
便于对其中的值进行修改。
1 | str := ReadString(username) |
这里有个不好处理的地方:由于返回的json文件中,存在整型和字符串类型的value,而在将数据封装到请求包的过程中,需要将json存到url.Values{}
中,这是一个map[string][]string
类型的对象,为了避免麻烦,在上述过程中,直接讲部分整型通过strconv.Itoa(int)
转成了字符类型。
3. 部署
为了实现整个上报过程的自动化,需要将程序放在服务器上,并定期运行。
3.1 构建多平台可执行程序
针对不同平台使用env GOOS=target-OS GOARCH=target-architecture go build path -o build-name
,常用的target-OS
和target-architecture
如下:
| GOOS
- Target Operating System | GOARCH
- Target Platform |
| :——————————: | :————————: |
| android
| arm
|
| darwin
| amd64
|
| darwin
| arm
|
| darwin
| arm64
|
| linux
| amd64
|
| windows
| amd64
|
当然,你也可以使用自动交叉编译的脚本来完成这个工作。
3.2 邮件提醒
目前主流邮箱都可以开启pop3或smtp的服务,用于在第三方上收发邮件,诸如qq、outlook、163(垃圾,别用)、gmail等都可以在设置界面找到相应的选项,开启后,服务商都会给你一段授权码(不是密码),用于身份识别。具体步骤如下:
开启smtp授权
服务器上
mkdir /root/.certs
配置证书:
1
2
3
4
5
6
7
8
9echo -n | openssl s_client -connect smtp.qq.com:465 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > ~/.certs/qq.crt
certutil -A -n "GeoTrust Global CA" -t "C,," -d ~/.certs -i ~/.certs/qq.crt
certutil -A -n "GeoTrust SSL CA" -t "C,," -d ~/.certs -i ~/.certs/qq.crt
certutil -L -d /root/.certs
certutil -A -n "GeoTrust SSL CA - G3" -t "Pu,Pu,Pu" -d ~/.certs/ -i ~/.certs/qq.crt安装mailx
1
2yum -y install sendmail
yum -y install mailx配置发件人信息:
vim /etc/mail.rc
1
2
3
4
5set from=example@qq.com
set smtp=smtp.qq.com
set smtp-auth-user=example@qq.com
set smtp-auth-password=AUTHORITY_CODE
set smtp-auth=login发送邮件:
cat response.log | mail -s 'title' yourmail@gmail.com
或mail -s 'title' yourmail@gmail.com < test.txt
3.3 定时执行任务
- 安装crontab
1 | yum install -y vixie-cron |
- 配置
1 | service crond start |
- 定时运行
1 | crontab -e |
出现一个文本文件,按照以下格式:
1 | * * * * * command |
设置为:
1 | 30 6 * * * {$PATH}/report.sh |
4. 总结
- 程序结构混杂;
- golang http包源码可以看一下;
- 源码.