Skip to content

Commit

Permalink
bugfix: 修复因 HttpsAgent 为单例,导致并发请求时因启用了SSL校验导致 proxy 或 sni 请求失败的问题
Browse files Browse the repository at this point in the history
  • Loading branch information
wangliang181230 committed Sep 29, 2024
1 parent 6064fe4 commit bf84613
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 20 deletions.
12 changes: 8 additions & 4 deletions packages/mitmproxy/src/lib/interceptor/impl/req/proxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,12 +116,16 @@ module.exports = {
}

if (interceptOpt.sni != null) {
let unVerifySsl = rOptions.agent.options.rejectUnauthorized === false

rOptions.servername = interceptOpt.sni
if (rOptions.agent && rOptions.agent.options) {
rOptions.agent.options.rejectUnauthorized = false
if (rOptions.agent.options.rejectUnauthorized && rOptions.agent.unVerifySslAgent) {
// rOptions.agent.options.rejectUnauthorized = false // 不能直接在agent上进行修改属性值,因为它采用了单例模式,所有请求共用这个对象的
rOptions.agent = rOptions.agent.unVerifySslAgent
unVerifySsl = true
}
res.setHeader('DS-Interceptor', `proxy: ${proxyTarget}, sni: ${interceptOpt.sni}`)
log.info('proxy intercept: hostname:', originHostname, ', target:', proxyTarget, ', sni replace servername:', rOptions.servername)
res.setHeader('DS-Interceptor', `proxy: ${proxyTarget}, sni: ${interceptOpt.sni}`, (unVerifySsl ? ', unVerifySsl' : ''))
log.info('proxy intercept: hostname:', originHostname, ', target:', proxyTarget, ', sni replace servername:', rOptions.servername, (unVerifySsl ? ', unVerifySsl' : ''))
} else {
res.setHeader('DS-Interceptor', `proxy: ${proxyTarget}`)
log.info('proxy intercept: hostname:', originHostname, ', target:', proxyTarget)
Expand Down
13 changes: 8 additions & 5 deletions packages/mitmproxy/src/lib/interceptor/impl/req/sni.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@ module.exports = {
requestIntercept (context, interceptOpt, req, res, ssl, next) {
const { rOptions, log } = context

let unVerifySsl = rOptions.agent.options.rejectUnauthorized === false

rOptions.servername = interceptOpt.sni
if (rOptions.agent && rOptions.agent.options) {
rOptions.agent.options.rejectUnauthorized = false
if (rOptions.agent.options.rejectUnauthorized && rOptions.agent.unVerifySslAgent) {
// rOptions.agent.options.rejectUnauthorized = false // 不能直接在agent上进行修改属性值,因为它采用了单例模式,所有请求共用这个对象的
rOptions.agent = rOptions.agent.unVerifySslAgent
unVerifySsl = true
}
res.setHeader('DS-Interceptor', `sni: ${interceptOpt.sni}`, (unVerifySsl ? ', unVerifySsl' : ''))

res.setHeader('DS-Interceptor', 'sni: ' + interceptOpt.sni)

log.info('sni intercept: sni replace servername:', rOptions.hostname, '➜', rOptions.servername)
log.info('sni intercept: sni replace servername:', rOptions.hostname, '➜', rOptions.servername, (unVerifySsl ? ', unVerifySsl' : ''))
return true
},
is (interceptOpt) {
Expand Down
23 changes: 18 additions & 5 deletions packages/mitmproxy/src/lib/proxy/common/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,27 @@ function getTimeoutConfig (hostname, serverSetting) {
}
}

function createHttpsAgent (timeoutConfig) {
function createHttpsAgent (timeoutConfig, verifySsl) {
const key = timeoutConfig.timeout + '-' + timeoutConfig.keepAliveTimeout
if (!httpsAgentCache[key]) {
httpsAgentCache[key] = new HttpsAgent({
verifySsl = !!verifySsl

const agent = new HttpsAgent({
keepAlive: true,
timeout: timeoutConfig.timeout,
keepAliveTimeout: timeoutConfig.keepAliveTimeout,
rejectUnauthorized: verifySsl
})

agent.unVerifySslAgent = new HttpsAgent({
keepAlive: true,
timeout: timeoutConfig.timeout,
keepAliveTimeout: timeoutConfig.keepAliveTimeout,
rejectUnauthorized: false
})

httpsAgentCache[key] = agent
log.info('创建 HttpsAgent 成功, timeoutConfig:', timeoutConfig, ', verifySsl:', verifySsl)
}
return httpsAgentCache[key]
}
Expand All @@ -45,13 +57,14 @@ function createHttpAgent (timeoutConfig) {
timeout: timeoutConfig.timeout,
keepAliveTimeout: timeoutConfig.keepAliveTimeout
})
log.info('创建 HttpsAgent 成功, timeoutConfig:', timeoutConfig)
}
return httpAgentCache[key]
}

function createAgent (protocol, timeoutConfig) {
function createAgent (protocol, timeoutConfig, verifySsl) {
return protocol === 'https:'
? createHttpsAgent(timeoutConfig)
? createHttpsAgent(timeoutConfig, verifySsl)
: createHttpAgent(timeoutConfig)
}

Expand Down Expand Up @@ -110,7 +123,7 @@ util.getOptionsFromRequest = (req, ssl, externalProxy = null, serverSetting) =>
if (headers.connection !== 'close') {
const timeoutConfig = getTimeoutConfig(hostname, serverSetting)
// log.info(`get timeoutConfig '${hostname}':`, timeoutConfig)
agent = createAgent(protocol, timeoutConfig)
agent = createAgent(protocol, timeoutConfig, serverSetting.verifySsl)
headers.connection = 'keep-alive'
} else {
agent = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,6 @@ module.exports = function createRequestHandler (createIntercepts, middlewares, e
const rOptions = commonUtil.getOptionsFromRequest(req, ssl, externalProxy, setting)
let url = `${rOptions.method}${rOptions.protocol}//${rOptions.hostname}:${rOptions.port}${rOptions.path}`

if (rOptions.agent) {
rOptions.agent.options.rejectUnauthorized = setting.verifySsl
} else if (rOptions.agent !== false) {
log.error('rOptions.agent 的值有问题:', rOptions)
}

if (rOptions.headers.connection === 'close') {
req.socket.setKeepAlive(false)
} else if (rOptions.customSocketId != null) { // for NTLM
Expand Down

0 comments on commit bf84613

Please sign in to comment.