Skip to content

Instantly share code, notes, and snippets.

@spaze
Last active August 25, 2024 11:20
Show Gist options
  • Save spaze/558b7c4cd81afa7c857381254ae7bd10 to your computer and use it in GitHub Desktop.
Save spaze/558b7c4cd81afa7c857381254ae7bd10 to your computer and use it in GitHub Desktop.
Opera VPN behind the curtains is just a proxy, here's how it works

2023 update

ℹ️ Please note this research is from 2016 when Opera has first added their browser "VPN", even before the "Chinese deal" was closed. They have since introduced some real VPN apps but this below is not about them.

🕵️ Some folks also like to use this article to show a proof that the Opera browser is a spyware or that Opera sells all your data to 3rd parties or something like that. This article here doesn't say anything like that.


When setting up (that's immediately when user enables it in settings) Opera VPN sends few API requests to https://api.surfeasy.com to obtain credentials and proxy IPs, see below, also see The Oprah Proxy.

The browser then talks to a proxy de0.opera-proxy.net (when VPN location is set to Germany), it's IP address can only be resolved from within Opera when VPN is on, it's 185.108.219.42 (or similar, see below). It's an HTTP/S proxy which requires auth.

When loading a page with Opera VPN enabled, the browser sends a lot of requests to de0.opera-proxy.net with Proxy-Authorization request header.

The Proxy-Authorization header decoded: CC68FE24C34B5B2414FB1DC116342EADA7D5C46B:9B9BE3FAE674A33D1820315F4CC94372926C8210B6AEC0B662EC7CAD611D86A3 (that's sha1(device_id):device_password, where device_id and device_password come from the POST /v2/register_device API call, please note that this decoded header is from another Opera installation and thus contains different device_id and device_password than what is shown below)

These creds can be used with the de0.opera-proxy.net even when connecting from a different machine, it's just an HTTP proxy anyway.

When you use the proxy on a different machine (with no Opera installed), you'll get the same IP as when using Opera's VPN, of course.

This Opera "VPN" is just a preconfigured HTTP/S proxy protecting just the traffic between Opera and the proxy, nothing else. It's not a VPN.

They even call it Secure proxy (besides calling it VPN, sure) in Opera settings.

The API calls are:

  1. https://api.surfeasy.com/v2/register_subscriber
  2. https://api.surfeasy.com/v2/register_device
  3. https://api.surfeasy.com/v2/geo_list
  4. https://api.surfeasy.com/v2/discover

"Everybody gets a proxy" logo

I have automated the API calls and have built The Oprah Proxy, a simple Python script which will fetch the credentials for you. It will also list available locations and proxies.

POST /v2/register_subscriber HTTP/1.1
Host: api.surfeasy.com
Connection: keep-alive
Content-Length: 114
Accept: application/json
SE-Client-Type: se0304
SE-Client-API-Key: 3690AC1CE5B39E6DC67D9C2B46D3C79923C43F05527D4FFADCC860740E9E2B25
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2687.0 Safari/537.36 OPR/38.0.2205.0 (Edition developer)
Accept-Encoding: gzip, deflate, lzma
email=9CDFC88A-F4C7-42F2-90EC-8CFC90C11387%40se0304.surfeasy.vpn&password=90C72B97B498ED2377D107611640726F6165610C
HTTP/1.1 200 OK
Server: nginx/1.8.0
Date: Sun, 24 Apr 2016 01:02:06 GMT
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
Status: 200 OK
X-UA-Compatible: IE=Edge,chrome=1
ETag: "43f3d56b6d9f5a5f571592b807546469"
Cache-Control: max-age=0, private, must-revalidate
Set-Cookie: subscriber_credentials=635d20f66976263af72af312f690a55e796d184f6589871ffafcd173b28fcab472e5f9082dc3e1972d8177fc71451fb6275b8c84af46a3c6b0d7bb6ebe6c3d57%3A%3A; domain=.surfeasy.com; path=/; secure; HttpOnly
Set-Cookie: api_session=BAhJIgGvZXlKcFpDSTZNVEkyT0RFeE5qQXNJbTltSWpvM056YzJNREF3TENKMGF5STZJalkxWkRZeFlXVmpOV1ppCk5UTmhOVFZpTURObU5tSmpORFZrT1dGa05ESTBPV0V6TWpoaE9HRTBOVEptTXpVME16TmpaRGN5WXpNdwpZakl5TVRNM05Ea2lMQ0owYlNJNklqSXdNVFl0TURjdE1qTlVNREU2TURJNk1EWmFJbjA9CgY6BkVG--11e3897571b24700b24190f1a89bce317cfdc6bf; domain=.surfeasy.com; path=/; expires=Sat, 23-Jul-2016 01:02:06 GMT; HttpOnly
Set-Cookie: _proxy_manager_session31=BAh7B0kiD3Nlc3Npb25faWQGOgZFVEkiJWZlOThjYjUzNTU2ODk4NTUzMzFjZjM4NWFjNjE0YWY0BjsAVEkiG3N1YnNjcmliZXJfY3JlZGVudGlhbHMGOwBGSSIBgDYzNWQyMGY2Njk3NjI2M2FmNzJhZjMxMmY2OTBhNTVlNzk2ZDE4NGY2NTg5ODcxZmZhZmNkMTczYjI4ZmNhYjQ3MmU1ZjkwODJkYzNlMTk3MmQ4MTc3ZmM3MTQ1MWZiNjI3NWI4Yzg0YWY0NmEzYzZiMGQ3YmI2ZWJlNmMzZDU3BjsAVA%3D%3D--217a0409bf7bd1c348c06378c41c9369e0cf99bb; domain=.surfeasy.com; path=/; secure; HttpOnly
X-Request-Id: 136be2daeba044ee3ad2241ccaa4e28c
X-Runtime: 0.482677
X-Rack-Cache: invalidate, pass
{
"return_code" : {
"0" : "OK"
},
"data" : {}
}
POST /v2/register_device HTTP/1.1
Host: api.surfeasy.com
Connection: keep-alive
Content-Length: 104
Accept: application/json
SE-Client-Type: se0304
SE-Client-API-Key: 3690AC1CE5B39E6DC67D9C2B46D3C79923C43F05527D4FFADCC860740E9E2B25
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2687.0 Safari/537.36 OPR/38.0.2205.0 (Edition developer)
Accept-Encoding: gzip, deflate, lzma
Cookie: subscriber_credentials=635d20f66976263af72af312f690a55e796d184f6589871ffafcd173b28fcab472e5f9082dc3e1972d8177fc71451fb6275b8c84af46a3c6b0d7bb6ebe6c3d57%3A%3A; api_session=BAhJIgGvZXlKcFpDSTZNVEkyT0RFeE5qQXNJbTltSWpvM056YzJNREF3TENKMGF5STZJalkxWkRZeFlXVmpOV1ppCk5UTmhOVFZpTURObU5tSmpORFZrT1dGa05ESTBPV0V6TWpoaE9HRTBOVEptTXpVME16TmpaRGN5WXpNdwpZakl5TVRNM05Ea2lMQ0owYlNJNklqSXdNVFl0TURjdE1qTlVNREU2TURJNk1EWmFJbjA9CgY6BkVG--11e3897571b24700b24190f1a89bce317cfdc6bf; _proxy_manager_session31=BAh7B0kiD3Nlc3Npb25faWQGOgZFVEkiJWZlOThjYjUzNTU2ODk4NTUzMzFjZjM4NWFjNjE0YWY0BjsAVEkiG3N1YnNjcmliZXJfY3JlZGVudGlhbHMGOwBGSSIBgDYzNWQyMGY2Njk3NjI2M2FmNzJhZjMxMmY2OTBhNTVlNzk2ZDE4NGY2NTg5ODcxZmZhZmNkMTczYjI4ZmNhYjQ3MmU1ZjkwODJkYzNlMTk3MmQ4MTc3ZmM3MTQ1MWZiNjI3NWI4Yzg0YWY0NmEzYzZiMGQ3YmI2ZWJlNmMzZDU3BjsAVA%3D%3D--217a0409bf7bd1c348c06378c41c9369e0cf99bb
client_type=se0304&device_hash=4BE7D6F1BD040DE45A371FD831167BC108554111&device_name=Opera-Browser-Client
HTTP/1.1 200 OK
Server: nginx/1.8.0
Date: Sun, 24 Apr 2016 01:02:06 GMT
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
Status: 200 OK
X-UA-Compatible: IE=Edge,chrome=1
ETag: "41d8e81a485d8c28d98a5a62b08aff2e"
Cache-Control: max-age=0, private, must-revalidate
Set-Cookie: api_session=BAhJIgGvZXlKcFpDSTZNVEkyT0RFeE5qQXNJbTltSWpvM056YzJNREF3TENKMGF5STZJalkxWkRZeFlXVmpOV1ppCk5UTmhOVFZpTURObU5tSmpORFZrT1dGa05ESTBPV0V6TWpoaE9HRTBOVEptTXpVME16TmpaRGN5WXpNdwpZakl5TVRNM05Ea2lMQ0owYlNJNklqSXdNVFl0TURjdE1qTlVNREU2TURJNk1EWmFJbjA9CgY6BkVG--11e3897571b24700b24190f1a89bce317cfdc6bf; domain=.surfeasy.com; path=/; expires=Sat, 23-Jul-2016 01:02:06 GMT; HttpOnly
X-Request-Id: dfa01c93650d7bd47c2e6b64b7b46222
X-Runtime: 0.293166
X-Rack-Cache: invalidate, pass
{
"return_code" : {
"0" : "OK"
},
"data" : {
"device_id" : "se0304-b7327fdf8ba42c3d5f698e1",
"device_password" : "7A64DDCDBDDA78B0FE2B556445E9FBD9CDD96DC01F384013175B0BD172923938",
"client_type" : "se0304"
}
}
POST /v2/geo_list HTTP/1.1
Host: api.surfeasy.com
Connection: keep-alive
Content-Length: 50
Accept: application/json
SE-Client-Type: se0304
SE-Client-API-Key: 3690AC1CE5B39E6DC67D9C2B46D3C79923C43F05527D4FFADCC860740E9E2B25
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2687.0 Safari/537.36 OPR/38.0.2205.0 (Edition developer)
Accept-Encoding: gzip, deflate, lzma
Cookie: subscriber_credentials=635d20f66976263af72af312f690a55e796d184f6589871ffafcd173b28fcab472e5f9082dc3e1972d8177fc71451fb6275b8c84af46a3c6b0d7bb6ebe6c3d57%3A%3A; _proxy_manager_session31=BAh7B0kiD3Nlc3Npb25faWQGOgZFVEkiJWZlOThjYjUzNTU2ODk4NTUzMzFjZjM4NWFjNjE0YWY0BjsAVEkiG3N1YnNjcmliZXJfY3JlZGVudGlhbHMGOwBGSSIBgDYzNWQyMGY2Njk3NjI2M2FmNzJhZjMxMmY2OTBhNTVlNzk2ZDE4NGY2NTg5ODcxZmZhZmNkMTczYjI4ZmNhYjQ3MmU1ZjkwODJkYzNlMTk3MmQ4MTc3ZmM3MTQ1MWZiNjI3NWI4Yzg0YWY0NmEzYzZiMGQ3YmI2ZWJlNmMzZDU3BjsAVA%3D%3D--217a0409bf7bd1c348c06378c41c9369e0cf99bb; api_session=BAhJIgGvZXlKcFpDSTZNVEkyT0RFeE5qQXNJbTltSWpvM056YzJNREF3TENKMGF5STZJalkxWkRZeFlXVmpOV1ppCk5UTmhOVFZpTURObU5tSmpORFZrT1dGa05ESTBPV0V6TWpoaE9HRTBOVEptTXpVME16TmpaRGN5WXpNdwpZakl5TVRNM05Ea2lMQ0owYlNJNklqSXdNVFl0TURjdE1qTlVNREU2TURJNk1EWmFJbjA9CgY6BkVG--11e3897571b24700b24190f1a89bce317cfdc6bf
device_id=6033E218A93734258100C090BE247C416DAD03B6
HTTP/1.1 200 OK
Server: nginx/1.8.1
Date: Sun, 24 Apr 2016 01:02:06 GMT
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
Status: 200 OK
X-UA-Compatible: IE=Edge,chrome=1
ETag: "238ae61eb6ad5f2c85642ef254d7790c"
Cache-Control: max-age=0, private, must-revalidate
X-Request-Id: eb9fde2ffd6714263b96d987e369bf66
X-Runtime: 0.057996
X-Rack-Cache: invalidate, pass
{
"data" : {
"locale" : "en",
"geos" : [
{
"country_code" : "CA",
"country" : "Canada",
"lat" : 43.6667,
"lng" : -79.4167
},
{
"lng" : 8.682,
"lat" : 50.11,
"country_code" : "DE",
"country" : "Germany"
},
{
"country_code" : "US",
"country" : "United States",
"lng" : -74.006,
"lat" : 40.7145
}
]
},
"return_code" : {
"0" : "OK"
}
}
POST /v2/discover HTTP/1.1
Host: api.surfeasy.com
Connection: keep-alive
Content-Length: 50
Accept: application/json
SE-Client-Type: se0304
SE-Client-API-Key: 3690AC1CE5B39E6DC67D9C2B46D3C79923C43F05527D4FFADCC860740E9E2B25
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2687.0 Safari/537.36 OPR/38.0.2205.0 (Edition developer)
Accept-Encoding: gzip, deflate, lzma
Cookie: subscriber_credentials=635d20f66976263af72af312f690a55e796d184f6589871ffafcd173b28fcab472e5f9082dc3e1972d8177fc71451fb6275b8c84af46a3c6b0d7bb6ebe6c3d57%3A%3A; _proxy_manager_session31=BAh7B0kiD3Nlc3Npb25faWQGOgZFVEkiJWZlOThjYjUzNTU2ODk4NTUzMzFjZjM4NWFjNjE0YWY0BjsAVEkiG3N1YnNjcmliZXJfY3JlZGVudGlhbHMGOwBGSSIBgDYzNWQyMGY2Njk3NjI2M2FmNzJhZjMxMmY2OTBhNTVlNzk2ZDE4NGY2NTg5ODcxZmZhZmNkMTczYjI4ZmNhYjQ3MmU1ZjkwODJkYzNlMTk3MmQ4MTc3ZmM3MTQ1MWZiNjI3NWI4Yzg0YWY0NmEzYzZiMGQ3YmI2ZWJlNmMzZDU3BjsAVA%3D%3D--217a0409bf7bd1c348c06378c41c9369e0cf99bb; api_session=BAhJIgGvZXlKcFpDSTZNVEkyT0RFeE5qQXNJbTltSWpvM056YzJNREF3TENKMGF5STZJalkxWkRZeFlXVmpOV1ppCk5UTmhOVFZpTURObU5tSmpORFZrT1dGa05ESTBPV0V6TWpoaE9HRTBOVEptTXpVME16TmpaRGN5WXpNdwpZakl5TVRNM05Ea2lMQ0owYlNJNklqSXdNVFl0TURjdE1qTlVNREU2TURJNk1EWmFJbjA9CgY6BkVG--11e3897571b24700b24190f1a89bce317cfdc6bf
serial_no=6033E218A93734258100C090BE247C416DAD03B6&requested_geo=%22DE%22
HTTP/1.1 200 OK
Server: nginx/1.8.0
Date: Sun, 24 Apr 2016 01:02:07 GMT
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
Status: 200 OK
X-UA-Compatible: IE=Edge,chrome=1
ETag: "7ee0cb88bd334f002fdac08ca1879451"
Cache-Control: max-age=0, private, must-revalidate
X-Request-Id: cd83f3a8974e8997cdcfb265085d3d05
X-Runtime: 0.843848
X-Rack-Cache: invalidate, pass
{
"return_code" : {
"0" : "OK"
},
"data" : {
"current_time" : 1461459727,
"ips" : [
{
"ports" : [
443
],
"ip" : "85.195.94.82",
"geo" : {
"country_code" : "DE",
"state_code" : "5"
},
"expiry_time" : 1462669327
},
{
"expiry_time" : 1462669327,
"ip" : "185.108.219.5",
"geo" : {
"country_code" : "DE",
"state_code" : "2"
},
"ports" : [
80
]
},
{
"ip" : "85.195.110.36",
"geo" : {
"country_code" : "DE",
"state_code" : "5"
},
"ports" : [
8181
],
"expiry_time" : 1462669327
},
{
"expiry_time" : 1462669327,
"ports" : [
22
],
"ip" : "185.108.219.44",
"geo" : {
"country_code" : "DE",
"state_code" : "2"
}
},
{
"expiry_time" : 1462669327,
"ip" : "185.108.219.10",
"geo" : {
"country_code" : "DE",
"state_code" : "2"
},
"ports" : [
443
]
},
{
"ip" : "85.195.110.35",
"geo" : {
"state_code" : "5",
"country_code" : "DE"
},
"ports" : [
80
],
"expiry_time" : 1462669327
},
{
"expiry_time" : 1462669327,
"geo" : {
"state_code" : "2",
"country_code" : "DE"
},
"ip" : "185.108.219.12",
"ports" : [
8181
]
},
{
"expiry_time" : 1462669327,
"ports" : [
22
],
"geo" : {
"state_code" : "5",
"country_code" : "DE"
},
"ip" : "139.59.136.236"
},
{
"expiry_time" : 1462669327,
"ports" : [
443
],
"ip" : "185.108.219.45",
"geo" : {
"country_code" : "DE",
"state_code" : "2"
}
}
],
"requester_geo" : {
"country_code" : "CZ",
"state_code" : "87"
}
}
}
@spaze
Copy link
Author

spaze commented Aug 10, 2024

⚠️⚠️⚠️ The links below this comment are most probably malware or phishing or something like that. You have been warned.

(I'll always delete them as soon as I can)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment