伪指纹浏览器开发的那些事

什么是伪指纹浏览器开发

就是通过开源的chromium浏览器进行二次简单的封装不涉及到重新编译chromium,配合puppeteer进行轻微的指纹修改开发

一、如何操作

本次操作客户端以前端擅长的electron来举例子,至于electron是什么,打开文心一言看看...

第一步下载chromium到本地客户端

登录官网,看到如下界面

可以发现箭头处指定是浏览器对应的版本buildId和系统,这里可以直接手动点击下载到本地,也可以通过@puppeteer/browsers这个库使用js代码去下载。这里说说如何使用它下载

javascript 复制代码
const { app } = require('electron')
const browserApi = require('@puppeteer/browsers')
const axios = require('axios')

// browser缓存路径,避免和electron一起打包占用安装包体积和打包时间
const cacheDir = `${app.getPath('cache')}/myBrowser`

browserApi.install({
  cacheDir, // 自己想要下载的路径,用来给puppeteer去调用
  browser: browserApi.Browser.CHROMIUM,
  // buildId: '1247373',
  // baseUrl: 'https://commondatastorage.googleapis.com/chromium-browser-snapshots'
})

耐心的小伙伴肯定发现了这里buildId版本号和baseUrl下载url我打了注释,是因为@puppeteer/browsers默认下载的chromium版本比较旧,那么我们怎么获取这个最新版本buildId和baseUrl呢,还是官网那个界面打开控制台,可以看到如下请求链接

然后看到请求结果 这就是最新的buildId了,然后封装成函数调用

javascript 复制代码
// 获取最新的chromium构建ID
function getLastBuildId(platform) {
  return axios
    .get(
      `https://download-chromium.appspot.com/rev/${browserApi.BrowserPlatform.MAC}?type=snapshots`
    )
    .then((res) => res.data.content)
}

baseUrl可以在界面点击下载时候,看到控制台有一个请求,那就是baseUrl了

下载好后,可以去我们定义的下载保存地址,通过终端去打开就可以看到了

二、第二步启动chromium

使用puppeteer-core这个库,启动我们下好的chromium

javascript 复制代码
const puppeteer = require('puppeteer-core')
const browserApi = require('@puppeteer/browsers')

// browser缓存路径
const cacheDir = `${app.getPath('cache')}/myBrowser`

// 获取安装的浏览器路径
function getBrowserPath() {
  return browserApi
    .getInstalledBrowsers({ cacheDir })
    .then((list) => list[0]?.executablePath)
}

// 浏览器生成
const createBrowser = async (proxyServer, userAgent) => {
  const browser = await puppeteer.launch({
    args: [
      `--proxy-server=${proxyServer}`,
      `--user-agent="${userAgent}"`,
      '--no-first-run',
      '--no-zygote',
      '--disable-extensions',
      '--disable-infobars',
      '--disable-automation',
      '--no-default-browser-check',
      '--disable-device-orientation',
      '--disable-metrics-reporting',
      '--disable-logging'
    ],
    headless: false,
    defaultViewport: null,
    ignoreHTTPSErrors: true,
    ignoreDefaultArgs: [
      '--enable-infobars',
      '--enable-features=NetworkService,NetworkServiceInProcess',
      '--enable-automation',
      'about:blank'
    ],
    executablePath: await getBrowserPath()
  })

  return browser
}

通过puppeteer.launch启动一个浏览器,至于启动参数这里我只说指纹相关的两个参数--proxy-server--user-agent,其他AI一下。

--proxy-server代理服务,浏览器访问的出口IP,即你用自己启动的浏览器访问google时候,那边服务端获取的ip就是你的代理ip,测试时候可以自己在另外一台机器上装个Squid测试。--user-agent即浏览器的window.navigator.userAgent,简单指纹一般都是依赖于它生成

三、开发过程中用到的功能点

看完puppeteer官网,我们知道操作chromium依赖于一套协议chromedevtools.github.io/devtools-pr...

3.1 更换dock图标

比如多开浏览器,我如何更换chromium的桌面dock图标,去标识这是我启动的第几个浏览器。我们可以使用Browser.setDockTile去操作浏览器更换dock图标

csharp 复制代码
const pages = await browser.pages()
const page = pages[0]
const session = await pages[0].target().createCDPSession()
await session.send('Browser.setDockTile', {
    image: new Buffer.from(fs.readFileSync(file)).toString('base64')
})

效果如下:

更多的协议操作需要自己摸索了,提示下,AI搜索chrome cdp协议

3.2 增加默认书签

这里我没找到协议,直接通过类似爬虫的方式,先进入标签管理页面,直接操作js新增,也算是一个技巧性的骚操作

csharp 复制代码
await page.goto('chrome://bookmarks/') // 进入标签管理页面
await page.evaluate(async () => {
  // 类似在控制台直接操作一样,下面的代码控制台一样可以达到效果
  const defaultBookmarks = [
    {
      title: "文心一言",
      url: "https://yiyan.baidu.com/",
    },
    {
      title: "掘金",
      url: "https://juejin.cn/",
    },
  ];

  defaultBookmarks.forEach((item) => {
    chrome.bookmarks.create({
      parentId: "1",
      ...item,
    });
  });
});
await page.goto('自己的本来要跳的首页')

3.3 如何使用已经打开的浏览器

c 复制代码
const browserWSEndpoint = browser.wsEndpoint() // 获取本次打开的浏览器链接,留作下一次使用
// 保存下来, 比如直接存在一个变量map中,给它定义一个唯一的browserId,下一次好直接获取
browserMap.set(browserId, browserWSEndpoint)

...
// 再次打开新页面,要用到上一次打开的浏览器
const browser = puppeteer.connect({
   ...launchOptions, // 和自己首次打开浏览器的配置一样
   browserWSEndpoint: browserMap.set(browserId)
})

这样就可以使用之前打开的浏览器打开网页了

3.4 如何把浏览器的信息显示在网页上

比如代理、userAgent、地区、浏览器名称等信息,先写个页面,然后轮询从localStorage直到获取信息为止。

javascript 复制代码
// 浏览器代理信息页
await page.goto('浏览器信息页')
// 设置localStorage
await page.evaluate(
  (values) => {
    window.localStorage.setItem('browserInfo', values)
  },
  JSON.stringify(browserData)
)

3.5 校验代理

一般的代理服务为了不让别人也能用都会加上账密校验,所以我们还需要在启动后,调用方法去校验

php 复制代码
// 校验proxy
if (proxyData.proxyServer) {
  await page.authenticate({
    username: proxyData.proxyUser,
    password: proxyData.proxyPwd
  })
}

page在打开页面后,并不会在页面中马上能获取到这里注入的browserInfo,可以通过轮询方式去扫描localStorage中是否存在我们注入的变量,这里举个react中的例子,在页面ready后去轮询处理

scss 复制代码
useEffect(() => {
  let loopId = null
  const clearLoop = () => {
    loopId && clearTimeout(loopId)
  }

  // 轮询直到获取browserInfo
  const loop = () => {
    loopId = setTimeout(() => {
      const localData = window.localStorage.getItem('browserInfo')
      if (localData) {
        Promise.resolve()
          .then(() => {
            setInfo(JSON.parse(localData))
          })
          .catch(() => {
            message.error('获取浏览器信息失败')
          })
      } else {
        loop()
      }
    }, 1500)
  }

  loop()

  return () => {
    clearLoop()
  }
})

四、遇到了哪一些问题

4.1 mac下关闭浏览器关不掉

当我们点击左上角关闭浏览器按钮或者是关闭所有页面时候,底部的dock中依旧存在着,我们不希望像mac其他软件一样保留在dock中,不然下一次打开浏览器时候,会出现相同标识的浏览器,可以这么解决

dart 复制代码
// 每次页面关闭时候,查看浏览器是不是还有页面了,没有就关闭
browser.on('targetdestroyed', async () => {
  const pages = await browser.pages()
  if (!pages.length) {
    await browser.close()
  }
})

4.2 当我们之间关闭电脑屏幕时候,比如盖上电脑,再次打开时候,关闭不了浏览器

打上log,可以发现熄屏时候,会触发puppeteer定义的browser的disconnected事件,但是再次打开电脑时候浏览器是可以正常使用的,也就是说,puppeteer和我们打开的chromium断连了,所以我们需要在disconnected事件里再此尝试链接下chromium,如果不行才认为是浏览器被关闭了

typescript 复制代码
browser.on('disconnected', () => {
  const cacheData = browserMap.get(browserId)
  puppeteer
    .connect({
      ...launchOptions,
      browserWSEndpoint: cacheData.browserWSEndpoint
    })
    .then((newBrowser) => {
      browser = newBrowser
      log.info(
        'browser disconnected but browser is exist',
      )
      initEvent()
    })
    .catch((err) => {
      log.info(
        'browser disconnected success',
      )
    })
})

结语

puppeteer很强大,chromium也强大,就是那个官网文档啊,写的真是让人...,所以多问问AI吧

相关推荐
理想不理想v1 分钟前
vue种ref跟reactive的区别?
前端·javascript·vue.js·webpack·前端框架·node.js·ecmascript
知孤云出岫2 分钟前
web 渗透学习指南——初学者防入狱篇
前端·网络安全·渗透·web
贩卖纯净水.7 分钟前
Chrome调试工具(查看CSS属性)
前端·chrome
栈老师不回家1 小时前
Vue 计算属性和监听器
前端·javascript·vue.js
前端啊龙1 小时前
用vue3封装丶高仿element-plus里面的日期联级选择器,日期选择器
前端·javascript·vue.js
一颗松鼠1 小时前
JavaScript 闭包是什么?简单到看完就理解!
开发语言·前端·javascript·ecmascript
小远yyds1 小时前
前端Web用户 token 持久化
开发语言·前端·javascript·vue.js
吕彬-前端2 小时前
使用vite+react+ts+Ant Design开发后台管理项目(五)
前端·javascript·react.js
学前端的小朱2 小时前
Redux的简介及其在React中的应用
前端·javascript·react.js·redux·store
guai_guai_guai3 小时前
uniapp
前端·javascript·vue.js·uni-app