Customizing TLS (JA3) Fingerprints through HTTP Proxy
git clone https://github.com/lylemi/ja3proxy
cd ja3proxy
make
./ja3proxy -port 8080 -client 360Browser -version 7.5
curl -v -k --proxy http://localhost:8080 https://www.example.comdocker run \
-v ./credentials:/app/credentials \
-p 8080:8080 \
ghcr.io/lylemi/ja3proxy:latest \
-cert /app/credentials/cert.pem \
-key /app/credentials/key.pem \
-client 360Browser \
-version 7.5See compose.yaml
docker compose up -dUsage of ja3proxy:
-addr string
proxy listen host
-port string
proxy listen port (default "8080")
-cert string
proxy tls cert (default "cert.pem")
-key string
proxy tls key (default "key.pem")
-client string
utls client (default "Golang")
-version string
utls client version (default "0")
-upstream string
upstream proxy, e.g. http://user:pass@host:port or socks5://user:pass@host:port
-debug
enable debugIf you encounter connection issues, you can disable uTLS fingerprinting to test if the problem is related to TLS fingerprinting:
# Disable uTLS fingerprinting (use standard TLS)
DISABLE_UTLS=true ./ja3proxy -port 8080
# Or on Windows PowerShell
$env:DISABLE_UTLS="true"; ./ja3proxy.exe -port 8080This will use standard TLS connections instead of uTLS fingerprinting, which can help identify if the issue is with the fingerprinting or the proxy itself.
When using HTTPS URLs, the proxy operates in CONNECT tunnel mode:
- The proxy establishes a TCP tunnel between client and target server
- TLS handshake is handled directly between client and target server
- The proxy only forwards raw TCP data without interfering with TLS
- This ensures maximum compatibility and security
For HTTP URLs, the proxy operates in HTTP proxy mode:
- The proxy handles the HTTP request/response cycle
- TLS fingerprinting can be applied when using
tls-https: trueheader
You can configure proxy settings per request using HTTP headers:
# Set timeout to 15 seconds
curl -H "tls-timeout: 15" --proxy http://localhost:8080 https://www.example.com
# Use specific proxy for this request
curl -H "tls-proxy: http://127.0.0.1:1080" --proxy http://localhost:8080 https://www.example.com
# Force HTTPS upgrade (HTTP requests will be upgraded to HTTPS)
curl -H "tls-https: true" --proxy http://localhost:8080 http://www.example.com
# Set custom TLS client fingerprint using unified identifier
curl -H "tls-client-identifier: chrome_120" --proxy http://localhost:8080 https://www.example.com
# Combine multiple settings
curl -H "tls-timeout: 20" -H "tls-proxy: socks5://127.0.0.1:1080" -H "tls-https: true" -H "tls-client-identifier: firefox_120" --proxy http://localhost:8080 http://www.example.com# Set timeout to 15 seconds
Invoke-WebRequest -Uri "https://www.example.com" -Proxy "http://localhost:8080" -Headers @{"tls-timeout"="15"}
# Use specific proxy for this request
Invoke-WebRequest -Uri "https://www.example.com" -Proxy "http://localhost:8080" -Headers @{"tls-proxy"="http://127.0.0.1:1080"}
# Force HTTPS upgrade
Invoke-WebRequest -Uri "http://www.example.com" -Proxy "http://localhost:8080" -Headers @{"tls-https"="true"}
# Set custom TLS client fingerprint using unified identifier
Invoke-WebRequest -Uri "https://www.example.com" -Proxy "http://localhost:8080" -Headers @{"tls-client-identifier"="chrome_120"}
# Combine multiple settings
Invoke-WebRequest -Uri "http://www.example.com" -Proxy "http://localhost:8080" -Headers @{
"tls-timeout"="20"
"tls-proxy"="socks5://127.0.0.1:1080"
"tls-https"="true"
"tls-client-identifier"="firefox_120"
}# Download curl.exe from https://curl.se/windows/ or use Git Bash
curl.exe -H "tls-timeout: 15" --proxy http://localhost:8080 https://www.example.com
# Set custom TLS client fingerprint using unified identifier
curl.exe -H "tls-client-identifier: chrome_120" --proxy http://localhost:8080 https://www.example.comHeader Parameters:
tls-timeout: Timeout in seconds for proxy requests (default: 10)tls-proxy: Proxy URL for this request (supports http:// and socks5://)tls-https: Force HTTPS upgrade for HTTP requests (set to "true")tls-client-identifier: Unified TLS client identifier (e.g., "chrome_120", "firefox_120", "safari_16_0")
Note: These headers are automatically removed before forwarding requests to target servers.
The tls-client-identifier header allows you to dynamically set TLS fingerprints for each request. Here are comprehensive usage examples:
# Chrome browsers
curl -H "tls-client-identifier: chrome_120" --proxy http://localhost:8080 https://www.example.com
curl -H "tls-client-identifier: chrome_106" --proxy http://localhost:8080 https://www.example.com
curl -H "tls-client-identifier: chrome_102" --proxy http://localhost:8080 https://www.example.com
# Firefox browsers
curl -H "tls-client-identifier: firefox_120" --proxy http://localhost:8080 https://www.example.com
curl -H "tls-client-identifier: firefox_105" --proxy http://localhost:8080 https://www.example.com
curl -H "tls-client-identifier: firefox_102" --proxy http://localhost:8080 https://www.example.com
# Safari browsers
curl -H "tls-client-identifier: safari_16_0" --proxy http://localhost:8080 https://www.example.com
# Edge browsers
curl -H "tls-client-identifier: edge_106" --proxy http://localhost:8080 https://www.example.com
curl -H "tls-client-identifier: edge_85" --proxy http://localhost:8080 https://www.example.com# iOS devices
curl -H "tls-client-identifier: ios_14" --proxy http://localhost:8080 https://www.example.com
curl -H "tls-client-identifier: ios_13" --proxy http://localhost:8080 https://www.example.com
curl -H "tls-client-identifier: ios_12_1" --proxy http://localhost:8080 https://www.example.com
# Android devices
curl -H "tls-client-identifier: android_11" --proxy http://localhost:8080 https://www.example.com# 360 Browser
curl -H "tls-client-identifier: 360browser_11_0" --proxy http://localhost:8080 https://www.example.com
curl -H "tls-client-identifier: 360browser_7_5" --proxy http://localhost:8080 https://www.example.com
# QQ Browser
curl -H "tls-client-identifier: qqbrowser_11_1" --proxy http://localhost:8080 https://www.example.com# Chrome fingerprint
Invoke-WebRequest -Uri "https://www.example.com" -Proxy "http://localhost:8080" -Headers @{"tls-client-identifier"="chrome_120"}
# Firefox fingerprint
Invoke-WebRequest -Uri "https://www.example.com" -Proxy "http://localhost:8080" -Headers @{"tls-client-identifier"="firefox_120"}
# iOS fingerprint
Invoke-WebRequest -Uri "https://www.example.com" -Proxy "http://localhost:8080" -Headers @{"tls-client-identifier"="ios_14"}
# Combine with other settings
Invoke-WebRequest -Uri "https://www.example.com" -Proxy "http://localhost:8080" -Headers @{
"tls-client-identifier"="chrome_120"
"tls-timeout"="15"
"tls-proxy"="socks5://127.0.0.1:1080"
}import requests
# Chrome fingerprint
response = requests.get(
'https://www.example.com',
proxies={'http': 'http://localhost:8080', 'https': 'http://localhost:8080'},
headers={'tls-client-identifier': 'chrome_120'}
)
# Firefox fingerprint
response = requests.get(
'https://www.example.com',
proxies={'http': 'http://localhost:8080', 'https': 'http://localhost:8080'},
headers={'tls-client-identifier': 'firefox_120'}
)
# iOS fingerprint with additional settings
response = requests.get(
'https://www.example.com',
proxies={'http': 'http://localhost:8080', 'https': 'http://localhost:8080'},
headers={
'tls-client-identifier': 'ios_14',
'tls-timeout': '20',
'tls-proxy': 'http://127.0.0.1:1080'
}
)const axios = require('axios');
// Chrome fingerprint
axios.get('https://www.example.com', {
proxy: {
host: 'localhost',
port: 8080,
protocol: 'http'
},
headers: {
'tls-client-identifier': 'chrome_120'
}
});
// Firefox fingerprint
axios.get('https://www.example.com', {
proxy: {
host: 'localhost',
port: 8080,
protocol: 'http'
},
headers: {
'tls-client-identifier': 'firefox_120'
}
});Scenario 1: Web Scraping with Different Browser Fingerprints
# Rotate between different Chrome versions to avoid detection
curl -H "tls-client-identifier: chrome_120" --proxy http://localhost:8080 https://target-site.com
curl -H "tls-client-identifier: chrome_106" --proxy http://localhost:8080 https://target-site.com
curl -H "tls-client-identifier: chrome_102" --proxy http://localhost:8080 https://target-site.comScenario 2: Mobile App Testing
# Test as iOS device
curl -H "tls-client-identifier: ios_14" --proxy http://localhost:8080 https://api.example.com
# Test as Android device
curl -H "tls-client-identifier: android_11" --proxy http://localhost:8080 https://api.example.comScenario 3: Bypass Geographic Restrictions
# Use different browser fingerprints to appear as different users
curl -H "tls-client-identifier: firefox_120" -H "tls-proxy: socks5://proxy1:1080" --proxy http://localhost:8080 https://geo-restricted-site.com
curl -H "tls-client-identifier: chrome_120" -H "tls-proxy: socks5://proxy2:1080" --proxy http://localhost:8080 https://geo-restricted-site.comScenario 4: Security Testing
# Test with various client fingerprints to check server behavior
curl -H "tls-client-identifier: chrome_120" --proxy http://localhost:8080 https://test-site.com
curl -H "tls-client-identifier: firefox_120" --proxy http://localhost:8080 https://test-site.com
curl -H "tls-client-identifier: safari_16_0" --proxy http://localhost:8080 https://test-site.comBased on uTLS library source code, the following TLS clients are supported:
| Client | Version |
|---|---|
| Golang | 0 |
| Chrome | 58 |
| Chrome | 62 |
| Chrome | 70 |
| Chrome | 72 |
| Chrome | 83 |
| Chrome | 87 |
| Chrome | 96 |
| Chrome | 100 |
| Chrome | 102 |
| Chrome | 106 |
| Chrome | 120 |
| Chrome | 131 |
| Chrome | 133 |
| Firefox | 55 |
| Firefox | 56 |
| Firefox | 63 |
| Firefox | 65 |
| Firefox | 99 |
| Firefox | 102 |
| Firefox | 105 |
| Firefox | 120 |
| Safari | 16.0 |
| iOS | 11.1 |
| iOS | 12.1 |
| iOS | 13 |
| iOS | 14 |
| Android | 11 |
| Edge | 85 |
| Edge | 106 |
| 360Browser | 7.5 |
| 360Browser | 11.0 |
| QQBrowser | 11.1 |
If you have any ideas or suggestions, please feel free to submit a pull request. We appreciate any contributions.
If you have any questions or suggestions, please feel free to contact us.