fix(TLS/SNI): Improve TLS session resumption handling and logging. Now, session resumption attempts are always logged with details, and connections without a proper SNI are rejected when allowSessionTicket is disabled. In addition, empty SNI extensions are explicitly treated as missing, ensuring stricter and more consistent TLS handshake validation.

This commit is contained in:
2025-03-12 09:56:21 +00:00
parent b48b90d613
commit 1a90566622
4 changed files with 88 additions and 43 deletions

View File

@@ -943,20 +943,28 @@ export class PortProxy {
// Analyze for session resumption attempt (session ticket or PSK)
const resumptionInfo = SniHandler.hasSessionResumption(renegChunk, this.settings.enableTlsDebugLogging);
// Only block if there's a session ticket without SNI
if (resumptionInfo.isResumption && !resumptionInfo.hasSNI) {
if (resumptionInfo.isResumption) {
// Always log resumption attempt for easier debugging
console.log(
`[${connectionId}] Session ticket detected in renegotiation without SNI and allowSessionTicket=false. ` +
`Terminating connection to force new TLS handshake.`
`[${connectionId}] Session resumption detected in renegotiation. ` +
`Has SNI: ${resumptionInfo.hasSNI ? 'Yes' : 'No'}, allowSessionTicket: ${this.settings.allowSessionTicket}`
);
this.initiateCleanupOnce(record, 'session_ticket_blocked');
return;
} else if (resumptionInfo.isResumption && resumptionInfo.hasSNI) {
if (this.settings.enableTlsDebugLogging) {
// Block if there's session resumption without SNI
if (!resumptionInfo.hasSNI) {
console.log(
`[${connectionId}] Session ticket with SNI detected in renegotiation. ` +
`Allowing connection since SNI is present.`
`[${connectionId}] Session resumption detected in renegotiation without SNI and allowSessionTicket=false. ` +
`Terminating connection to force new TLS handshake.`
);
this.initiateCleanupOnce(record, 'session_ticket_blocked');
return;
} else {
if (this.settings.enableDetailedLogging) {
console.log(
`[${connectionId}] Session resumption with SNI detected in renegotiation. ` +
`Allowing connection since SNI is present.`
);
}
}
}
}
@@ -1575,25 +1583,33 @@ export class PortProxy {
// Analyze for session resumption attempt
const resumptionInfo = SniHandler.hasSessionResumption(chunk, this.settings.enableTlsDebugLogging);
// Only block if there's a session ticket without SNI
if (resumptionInfo.isResumption && !resumptionInfo.hasSNI) {
if (resumptionInfo.isResumption) {
// Always log resumption attempt for easier debugging
console.log(
`[${connectionId}] Session ticket detected in initial ClientHello without SNI and allowSessionTicket=false. ` +
`Terminating connection to force new TLS handshake.`
`[${connectionId}] Session resumption detected in initial ClientHello. ` +
`Has SNI: ${resumptionInfo.hasSNI ? 'Yes' : 'No'}, allowSessionTicket: ${this.settings.allowSessionTicket}`
);
if (connectionRecord.incomingTerminationReason === null) {
connectionRecord.incomingTerminationReason = 'session_ticket_blocked';
this.incrementTerminationStat('incoming', 'session_ticket_blocked');
}
socket.end();
this.cleanupConnection(connectionRecord, 'session_ticket_blocked');
return;
} else if (resumptionInfo.isResumption && resumptionInfo.hasSNI) {
if (this.settings.enableTlsDebugLogging) {
// Block if there's session resumption without SNI
if (!resumptionInfo.hasSNI) {
console.log(
`[${connectionId}] Session ticket with SNI detected in initial ClientHello. ` +
`Allowing connection since SNI is present.`
`[${connectionId}] Session resumption detected in initial ClientHello without SNI and allowSessionTicket=false. ` +
`Terminating connection to force new TLS handshake.`
);
if (connectionRecord.incomingTerminationReason === null) {
connectionRecord.incomingTerminationReason = 'session_ticket_blocked';
this.incrementTerminationStat('incoming', 'session_ticket_blocked');
}
socket.end();
this.cleanupConnection(connectionRecord, 'session_ticket_blocked');
return;
} else {
if (this.settings.enableDetailedLogging) {
console.log(
`[${connectionId}] Session resumption with SNI detected in initial ClientHello. ` +
`Allowing connection since SNI is present.`
);
}
}
}
}
@@ -1949,25 +1965,33 @@ export class PortProxy {
// Analyze for session resumption attempt
const resumptionInfo = SniHandler.hasSessionResumption(chunk, this.settings.enableTlsDebugLogging);
// Only block if there's a session ticket without SNI
if (resumptionInfo.isResumption && !resumptionInfo.hasSNI) {
if (resumptionInfo.isResumption) {
// Always log resumption attempt for easier debugging
console.log(
`[${connectionId}] Session ticket detected in initial ClientHello without SNI and allowSessionTicket=false. ` +
`Terminating connection to force new TLS handshake.`
`[${connectionId}] Session resumption detected in SNI handler. ` +
`Has SNI: ${resumptionInfo.hasSNI ? 'Yes' : 'No'}, allowSessionTicket: ${this.settings.allowSessionTicket}`
);
if (connectionRecord.incomingTerminationReason === null) {
connectionRecord.incomingTerminationReason = 'session_ticket_blocked';
this.incrementTerminationStat('incoming', 'session_ticket_blocked');
}
socket.end();
this.cleanupConnection(connectionRecord, 'session_ticket_blocked');
return;
} else if (resumptionInfo.isResumption && resumptionInfo.hasSNI) {
if (this.settings.enableTlsDebugLogging) {
// Block if there's session resumption without SNI
if (!resumptionInfo.hasSNI) {
console.log(
`[${connectionId}] Session ticket with SNI detected in initial ClientHello. ` +
`Allowing connection since SNI is present.`
`[${connectionId}] Session resumption detected in SNI handler without SNI and allowSessionTicket=false. ` +
`Terminating connection to force new TLS handshake.`
);
if (connectionRecord.incomingTerminationReason === null) {
connectionRecord.incomingTerminationReason = 'session_ticket_blocked';
this.incrementTerminationStat('incoming', 'session_ticket_blocked');
}
socket.end();
this.cleanupConnection(connectionRecord, 'session_ticket_blocked');
return;
} else {
if (this.settings.enableDetailedLogging) {
console.log(
`[${connectionId}] Session resumption with SNI detected in SNI handler. ` +
`Allowing connection since SNI is present.`
);
}
}
}
}