[ssl] Are HTTPS URLs encrypted?

Are all URLs encrypted when using TLS/SSL (HTTPS) encryption? I would like to know because I want all URL data to be hidden when using TLS/SSL (HTTPS).

If TLS/SSL gives you total URL encryption then I don't have to worry about hiding confidential information from URLs.

This question is related to ssl https httprequest

The answer is


Linking to my answer on a duplicate question. Not only is the URL available in the browsers history, the server side logs but it's also sent as the HTTP Referer header which if you use third party content, exposes the URL to sources outside your control.


Since nobody provided a wire capture, here's one.
Server Name (the domain part of the URL) is presented in the ClientHello packet, in plain text.

The following shows a browser request to:
https://i.stack.imgur.com/path/?some=parameters&go=here

ClientHello SNI See this answer for more on TLS version fields (there are 3 of them - not versions, fields that each contain a version number!)

From https://www.ietf.org/rfc/rfc3546.txt:

3.1. Server Name Indication

[TLS] does not provide a mechanism for a client to tell a server the name of the server it is contacting. It may be desirable for clients to provide this information to facilitate secure connections to servers that host multiple 'virtual' servers at a single underlying network address.

In order to provide the server name, clients MAY include an extension of type "server_name" in the (extended) client hello.


In short:

  • FQDN (the domain part of the URL) MAY be transmitted in clear inside the ClientHello packet if SNI extension is used

  • The rest of the URL (/path/?some=parameters&go=here) has no business being inside ClientHello since the request URL is a HTTP thing (OSI Layer 7), therefore it will never show up in a TLS handshake (Layer 4 or 5). That will come later on in a GET /path/?some=parameters&go=here HTTP/1.1 HTTP request, AFTER the secure TLS channel is established.


EXECUTIVE SUMMARY

Domain name MAY be transmitted in clear (if SNI extension is used in the TLS handshake) but URL (path and parameters) is always encrypted.


MARCH 2019 UPDATE

Thank you carlin.scott for bringing this one up.

The payload in the SNI extension can now be encrypted via this draft RFC proposal. This capability only exists in TLS 1.3 (as an option and it's up to both ends to implement it) and there is no backwards compatibility with TLS 1.2 and below.

CloudFlare is doing it and you can read more about the internals here — If the chicken must come before the egg, where do you put the chicken?

In practice this means that instead of transmitting the FQDN in plain text (like the Wireshark capture shows), it is now encrypted.

NOTE: This addresses the privacy aspect more than the security one since a reverse DNS lookup MAY reveal the intended destination host anyway.

SEPTEMBER 2020 UPDATE

There's now a draft RFC for encrypting the entire Client Hello message, not just the SNI part: https://datatracker.ietf.org/doc/draft-ietf-tls-esni/?include_text=1

At the time of writing this browser support is VERY limited.


Entire request and response is encrypted, including URL.

Note that when you use a HTTP Proxy, it knows the address (domain) of the target server, but doesn't know the requested path on this server (i.e. request and response are always encrypted).


Additionally, if you're building a ReSTful API, browser leakage and http referer issues are mostly mitigated as the client may not be a browser and you may not have people clicking links.

If this is the case I'd recommend oAuth2 login to obtain a bearer token. In which case the only sensitive data would be the initial credentials...which should probably be in a post request anyway


Yes and no.

The server address portion is NOT encrypted since it is used to set up the connection.

This may change in future with encrypted SNI and DNS but as of 2018 both technologies are not commonly in use.

The path, query string etc. are encrypted.

Note for GET requests the user will still be able to cut and paste the URL out of the location bar, and you will probably not want to put confidential information in there that can be seen by anyone looking at the screen.


It is now 2019 and the TLS v1.3 has been released. According to Cloudflare, the server name indication (SNI aka the hostname) can be encrypted thanks to TLS v1.3. So, I told myself great! Let's see how it looks within the TCP packets of cloudflare.com So, I caught a "client hello" handshake packet from a response of the cloudflare server using Google Chrome as browser & wireshark as packet sniffer. I still can read the hostname in plain text within the Client hello packet as you can see below. It is not encrypted.

enter image description here

So, beware of what you can read because this is still not an anonymous connection. A middleware application between the client and the server could log every domain that are requested by a client.

So, it looks like the encryption of the SNI requires additional implementations to work along with TLSv1.3

UPDATE June 2020: It looks like the Encrypted SNI is initiated by the browser. Cloudflare has a page for you to check if your browser supports Encrypted SNI:

https://www.cloudflare.com/ssl/encrypted-sni/

At this point, I think Google chrome does not support it. You can activate Encrypted SNI in Firefox manually. When I tried it for some reason, it didn't work instantly. I restarted Firefox twice before it worked:

Type: about:config in the URL field.

Check if network.security.esni.enabled is true. Clear your cache / restart

Go to the website, I mentioned before.

As you can see VPN services are still useful today for people who want to ensure that a coffee shop owner does not log the list of websites that people visit.


As the other answers have already pointed out, https "URLs" are indeed encrypted. However, your DNS request/response when resolving the domain name is probably not, and of course, if you were using a browser, your URLs might be recorded too.


Additionally, if you're building a ReSTful API, browser leakage and http referer issues are mostly mitigated as the client may not be a browser and you may not have people clicking links.

If this is the case I'd recommend oAuth2 login to obtain a bearer token. In which case the only sensitive data would be the initial credentials...which should probably be in a post request anyway


I agree with the previous answers:

To be explicit:

With TLS, the first part of the URL (https://www.example.com/) is still visible as it builds the connection. The second part (/herearemygetparameters/1/2/3/4) is protected by TLS.

However there are a number of reasons why you should not put parameters in the GET request.

First, as already mentioned by others: - leakage through browser address bar - leakage through history

In addition to that you have leakage of URL through the http referer: user sees site A on TLS, then clicks a link to site B. If both sites are on TLS, the request to site B will contain the full URL from site A in the referer parameter of the request. And admin from site B can retrieve it from the log files of server B.)


Entire request and response is encrypted, including URL.

Note that when you use a HTTP Proxy, it knows the address (domain) of the target server, but doesn't know the requested path on this server (i.e. request and response are always encrypted).


Althought there are some good answers already here, most of them are focusing in browser navigation. I'm writing this in 2018 and probably someone wants to know about the security of mobile apps.

For mobile apps, if you control both ends of the application (server and app), as long as you use HTTPS you're secure. iOS or Android will verify the certificate and mitigate possible MiM attacks (that would be the only weak point in all this). You can send sensitive data through HTTPS connections that it will be encrypted during transport. Just your app and the server will know any parameters sent through https.

The only "maybe" here would be if client or server are infected with malicious software that can see the data before it is wrapped in https. But if someone is infected with this kind of software, they will have access to the data, no matter what you use to transport it.


As the other answers have already pointed out, https "URLs" are indeed encrypted. However, your DNS request/response when resolving the domain name is probably not, and of course, if you were using a browser, your URLs might be recorded too.


I agree with the previous answers:

To be explicit:

With TLS, the first part of the URL (https://www.example.com/) is still visible as it builds the connection. The second part (/herearemygetparameters/1/2/3/4) is protected by TLS.

However there are a number of reasons why you should not put parameters in the GET request.

First, as already mentioned by others: - leakage through browser address bar - leakage through history

In addition to that you have leakage of URL through the http referer: user sees site A on TLS, then clicks a link to site B. If both sites are on TLS, the request to site B will contain the full URL from site A in the referer parameter of the request. And admin from site B can retrieve it from the log files of server B.)


While you already have very good answers, I really like the explanation on this website: https://https.cio.gov/faq/#what-information-does-https-protect

in short: using HTTPS hides:

  • HTTP method
  • query params
  • POST body (if present)
  • Request headers (cookies included)
  • Status code

A third-party that is monitoring traffic may also be able to determine the page visited by examining your traffic an comparing it with the traffic another user has when visiting the site. For example if there were 2 pages only on a site, one much larger than the other, then comparison of the size of the data transfer would tell which page you visited. There are ways this could be hidden from the third-party but they're not normal server or browser behaviour. See for example this paper from SciRate, https://scirate.com/arxiv/1403.0297.

In general other answers are correct, practically though this paper shows that pages visited (ie URL) can be determined quite effectively.


Entire request and response is encrypted, including URL.

Note that when you use a HTTP Proxy, it knows the address (domain) of the target server, but doesn't know the requested path on this server (i.e. request and response are always encrypted).


Yes and no.

The server address portion is NOT encrypted since it is used to set up the connection.

This may change in future with encrypted SNI and DNS but as of 2018 both technologies are not commonly in use.

The path, query string etc. are encrypted.

Note for GET requests the user will still be able to cut and paste the URL out of the location bar, and you will probably not want to put confidential information in there that can be seen by anyone looking at the screen.


An addition to the helpful answer from Marc Novakowski - the URL is stored in the logs on the server (e.g., in /etc/httpd/logs/ssl_access_log), so if you don't want the server to maintain the information over the longer term, don't put it in the URL.


Linking to my answer on a duplicate question. Not only is the URL available in the browsers history, the server side logs but it's also sent as the HTTP Referer header which if you use third party content, exposes the URL to sources outside your control.


You can not always count on privacy of the full URL either. For instance, as is sometimes the case on enterprise networks, supplied devices like your company PC are configured with an extra "trusted" root certificate so that your browser can quietly trust a proxy (man-in-the-middle) inspection of https traffic. This means that the full URL is exposed for inspection. This is usually saved to a log.

Furthermore, your passwords are also exposed and probably logged and this is another reason to use one time passwords or to change your passwords frequently.

Finally, the request and response content is also exposed if not otherwise encrypted.

One example of the inspection setup is described by Checkpoint here. An old style "internet café" using supplied PC's may also be set up this way.


Althought there are some good answers already here, most of them are focusing in browser navigation. I'm writing this in 2018 and probably someone wants to know about the security of mobile apps.

For mobile apps, if you control both ends of the application (server and app), as long as you use HTTPS you're secure. iOS or Android will verify the certificate and mitigate possible MiM attacks (that would be the only weak point in all this). You can send sensitive data through HTTPS connections that it will be encrypted during transport. Just your app and the server will know any parameters sent through https.

The only "maybe" here would be if client or server are infected with malicious software that can see the data before it is wrapped in https. But if someone is infected with this kind of software, they will have access to the data, no matter what you use to transport it.


An addition to the helpful answer from Marc Novakowski - the URL is stored in the logs on the server (e.g., in /etc/httpd/logs/ssl_access_log), so if you don't want the server to maintain the information over the longer term, don't put it in the URL.


Yes and no.

The server address portion is NOT encrypted since it is used to set up the connection.

This may change in future with encrypted SNI and DNS but as of 2018 both technologies are not commonly in use.

The path, query string etc. are encrypted.

Note for GET requests the user will still be able to cut and paste the URL out of the location bar, and you will probably not want to put confidential information in there that can be seen by anyone looking at the screen.


A third-party that is monitoring traffic may also be able to determine the page visited by examining your traffic an comparing it with the traffic another user has when visiting the site. For example if there were 2 pages only on a site, one much larger than the other, then comparison of the size of the data transfer would tell which page you visited. There are ways this could be hidden from the third-party but they're not normal server or browser behaviour. See for example this paper from SciRate, https://scirate.com/arxiv/1403.0297.

In general other answers are correct, practically though this paper shows that pages visited (ie URL) can be determined quite effectively.


You can not always count on privacy of the full URL either. For instance, as is sometimes the case on enterprise networks, supplied devices like your company PC are configured with an extra "trusted" root certificate so that your browser can quietly trust a proxy (man-in-the-middle) inspection of https traffic. This means that the full URL is exposed for inspection. This is usually saved to a log.

Furthermore, your passwords are also exposed and probably logged and this is another reason to use one time passwords or to change your passwords frequently.

Finally, the request and response content is also exposed if not otherwise encrypted.

One example of the inspection setup is described by Checkpoint here. An old style "internet café" using supplied PC's may also be set up this way.


As the other answers have already pointed out, https "URLs" are indeed encrypted. However, your DNS request/response when resolving the domain name is probably not, and of course, if you were using a browser, your URLs might be recorded too.


While you already have very good answers, I really like the explanation on this website: https://https.cio.gov/faq/#what-information-does-https-protect

in short: using HTTPS hides:

  • HTTP method
  • query params
  • POST body (if present)
  • Request headers (cookies included)
  • Status code

It is now 2019 and the TLS v1.3 has been released. According to Cloudflare, the server name indication (SNI aka the hostname) can be encrypted thanks to TLS v1.3. So, I told myself great! Let's see how it looks within the TCP packets of cloudflare.com So, I caught a "client hello" handshake packet from a response of the cloudflare server using Google Chrome as browser & wireshark as packet sniffer. I still can read the hostname in plain text within the Client hello packet as you can see below. It is not encrypted.

enter image description here

So, beware of what you can read because this is still not an anonymous connection. A middleware application between the client and the server could log every domain that are requested by a client.

So, it looks like the encryption of the SNI requires additional implementations to work along with TLSv1.3

UPDATE June 2020: It looks like the Encrypted SNI is initiated by the browser. Cloudflare has a page for you to check if your browser supports Encrypted SNI:

https://www.cloudflare.com/ssl/encrypted-sni/

At this point, I think Google chrome does not support it. You can activate Encrypted SNI in Firefox manually. When I tried it for some reason, it didn't work instantly. I restarted Firefox twice before it worked:

Type: about:config in the URL field.

Check if network.security.esni.enabled is true. Clear your cache / restart

Go to the website, I mentioned before.

As you can see VPN services are still useful today for people who want to ensure that a coffee shop owner does not log the list of websites that people visit.


Since nobody provided a wire capture, here's one.
Server Name (the domain part of the URL) is presented in the ClientHello packet, in plain text.

The following shows a browser request to:
https://i.stack.imgur.com/path/?some=parameters&go=here

ClientHello SNI See this answer for more on TLS version fields (there are 3 of them - not versions, fields that each contain a version number!)

From https://www.ietf.org/rfc/rfc3546.txt:

3.1. Server Name Indication

[TLS] does not provide a mechanism for a client to tell a server the name of the server it is contacting. It may be desirable for clients to provide this information to facilitate secure connections to servers that host multiple 'virtual' servers at a single underlying network address.

In order to provide the server name, clients MAY include an extension of type "server_name" in the (extended) client hello.


In short:

  • FQDN (the domain part of the URL) MAY be transmitted in clear inside the ClientHello packet if SNI extension is used

  • The rest of the URL (/path/?some=parameters&go=here) has no business being inside ClientHello since the request URL is a HTTP thing (OSI Layer 7), therefore it will never show up in a TLS handshake (Layer 4 or 5). That will come later on in a GET /path/?some=parameters&go=here HTTP/1.1 HTTP request, AFTER the secure TLS channel is established.


EXECUTIVE SUMMARY

Domain name MAY be transmitted in clear (if SNI extension is used in the TLS handshake) but URL (path and parameters) is always encrypted.


MARCH 2019 UPDATE

Thank you carlin.scott for bringing this one up.

The payload in the SNI extension can now be encrypted via this draft RFC proposal. This capability only exists in TLS 1.3 (as an option and it's up to both ends to implement it) and there is no backwards compatibility with TLS 1.2 and below.

CloudFlare is doing it and you can read more about the internals here — If the chicken must come before the egg, where do you put the chicken?

In practice this means that instead of transmitting the FQDN in plain text (like the Wireshark capture shows), it is now encrypted.

NOTE: This addresses the privacy aspect more than the security one since a reverse DNS lookup MAY reveal the intended destination host anyway.

SEPTEMBER 2020 UPDATE

There's now a draft RFC for encrypting the entire Client Hello message, not just the SNI part: https://datatracker.ietf.org/doc/draft-ietf-tls-esni/?include_text=1

At the time of writing this browser support is VERY limited.


Yes and no.

The server address portion is NOT encrypted since it is used to set up the connection.

This may change in future with encrypted SNI and DNS but as of 2018 both technologies are not commonly in use.

The path, query string etc. are encrypted.

Note for GET requests the user will still be able to cut and paste the URL out of the location bar, and you will probably not want to put confidential information in there that can be seen by anyone looking at the screen.


As the other answers have already pointed out, https "URLs" are indeed encrypted. However, your DNS request/response when resolving the domain name is probably not, and of course, if you were using a browser, your URLs might be recorded too.


Examples related to ssl

Requests (Caused by SSLError("Can't connect to HTTPS URL because the SSL module is not available.") Error in PyCharm requesting website A fatal error occurred while creating a TLS client credential. The internal error state is 10013 curl: (35) error:1408F10B:SSL routines:ssl3_get_record:wrong version number How to install OpenSSL in windows 10? ssl.SSLError: tlsv1 alert protocol version Invalid self signed SSL cert - "Subject Alternative Name Missing" "SSL certificate verify failed" using pip to install packages ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:749) Powershell Invoke-WebRequest Fails with SSL/TLS Secure Channel "ssl module in Python is not available" when installing package with pip3

Examples related to https

What's the net::ERR_HTTP2_PROTOCOL_ERROR about? Requests (Caused by SSLError("Can't connect to HTTPS URL because the SSL module is not available.") Error in PyCharm requesting website Android 8: Cleartext HTTP traffic not permitted ssl.SSLError: tlsv1 alert protocol version Invalid self signed SSL cert - "Subject Alternative Name Missing" How do I make a https post in Node Js without any third party module? Page loaded over HTTPS but requested an insecure XMLHttpRequest endpoint How to force Laravel Project to use HTTPS for all routes? Could not create SSL/TLS secure channel, despite setting ServerCertificateValidationCallback Use .htaccess to redirect HTTP to HTTPs

Examples related to httprequest

Http post and get request in angular 6 Postman: How to make multiple requests at the same time Adding header to all request with Retrofit 2 Understanding Chrome network log "Stalled" state Why is this HTTP request not working on AWS Lambda? Simulate a specific CURL in PostMan HTTP Request in Swift with POST method What are all the possible values for HTTP "Content-Type" header? How to get host name with port from a http or https request Why I get 411 Length required error?