JS `HTTPS` `SSL Pinning` (SSL证书锁定) 绕过与流量拦截

各位观众老爷,晚上好!我是你们的老朋友,今天咱们来聊聊一个有点刺激,但又非常实用的主题:JS环境下的HTTPS SSL Pinning绕过与流量拦截。注意!我们今天讨论的是技术原理和方法,目的是为了更好地理解安全机制,而不是教唆大家干坏事。请务必遵守法律法规,文明用码。

第一部分:SSL Pinning是个啥?为啥要搞它?

首先,咱们得明白SSL Pinning是干嘛的。简单来说,它是一种安全措施,旨在防止中间人攻击(Man-in-the-Middle,MITM)。

想象一下,没有SSL Pinning的情况下,你用手机APP访问银行服务器,数据传输是加密的,看起来很安全。但是!如果有个坏人(中间人)在你和银行服务器之间,他伪造了一个假的银行证书,你的APP一看,嗯,这个证书挺正规的,就和这个“假的银行”建立了连接。然后,你的账号密码、交易信息就被坏人截获了。

而SSL Pinning就像给你的APP安装了一个“验钞机”,它会检查银行服务器的证书是不是它预先“记住”的那个。如果证书不匹配,APP就会拒绝连接,从而防止中间人攻击。

SSL Pinning的实现方式主要有三种:

  • Certificate Pinning (证书锁定): 直接把服务器的证书放到APP里。
  • Public Key Pinning (公钥锁定): 把服务器证书的公钥放到APP里。
  • Hash Pinning (哈希值锁定): 把服务器证书的哈希值放到APP里。

一般来说,公钥锁定和哈希值锁定更常用,因为更新证书更方便,不需要每次都重新发布APP。

为啥要绕过它?

通常情况下,我们是不会绕过SSL Pinning的。但是,在某些特殊情况下,比如:

  • 安全测试: 为了测试APP的安全性,看看是否存在漏洞。
  • 逆向工程: 为了分析APP的内部逻辑和协议。
  • 研究学习: 为了学习SSL Pinning的原理和绕过方法(仅限个人研究!)。

第二部分:JS环境下的SSL Pinning绕过思路

在JS环境下,尤其是Node.js或者Electron等环境中,绕过SSL Pinning的思路主要有以下几种:

  1. Hook (钩子)大法:
    • 修改tls.connect方法。
    • 修改https.request方法。
    • 修改crypto.X509Certificate对象。
  2. 代理 (Proxy) 拦截:
    • 使用中间人代理工具(如Charles、Burp Suite、mitmproxy)进行流量拦截和修改。
    • 自定义代理服务器,修改TLS握手过程。
  3. 证书信任 (Trust Anchor) 修改:
    • 添加自定义的CA证书到系统信任列表。
    • 修改Node.js的默认CA证书列表。

第三部分:代码实战(以Node.js为例)

1. Hook大法绕过

这种方法的核心思想是:在代码执行之前,修改Node.js的内置模块,让它信任我们伪造的证书。

// hook_ssl.js
const tls = require('tls');
const https = require('https');
const crypto = require('crypto');

// 修改tls.connect方法
const originalConnect = tls.connect;
tls.connect = function(...args) {
  const options = args[0];
  if (typeof options === 'object') {
    // 禁用证书验证
    options.rejectUnauthorized = false;
  }
  return originalConnect.apply(this, args);
};

// 修改https.request方法
const originalRequest = https.request;
https.request = function(...args) {
  const options = args[0];
  if (typeof options === 'object') {
    // 禁用证书验证
    options.rejectUnauthorized = false;
  }
  return originalRequest.apply(this, args);
};

// 修改crypto.X509Certificate对象 (可选,更彻底的绕过)
const originalVerify = crypto.X509Certificate.prototype.verify;
crypto.X509Certificate.prototype.verify = function() {
    return true; // 始终返回true,表示验证通过
};

console.log('SSL Pinning Hook injected!');

使用方法:

// app.js
require('./hook_ssl.js'); // 引入hook文件

const https = require('https');

https.get('https://pinned.badssl.com/', (res) => {
  console.log('statusCode:', res.statusCode);
  res.on('data', (d) => {
    process.stdout.write(d);
  });
}).on('error', (e) => {
  console.error(e);
});

运行node app.js,你会发现即使目标网站使用了SSL Pinning,也能成功访问。

注意: 这种方法非常暴力,直接修改了Node.js的内置模块,可能会导致其他问题。建议只在测试环境中使用。

2. 代理拦截绕过

这种方法需要借助中间人代理工具,比如Charles、Burp Suite、mitmproxy等。

  • 步骤1: 配置代理工具,使其监听指定的端口。
  • 步骤2: 在Node.js代码中,设置代理服务器。
// proxy_app.js
const https = require('https');

const options = {
  hostname: 'pinned.badssl.com',
  port: 443,
  path: '/',
  method: 'GET',
  agent: new https.Agent({
    host: '127.0.0.1', // 代理服务器地址
    port: 8080,        // 代理服务器端口
    rejectUnauthorized: false // 禁用证书验证 (重要!)
  })
};

const req = https.request(options, (res) => {
  console.log('statusCode:', res.statusCode);

  res.on('data', (d) => {
    process.stdout.write(d);
  });
});

req.on('error', (e) => {
  console.error(e);
});

req.end();

运行node proxy_app.js,同时启动代理工具,并配置好SSL代理。代理工具会自动拦截HTTPS流量,并使用自己的证书进行加密。由于我们设置了rejectUnauthorized: false,所以Node.js会信任代理工具的证书,从而绕过SSL Pinning。

3. 证书信任修改绕过

这种方法需要修改Node.js的默认CA证书列表,添加自定义的CA证书。

// trust_anchor_app.js
const https = require('https');
const fs = require('fs');

// 读取自定义CA证书
const ca = fs.readFileSync('path/to/your/ca.pem'); // 替换为你的CA证书路径

const options = {
  hostname: 'pinned.badssl.com',
  port: 443,
  path: '/',
  method: 'GET',
  ca: [ca] // 添加自定义CA证书
};

const req = https.request(options, (res) => {
  console.log('statusCode:', res.statusCode);

  res.on('data', (d) => {
    process.stdout.write(d);
  });
});

req.on('error', (e) => {
  console.error(e);
});

req.end();

重要步骤:

  1. 生成自定义CA证书: 可以使用openssl命令生成。
  2. 将自定义CA证书添加到系统信任列表: 不同操作系统的方法不同,请自行搜索。
  3. 在Node.js代码中,指定自定义CA证书。

第四部分:流量拦截与修改

绕过SSL Pinning后,我们就可以拦截和修改HTTPS流量了。

1. 使用代理工具:

Charles、Burp Suite、mitmproxy等代理工具都提供了强大的流量拦截和修改功能。你可以:

  • 查看请求和响应的详细信息。
  • 修改请求头和响应头。
  • 修改请求体和响应体。
  • 设置断点,手动修改流量。

2. 自定义代理服务器:

如果你想更深入地控制流量,可以自定义代理服务器。

// custom_proxy.js
const http = require('http');
const https = require('https');
const net = require('net');
const tls = require('tls');

const proxyPort = 8080;

const server = http.createServer((req, res) => {
  // 处理HTTP请求
  console.log(`Received HTTP request: ${req.method} ${req.url}`);

  // 将请求转发到目标服务器
  const options = {
    hostname: req.headers.host.split(':')[0],
    port: req.headers.host.split(':')[1] || 80,
    path: req.url,
    method: req.method,
    headers: req.headers,
    agent: false // 禁止使用keep-alive连接
  };

  const proxyReq = http.request(options, (proxyRes) => {
    res.writeHead(proxyRes.statusCode, proxyRes.headers);
    proxyRes.pipe(res, { end: true });
  });

  req.pipe(proxyReq, { end: true });

  proxyReq.on('error', (err) => {
    console.error(`HTTP proxy error: ${err.message}`);
    res.writeHead(500, { 'Content-Type': 'text/plain' });
    res.end('HTTP proxy error');
  });
}).on('connect', (req, socket, head) => {
  // 处理HTTPS请求
  const hostname = req.url.split(':')[0];
  const port = req.url.split(':')[1] || 443;

  console.log(`Received HTTPS CONNECT request: ${hostname}:${port}`);

  // 建立到目标服务器的TLS连接
  const tlsSocket = tls.connect({
    host: hostname,
    port: port,
    servername: hostname, // SNI (Server Name Indication)
    rejectUnauthorized: false // 禁用证书验证 (重要!)
  }, () => {
    // 告诉客户端连接已建立
    socket.write('HTTP/1.1 200 Connection Establishedrnrn');

    // 将客户端和目标服务器之间的流量进行转发
    tlsSocket.pipe(socket, { end: true });
    socket.pipe(tlsSocket, { end: true });
  });

  tlsSocket.on('error', (err) => {
    console.error(`HTTPS proxy error: ${err.message}`);
    socket.write('HTTP/1.1 500 Connection Errorrnrn');
    socket.end();
  });

  tlsSocket.write(head); // 写入head数据
});

server.listen(proxyPort, () => {
  console.log(`Proxy server listening on port ${proxyPort}`);
});

这个代码实现了一个简单的HTTP和HTTPS代理服务器。

关键点:

  • rejectUnauthorized: false 禁用证书验证,绕过SSL Pinning。
  • tls.connect 建立到目标服务器的TLS连接。
  • socket.pipe 将客户端和目标服务器之间的流量进行转发。

第五部分:总结与注意事项

总结:

方法 优点 缺点 适用场景
Hook大法 简单粗暴,效果明显 影响范围大,可能会导致其他问题,容易被检测 调试、测试
代理拦截 灵活可控,可以修改流量 需要配置代理工具,有一定的学习成本 抓包分析、流量修改
证书信任修改 比较安全,影响范围较小 需要生成和管理CA证书,操作相对复杂 长期信任特定证书的场景
自定义代理服务器 完全控制流量,可以实现复杂的逻辑 需要编写大量的代码,调试难度较高 需要自定义流量处理逻辑的场景

注意事项:

  • 请务必遵守法律法规,文明用码。
  • 不要将这些技术用于非法用途。
  • 在生产环境中,不要禁用SSL Pinning。
  • 了解SSL Pinning的原理,有助于更好地保护你的应用程序。
  • 时刻关注最新的安全漏洞和绕过技术。

好了,今天的讲座就到这里。希望大家有所收获。记住,技术是一把双刃剑,用好了可以保护自己,用不好可能会伤害别人。请谨慎使用!如果大家还有什么问题,欢迎提问。下次再见!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注