大家好,我是TheWeiJun;最近疫情很严重,大家都要做好防护。转眼间,距离上次发文又快一个月了。今天给大家带来一个Go语言版本的某容器管理平台模拟登录的案例,目的是解放双手,实现自动部署和重启操作,欢迎各位读者多多阅读与交流!

特别声明:本公众号文章只作为学术研究,不用于其它不法用途;如有侵权请联系作者删除。

 目录

一、前言介绍

二、模拟登录

三、参数分析

四、代码实现

五、思路总结


趣味模块

老六是一名spider工程师,最近老六遇到了一个棘手的问题,老六每次写完代码上传git后,希望某容器管理平台能够自动同步git代码并且实现代码自动同步重启。老六一番研究后发现某容器平台除了代码宕机重启和定时重启,没有自动重启这么一说!老六很苦恼,后来老六想了想自己的职业,于是决定给他实现自动快速重启功能,彻底解放自己的双手,继续自己的复制粘贴高端操作!接下来,让我们一起去看看老六如何实现的自动登录和快速重启操作吧。


一、前言介绍

1.  什么是模拟登录?

解释:网页上以及app中输入账号密码的过程称为登录,不经过登录有些页面是无法直接跳转的。而模拟登录就是模拟手动输入账号密码的过程,获得登录成功后的cookie,以此cookie直接访问需要登录才能进入的页面,从而获取数据。

2. 模拟登录能做什么?

解释:模拟登录成功后,我们可以模拟人的行为下发一些操作指令,程序会根据我们下发的指令达到真实的人为效果,彻底解放我们的双手。

3.  什么是Cookie?

解释:cookies一种保存在电脑上的一种文件,当我们使用电脑进行浏览网页的时候,服务器就会生成一个证书,并且返回给我们的电脑,这个证书就是cookie,一般情况下,cookie是服务器写入客户端的文件,我们也可以叫浏览器缓存。


二、模拟登录

1、首先打开我们本次需要模拟登录的网站,浏览器中打开网页,截图如下所示:

2、点击账号密码,触发模拟登录操作,打开浏览器开发者工具查看相关请求包,截图如下所示:

环节说明:由于我们想要获取登录的协议接口,故我们随便输入内容,可查看到模拟登录所需要的data参数主要为上图六个。接下来,我们只需要模拟这几个参数并结合headers参数分析即可实现模拟登录!

3、一般网站开发人员为了安全,都会有csrf攻击防护,我们查看请求headers,截图如下所示:

总结:接下来我们只需要模拟data、headers参数即可实现模拟登录访问网站,达到我们最终的目的。


三、参数分析

1、参数初判断,需要我们模拟的参数主要有以下:

   Data参数分析如下:

  • username:登录所需要的账号。

  • password:登录所需要的密码。

  • description:固定值,经过多次验证。

  • responseType:固定值,同上。

  • ttl:网站cookie过期时间,同redis过期时间类似。

  • labels:固定值,同上。

Headers参数分析如下:

  • x-api-csrf:登录所需要csrf参数。

  • Cookie:登录成功后需要保留的参数。

2、为了获取csrf参数,我们再次刷新页面,分析每一个可疑请求包,截图如下所示:

3、从前到后分析每一个请求包,我们发现csrf参数并不是通过response或者Set-Cookie的参数返回,这种情况很少见,于是我们模拟请求,查看响应体,果然有意外收获,截图如下所示:

总结:查看js代码后,我发现了问题关键,这个是由于通过浏览器访问时,js代码会将set-cookie给remove掉,这样对我们在分析该网站时,就会定位不到该参数如何下发的,从而放弃操作。那么接下来,我们用Golang去实现模拟登录,并下发操作重启代码服务吧。


四、代码实现

1、使用http包忽略证书认证,并提取登录所需的csrf参数,代码如下所示:

package mainimport (  "crypto/tls"  "fmt"  "log"  "net/http")func main() {  tr := &http.Transport{    // 处理x509: certificate signed by unknown authority    TLSClientConfig: &tls.Config{InsecureSkipVerify: true},  }  client := &http.Client{Transport: tr}  req, err := http.NewRequest("GET", "https://xxxx/v3/settings/ui-pl", nil)  if err != nil {    log.Fatal(err)  }  req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9")  req.Header.Set("Cache-Control", "no-cache")  req.Header.Set("Connection", "keep-alive")  req.Header.Set("Cookie", "R_USERNAME=")  req.Header.Set("Pragma", "no-cache")  req.Header.Set("Referer", "https://xxxx/login")  req.Header.Set("Sec-Fetch-Dest", "empty")  req.Header.Set("Sec-Fetch-Mode", "cors")  req.Header.Set("Sec-Fetch-Site", "same-origin")  req.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36")  req.Header.Set("accept", "application/json")  req.Header.Set("content-type", "application/json")  req.Header.Set("sec-ch-ua", `"Not?A_Brand";v="8", "Chromium";v="108", "Google Chrome";v="108"`)  req.Header.Set("sec-ch-ua-mobile", "?0")  req.Header.Set("sec-ch-ua-platform", `"macOS"`)  req.Header.Set("x-api-action-links", "actionLinks")  req.Header.Set("x-api-no-challenge", "true")  resp, err := client.Do(req)  if err != nil {    log.Fatal(err)  }  defer resp.Body.Close()  CsrfStr := resp.Header.Get("Set-Cookie")  fmt.Printf("%s\n", CsrfStr)}

Goland中代码打印截图如下:

2、接下来我们使用上面获取的参数来完成模拟登录操作,完整代码如下:

package mainimport (  "crypto/tls"  "fmt"  "log"  "net/http"  "strings")var tr = &http.Transport{  // 处理x509: certificate signed by unknown authority  TLSClientConfig: &tls.Config{InsecureSkipVerify: true},}var client = &http.Client{Transport: tr}func GetCsrf() string {  req, err := http.NewRequest("GET", "https://xxxx/v3/settings/ui-pl", nil)  if err != nil {    log.Fatal(err)  }  req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9")  req.Header.Set("Cache-Control", "no-cache")  req.Header.Set("Connection", "keep-alive")  req.Header.Set("Cookie", "R_USERNAME=xxx")  req.Header.Set("Pragma", "no-cache")  req.Header.Set("Referer", "https://xxxx/login")  req.Header.Set("Sec-Fetch-Dest", "empty")  req.Header.Set("Sec-Fetch-Mode", "cors")  req.Header.Set("Sec-Fetch-Site", "same-origin")  req.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36")  req.Header.Set("accept", "application/json")  req.Header.Set("content-type", "application/json")  req.Header.Set("sec-ch-ua", `"Not?A_Brand";v="8", "Chromium";v="108", "Google Chrome";v="108"`)  req.Header.Set("sec-ch-ua-mobile", "?0")  req.Header.Set("sec-ch-ua-platform", `"macOS"`)  req.Header.Set("x-api-action-links", "actionLinks")  req.Header.Set("x-api-no-challenge", "true")  resp, err := client.Do(req)  if err != nil {    log.Fatal(err)  }  defer resp.Body.Close()  SetCookie := resp.Header.Get("Set-Cookie")  splitStr := strings.Split(SetCookie, ";")[0]  CsrfStr := strings.Replace(splitStr, "CSRF=", "", 1)  return CsrfStr}func Login(CsrfStr string) {  var data = strings.NewReader(`{"username":"xxxx","password":"xxxxx","description":"UI Session","responseType":"cookie","ttl":57600000,"labels":{"ui-session":"true"}}`)  req, err := http.NewRequest("POST", "https://xxxx/v3-public/localProviders/local?action=login", data)  if err != nil {    log.Fatal(err)  }  req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9")  req.Header.Set("Cache-Control", "no-cache")  req.Header.Set("Connection", "keep-alive")  req.Header.Set("Origin", "https://xxxx")  req.Header.Set("Pragma", "no-cache")  req.Header.Set("Referer", "https://xxxxx/login")  req.Header.Set("Sec-Fetch-Dest", "empty")  req.Header.Set("Cookie", "R_USERNAME=; CSRF="+CsrfStr)  req.Header.Set("Sec-Fetch-Mode", "cors")  req.Header.Set("Sec-Fetch-Site", "same-origin")  req.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36")  req.Header.Set("accept", "application/json")  req.Header.Set("content-type", "application/json")  req.Header.Set("sec-ch-ua", `"Not?A_Brand";v="8", "Chromium";v="108", "Google Chrome";v="108"`)  req.Header.Set("sec-ch-ua-mobile", "?0")  req.Header.Set("sec-ch-ua-platform", `"macOS"`)  req.Header.Set("x-api-action-links", "actionLinks")  req.Header.Set("x-api-csrf", CsrfStr)  req.Header.Set("x-api-no-challenge", "true")  resp, err := client.Do(req)  if err != nil {    log.Fatal(err)  }  defer resp.Body.Close()  SetCookie := resp.Header.Get("Set-Cookie")  fmt.Println(SetCookie)}func main() {  CsrfStr := GetCsrf()  Login(CsrfStr)}

Goland中打印登录后的token截图如下:

浏览器中登录后的token截图如下:

3、模拟登录流程实现后,我们开始下发重启代码操作,最后完整代码如下:

package mainimport (  "crypto/tls"  "fmt"  "log"  "net/http"  "strings")var tr = &http.Transport{  // 处理x509: certificate signed by unknown authority  TLSClientConfig: &tls.Config{InsecureSkipVerify: true},}var client = &http.Client{Transport: tr}func GetCsrf() string {  req, err := http.NewRequest("GET", "https://xxxx/v3/settings/ui-pl", nil)  if err != nil {    log.Fatal(err)  }  req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9")  req.Header.Set("Cache-Control", "no-cache")  req.Header.Set("Connection", "keep-alive")  req.Header.Set("Cookie", "R_USERNAME=xxx")  req.Header.Set("Pragma", "no-cache")  req.Header.Set("Referer", "https://xxxx/login")  req.Header.Set("Sec-Fetch-Dest", "empty")  req.Header.Set("Sec-Fetch-Mode", "cors")  req.Header.Set("Sec-Fetch-Site", "same-origin")  req.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36")  req.Header.Set("accept", "application/json")  req.Header.Set("content-type", "application/json")  req.Header.Set("sec-ch-ua", `"Not?A_Brand";v="8", "Chromium";v="108", "Google Chrome";v="108"`)  req.Header.Set("sec-ch-ua-mobile", "?0")  req.Header.Set("sec-ch-ua-platform", `"macOS"`)  req.Header.Set("x-api-action-links", "actionLinks")  req.Header.Set("x-api-no-challenge", "true")  resp, err := client.Do(req)  if err != nil {    log.Fatal(err)  }  defer resp.Body.Close()  SetCookie := resp.Header.Get("Set-Cookie")  splitStr := strings.Split(SetCookie, ";")[0]  CsrfStr := strings.Replace(splitStr, "CSRF=", "", 1)  return CsrfStr}func Login(CsrfStr string) {  var data = strings.NewReader(`{"username":"xxxx","password":"xxxxx","description":"UI Session","responseType":"cookie","ttl":57600000,"labels":{"ui-session":"true"}}`)  req, err := http.NewRequest("POST", "https://xxxx/v3-public/localProviders/local?action=login", data)  if err != nil {    log.Fatal(err)  }  req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9")  req.Header.Set("Cache-Control", "no-cache")  req.Header.Set("Connection", "keep-alive")  req.Header.Set("Origin", "https://xxxx")  req.Header.Set("Pragma", "no-cache")  req.Header.Set("Referer", "https://xxxxx/login")  req.Header.Set("Sec-Fetch-Dest", "empty")  req.Header.Set("Cookie", "R_USERNAME=weijun; CSRF="+CsrfStr)  req.Header.Set("Sec-Fetch-Mode", "cors")  req.Header.Set("Sec-Fetch-Site", "same-origin")  req.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36")  req.Header.Set("accept", "application/json")  req.Header.Set("content-type", "application/json")  req.Header.Set("sec-ch-ua", `"Not?A_Brand";v="8", "Chromium";v="108", "Google Chrome";v="108"`)  req.Header.Set("sec-ch-ua-mobile", "?0")  req.Header.Set("sec-ch-ua-platform", `"macOS"`)  req.Header.Set("x-api-action-links", "actionLinks")  req.Header.Set("x-api-csrf", CsrfStr)  req.Header.Set("x-api-no-challenge", "true")  resp, err := client.Do(req)  if err != nil {    log.Fatal(err)  }  defer resp.Body.Close()  SetCookie := resp.Header.Get("Set-Cookie")  fmt.Println(SetCookie)}func Redeploy(token, CsrfStr string) {  req, err := http.NewRequest("POST", "https://xxxxx/v3/project/c-djhlx:p-vnncq/workloads/deployment:default:task5?action=redeploy", nil)  if err != nil {    log.Fatal(err)  }  req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9")  req.Header.Set("Cache-Control", "no-cache")  req.Header.Set("Connection", "keep-alive")  req.Header.Set("Content-Length", "0")  req.Header.Set("Cookie", "R_USERNAME=xxxx; CSRF="+CsrfStr+"; "+token)  req.Header.Set("Origin", "https://xxxx")  req.Header.Set("Pragma", "no-cache")  req.Header.Set("Referer", "xxxx")  req.Header.Set("Sec-Fetch-Dest", "empty")  req.Header.Set("Sec-Fetch-Mode", "cors")  req.Header.Set("Sec-Fetch-Site", "same-origin")  req.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36")  req.Header.Set("accept", "application/json")  req.Header.Set("content-type", "application/json")  req.Header.Set("sec-ch-ua", `"Not?A_Brand";v="8", "Chromium";v="108", "Google Chrome";v="108"`)  req.Header.Set("sec-ch-ua-mobile", "?0")  req.Header.Set("sec-ch-ua-platform", `"macOS"`)  req.Header.Set("x-api-action-links", "actionLinks")  req.Header.Set("x-api-csrf", CsrfStr)  req.Header.Set("x-api-no-challenge", "true")  resp, err := client.Do(req)  if err != nil {    log.Fatal(err)  }  defer resp.Body.Close()  Options := resp.Header.Get("X-Content-Type-Options")  if Options != "" {    fmt.Println("Redeploy successful!")  }}func main() {  CsrfStr := GetCsrf()  token := Login(CsrfStr)  Redeploy(token, CsrfStr)}

代码运行后,Goland运行截图如下所示:

代码执行完毕后,浏览器中服务状态截图如下:

总结:对比上面两张截图,我们发现我们的代码已经能够重启指定的woker服务了,这样就实现了我们想要的自动化重启功能,整个流程到此就完全结束了!


五、思路总结

通过本次案例分析,我们不仅可以通过Python实现模拟登录,也可以用Go去实现模拟登录。本篇分享到这里就结束了,欢迎大家关注下一期,我们不见不散☀️☀️😊。最后希望大家多多转发、点赞、在看支持一波


关注我们获得更多精彩内容

逆向与爬虫的故事

不止于爬虫开发,还有Js逆向、App逆向!

往期推荐

作者简介

我是TheWeiJun,有着执着的追求,信奉终身成长,不定义自己,热爱技术但不拘泥于技术,爱好分享,喜欢读书和乐于结交朋友,欢迎扫我微信与我交朋友💕

分享日常学习中关于爬虫及逆向分析的一些思路,文中若有错误的地方,欢迎大家多多交流指正💕

微信搜公众号:逆向与爬虫的故事;给我一个关注!