You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript实现加密HTTPS请求透传代理:规避自签名证书且防payload泄露

Great question—this is totally feasible, and it’s a smart way to keep your payload end-to-end encrypted while getting around browser restrictions on self-signed certificates. Let’s break down how to pull this off, with concrete code examples for both your Go and Python backends.

Core Concept

What you’re aiming for is end-to-end encrypted request tunneling:

  1. The browser encrypts the request payload directly using the edge API’s TLS certificate (completing the client-side TLS handshake logic)
  2. The encrypted raw TLS byte stream is sent to your backend proxy
  3. Your backend acts as a dumb TCP forwarder—no parsing, no decryption, just passing bytes back and forth between the browser and edge API
  4. The edge API decrypts the request, processes it, sends back an encrypted response, which your backend forwards to the browser for decryption

This ensures your backend never sees the plaintext payload, exactly what you need.

Step-by-Step Implementation

1. Browser Side: Fetch Edge Certificate & Build Encrypted TLS Requests

Directly constructing TLS packets from scratch is complex, so we’ll use the forge library (a pure-JS crypto toolkit with TLS support) to simplify the process.

First, you’ll need to securely obtain the edge API’s certificate (e.g., hardcode its fingerprint in the frontend and verify against a dynamically fetched cert, or pre-distribute the cert to your frontend):

// Load forge (bundle it for browser use via Webpack/Rollup)
import forge from 'node-forge';

// Pre-configured edge API details
const EDGE_API_HOST = 'edge-api.yourdomain.com:443';
const EXPECTED_CERT_FINGERPRINT = 'aa:bb:cc:...'; // Hardcode trusted fingerprint

// Fetch edge API certificate (or use pre-loaded PEM)
async function getEdgeCert() {
  // In production, fetch this via a secure endpoint or use pre-bundled PEM
  const certPem = await fetch('/api/edge-cert').then(res => res.text());
  return forge.pki.certificateFromPem(certPem);
}

// Build and send encrypted request to backend proxy
async function sendEncryptedRequest(payload) {
  const edgeCert = await getEdgeCert();
  
  // Verify certificate fingerprint matches trusted value
  const certFingerprint = forge.pki.getCertificateFingerprint(edgeCert, {md: forge.md.sha256.create()});
  if (certFingerprint !== EXPECTED_CERT_FINGERPRINT) {
    throw new Error('Untrusted edge API certificate');
  }

  // Construct plaintext HTTP request
  const plaintextRequest = `POST /your/edge/endpoint HTTP/1.1
Host: edge-api.yourdomain.com
Content-Type: application/json
Content-Length: ${JSON.stringify(payload).length}

${JSON.stringify(payload)}`;

  // Create TLS client connection
  const tlsClient = forge.tls.createConnection({
    server: false,
    verify: (conn, verified, depth, certs) => {
      // We already verified the fingerprint, so bypass default validation
      return true;
    },
    connected: () => {
      // Send plaintext request once handshake completes
      tlsClient.prepare(plaintextRequest);
    },
    tlsDataReady: (encryptedData) => {
      // Convert forge's binary data to Uint8Array for fetch
      const byteArray = forge.util.createBuffer(encryptedData).toHex().match(/.{1,2}/g)
        .map(byte => parseInt(byte, 16))
        .reduce((buf, byte) => {
          buf.push(byte);
          return buf;
        }, []);

      // Send encrypted TLS bytes to backend proxy
      fetch('/api/proxy', {
        method: 'POST',
        body: new Uint8Array(byteArray),
        headers: {
          'X-Edge-Target': EDGE_API_HOST // Tell backend where to forward
        }
      })
      .then(res => res.arrayBuffer())
      .then(responseBuffer => {
        // Pass edge API's encrypted response back to TLS client for decryption
        tlsClient.process(forge.util.bytesToHex(new Uint8Array(responseBuffer)));
      });
    },
    dataReady: (decryptedResponse) => {
      // Handle plaintext response from edge API
      console.log('Edge API response:', decryptedResponse);
    },
    error: (err) => console.error('TLS Error:', err)
  });

  // Initiate TLS handshake
  tlsClient.handshake();
}

// Usage example
sendEncryptedRequest({key: "secret-value"});

2. Backend Proxy: Go Implementation

Go is ideal for high-performance TCP forwarding. This code creates a simple HTTP endpoint that forwards raw bytes to the edge API:

package main

import (
	"io"
	"net"
	"net/http"
)

func proxyHandler(w http.ResponseWriter, r *http.Request) {
	// Get target edge API from request header
	edgeTarget := r.Header.Get("X-Edge-Target")
	if edgeTarget == "" {
		http.Error(w, "Missing X-Edge-Target header", http.StatusBadRequest)
		return
	}

	// Establish TCP connection to edge API
	edgeConn, err := net.Dial("tcp", edgeTarget)
	if err != nil {
		http.Error(w, "Failed to connect to edge API", http.StatusServiceUnavailable)
		return
	}
	defer edgeConn.Close()

	// Set response headers for binary stream
	w.Header().Set("Content-Type", "application/octet-stream")

	// Bidirectional data forwarding: browser ↔ edge API
	go io.Copy(edgeConn, r.Body)
	io.Copy(w, edgeConn)
}

func main() {
	http.HandleFunc("/api/proxy", proxyHandler)
	http.ListenAndServe(":8080", nil)
}

3. Backend Proxy: Python Implementation

For lighter workloads, use Flask with asyncio to handle bidirectional forwarding:

from flask import Flask, request, Response
import asyncio

app = Flask(__name__)

async def forward_data(source_reader, dest_writer):
    while True:
        data = await source_reader.read(4096)
        if not data:
            break
        dest_writer.write(data)
        await dest_writer.drain()
    dest_writer.close()
    await dest_writer.wait_closed()

async def proxy_tunnel(edge_target, request_data):
    host, port = edge_target.split(':')
    port = int(port)

    # Connect to edge API
    edge_reader, edge_writer = await asyncio.open_connection(host, port)
    
    # Send browser's encrypted data to edge API
    edge_writer.write(request_data)
    await edge_writer.drain()

    # Read encrypted response from edge API
    response_data = b""
    while True:
        chunk = await edge_reader.read(4096)
        if not chunk:
            break
        response_data += chunk
    
    edge_writer.close()
    await edge_writer.wait_closed()
    return response_data

@app.route('/api/proxy', methods=['POST'])
def proxy():
    edge_target = request.headers.get('X-Edge-Target')
    if not edge_target:
        return "Missing X-Edge-Target header", 400

    request_data = request.get_data()
    response_data = asyncio.run(proxy_tunnel(edge_target, request_data))
    
    return Response(response_data, content_type='application/octet-stream')

if __name__ == '__main__':
    app.run(port=8080, debug=False)

Critical Notes

  • Certificate Trust: Always verify the edge API’s certificate fingerprint in the frontend to prevent man-in-the-middle attacks. Never rely on unvalidated certificates.
  • TLS Compatibility: Ensure all parties use the same TLS version (TLS 1.3 is recommended for security and performance).
  • Performance: The Go implementation will handle high concurrency better than Python. Use Go for production if you expect heavy traffic.
  • Error Handling: Add retry logic for TCP connection failures and clear error messages for end users.

内容的提问来源于stack exchange,提问作者gkrizek

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 18:32:41