Is a Free Proxy Safe? We Played the Owner to Find Out
By the Proxy11 team. Updated .
Every request you send through a proxy passes through someone else's computer. What that person can see depends almost entirely on one thing: whether the site uses HTTPS. We set up proxies of our own, logged everything they could see, and tried the two tricks a dishonest owner would try.
How we tested
We ran three small proxies on one of our own servers, each written to do what a bad owner might do. The first logs everything it can see. The second changes web pages on the way through. The third tries to read encrypted traffic by putting its own certificate in the middle.
Then we sent requests through them with curl 8.5.0 and Python requests 2.31. Every request carried a fake login, username=demo&password=not-my-real-password, and a fake session cookie, session=abc123test. The logs below are what the proxies wrote down. We only removed the port label at the start of each line, left out repeated connection lines in the last test, and shortened one long line of HTML, marked with .... Nothing real was sent, and the test proxies were deleted afterwards.
Over plain HTTP, the owner sees everything
We posted the fake login to an http:// address through the logging proxy. This is the complete log entry:
from 127.0.0.1:39462 POST http://httpbin.org/post HTTP/1.1 Host: httpbin.org User-Agent: curl/8.5.0 Accept: */* Proxy-Connection: Keep-Alive Cookie: session=abc123test Content-Length: 43 Content-Type: application/x-www-form-urlencoded body: username=demo&password=not-my-real-password response: HTTP/1.1 200 OK, 482 bytes
The owner gets your IP address, the full URL, your cookie, the username and the password, and then the page the site sent back. With a real session cookie, they could log in as you without ever knowing your password.
Nothing about this needs special skill. Our logging proxy is a short script, and well-known proxy software can log the same things with a setting.
Over HTTPS, the owner sees the site name and not much else
Then we sent exactly the same login and cookie to an https:// address, with a fake API key in the URL as well, ?key=TEST-API-KEY. The complete log entry:
from 127.0.0.1:39468 CONNECT httpbin.org:443 HTTP/1.1 Host: httpbin.org:443 User-Agent: curl/8.5.0 Proxy-Connection: Keep-Alive TLS ClientHello names the site: httpbin.org tunnel closed: 914 bytes from client, 5050 bytes from site
No path, no API key, no cookie, no password. For HTTPS, your client asks the proxy to open a tunnel to a site, and everything after that is encrypted between you and the site. The proxy just passes bytes it can't read.
It still learns a few things. The site name appears twice: once in the CONNECT request, and once in the start of the encrypted connection, where your client names the site it wants. Some sites and browsers now hide that second one with Encrypted Client Hello, but the CONNECT line still gives the name away. The owner can also see how much data went each way and when, which can hint at what you did, such as an upload or a large download.
| What the owner can see | Plain HTTP | HTTPS |
|---|---|---|
| Your IP address | Yes | Yes |
| Which site you visit | Yes | Yes |
| The page path and anything in the URL | Yes | No |
| Cookies and login sessions | Yes | No |
| Usernames, passwords and form data | Yes | No |
| The pages you get back | Yes | No |
| How much data, and when | Yes | Yes |
| Can change the page | Yes | Only if you ignore a certificate error |
The owner can change pages served over HTTP
Our second proxy adds one line to any HTML page fetched over plain HTTP. Here is the end of example.com fetched through it:
$ curl -s -x http://127.0.0.1:18102 http://example.com | tail -2 ...<script src=/s.js></script><p>This line was added by the proxy.</p> </body></html>
We added a harmless sentence. A dishonest owner could add adverts, a fake login box, a script that mines cryptocurrency, or a download link swapped for malware. Over HTTPS this can't happen without a certificate error, which is the next test.
You can check a proxy for this yourself. Fetch a page that never changes, directly and through the proxy, and compare the fingerprints:
$ curl -s http://example.com | sha256sum | cut -c1-16 25ddf2c883e0d195 $ curl -s -x http://127.0.0.1:18102 http://example.com | sha256sum | cut -c1-16 e09bfb7687616dfe
Different fingerprints mean the proxy changed something. We fetched the direct page twice to make sure it really doesn't change between requests, and it gave the same fingerprint both times. Use a static page for this. Most sites change slightly on every load, so they will look different even through an honest proxy.
Can the owner read HTTPS? Only if you let them
Our third proxy accepts the tunnel request, then answers with its own certificate instead of passing you through to the real site. If your client accepted that, the proxy could read everything. Both curl and Python refused it:
$ curl -sS -x http://127.0.0.1:18103 https://example.com -o /dev/null curl: (60) SSL certificate problem: self-signed certificate requests.exceptions.SSLError: ... certificate verify failed: self-signed certificate
The proxy's log shows the attempt failed, and it read nothing:
CONNECT example.com:443 HTTP/1.1 Host: example.com:443 client refused our certificate: TLSV1_ALERT_UNKNOWN_CA
Now the part that matters. We ran the same request again with certificate checks switched off, using curl -k and verify=False in Python. People do this all the time to make an error go away. This time the proxy logged:
client accepted our certificate, reading request: POST /login HTTP/1.1 Host: example.com User-Agent: python-requests/2.31.0 Accept-Encoding: gzip, deflate, br Accept: */* Connection: keep-alive Content-Length: 43 Content-Type: application/x-www-form-urlencoded username=demo&password=not-my-real-password
With checks off, HTTPS through that proxy was no safer than plain HTTP. The same goes for clicking past a certificate warning in a browser. So if a certificate error shows up only when you use a particular proxy, that proxy is trying to read your traffic. Stop using it. Don't switch the check off.
For the same reason, never install a root certificate because a proxy or proxy service asks you to. That gives it the ability to read your HTTPS traffic without any warning at all.
So what is a free proxy good for?
Used over HTTPS with certificate checks on, a public proxy can see where you go but not what you do there. That makes it fine for a lot of everyday work:
- Fetching public pages and data, for example for scraping.
- Checking how a site looks, or what it shows, from another country.
- Testing your own site from IP addresses that aren't yours.
- Spreading requests over many IPs so one address doesn't hit a rate limit.
Keep these off public proxies:
- Logging in to your accounts, and anything with payment details.
- Anything sent over plain HTTP that you wouldn't want a stranger to read.
- Anything where it matters that nobody knows which sites you visit. The owner sees your IP and the site name together.
A quick safety checklist
- Use
https://URLs. If a site only offers HTTP, assume the proxy owner can read and change it. - Never use
curl -k,verify=Falseor click past a certificate warning while using a proxy. - Never install a certificate a proxy asks you to install.
- Compare a static page's fingerprint directly and through the proxy if you need to know it isn't changing pages.
- Don't log in to anything through a public proxy.
- Rotate between proxies, so no single owner sees all of your traffic.
Our free proxy checker tests whether proxies work, and can help you trim a list before you use it. Whether a proxy is honest is something only tests like the ones above can tell you, so keep your important traffic on HTTPS either way.