I googled a lot and many answers are Yes. For example: Is GET data also encrypted in HTTPS? But the senior security engineer in our company told me the URL would not be encrypted.
Image that, if the URL was encrypted, how does the DNS server find the host and connect?
I think is this is very strong point although it's against most of the answers. So I'm really confused and my questions are:
Does https encrypt the everything in the request? (including the URL, host, path, parameters, headers)
If yes, how the DNS server decrypt the request and send it to the host server?
I tried to access https://www.amazon.com/gp/css/homepage.html/ref=ya_surl_youracct and my IE sent two requests to the server:
First:
CONNECT www.amazon.com:443 HTTP/1.0
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
Host: www.amazon.com
Content-Length: 0
DNT: 1
Connection: Keep-Alive
Pragma: no-cache
Second:
GET /gp/css/homepage.html/ref=ya_surl_youracct HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
Accept-Language: en-US,zh-CN;q=0.5
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
Accept-Encoding: gzip, deflate
Host: www.amazon.com
DNT: 1
Connection: Keep-Alive
It seems my browser has requested twice: the first time is to establish the connection with host (without encryption) and the second time send an encrypted request over https? Am I right? If I am understanding this correctly, when a client call the RESTFUL API using https, it sends the requests (connection and get/post) twice every time?
The URL IS encrypted from the time it leaves the browser until it hits the destination server.
What happens is that the browser extracts the domain name and the port from the URL and uses that to resolve DNS itself. Then it starts an encrypted channel to the destination server IP:port. Then it sends a HTTP request through that encrypted channel.
The important part is anyone but you and the destination server can only see that you're connecting to a specific IP address and port. They can't tell anything else (like specific URLs, GET parameters, etc).
Attackers can't even see the domain in most cases (though they can infer it if there is actually a DNS lookup - if it wasn't cached).
The big thing to understand is that DNS (Domain Name Service) is a completely different service with a different protocol from HTTP. The browser makes DNS lookup requests to convert a domain name into an IP address. Then it uses that IP address to issue a HTTP request.
But at no time does the DNS server receive a HTTP request, and at no time does it actually do anything other than provide a domain-name - IP mapping for users.
While the other responses are correct so far as they go, there are many other considerations than just the encryption between the browser and the server. Here are some things to think about...
The IP address of the server is resolved.
The browser makes a TCP socket connection to the server's IP address using TLS. This is the CONNECT you see in your example.
The request is sent to the server over the encrypted session.
If this was all there is to it, you are done. No problem.
But wait, there's more!
Having the fields in a GET instead of a POST reveals sensitive data when...
Someone looks in the server logs. This might be a snoopy employee, but it can also be the NSA or other three-letter government agency, or the logs might become public record if subpoenaed in a trial.
An attacker causes the web site encryption to fall back to cleartext or a broken cipher. Have a look at the SSL checker from Qualsys labs to see if a site is vulnerable to this.
Any link on the page to an external site will show the URI of the page as the referrer. User ID and passwords are unintentionally yet commonly given away in this fashion to advertising networks. I sometimes spot these in my own blog.
The URL is available in the browser history and therefore accessible to scripts. If the computer is public (someone checks your web site from the guest PC in the hotel or airport lounge) the GET request leaks data to anyone else using that device.
As I mentioned, I sometimes find IDs, passwords and other sensitive info in the referrer logs of my blogs. In my case, I contact the owner of the referring site and tell them they are exposing their users to hacking. A less scrupulous person would add comments or updates to the site with links to their own web site, with the intention of harvesting the sensitive data in their referrer logs.
So your company's senior security engineer is correct that the URL is not encrypted in many places where it is extremely important to do so. You and the other respondents are also correct that it is encrypted in the very narrow use case of the browser talking to the server in context of a TLS session. Perhaps the confusion you mention has to do with the difference in the scope of these two use cases.
Please see also:
Testing for Exposed Session Variables (OTG-SESS-004)
Session Management - How to protect yourself (Note that "always use POST" is repeated over and over on this page.)
Client account hijacking through abusing session fixation on the provider
The URL (also known as "Uniform Resource Locator") contains four parts:
Protocol (e.g. https)
Host name (e.g. stackoverflow.com)
Port (not always included, typically 80 for http and 443 for https)
Path and file name or query
Some examples:
ftp://www.ftp.org/docs/test.txt
mailto:user#test101.com
news:soc.culture.Singapore
telnet://www.test101.com/
The URL as an entire unit is not actually encrypted because it is not passed in its entirety. The URL is actually pulled apart into bits and each part is used in different ways. E.g. the protocol portion will tell your browser how to use the rest of the URL, the host name will tell it how to look up the IP address of the intended recipient, and the port will tell it, well, which port to use. The only portion of the URL that is passed in the payload itself is the path and query, and that portion is encrypted.
If you take a look at an HTTP request in the raw, it looks something like this:
GET /docs/index.html HTTP/1.1
Host: www.test101.com
Accept: image/gif, image/jpeg, */*
Accept-Language: en-us
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)
(blank line)
--Body goes here--
What you see in the example above is passed. Notice the full URL appears nowhere. The host header can actually be omitted completely (it is not used for routing). The only portion of the URL that appears here is to the right of the GET verb, and only includes the rightmost portion of the original URL. The protocol and the port number appear nowhere in the message itself.
Short answer: Everything to the right of the port number in the URL is included in the payload of the https request and is in fact encrypted.
Related
When looking at the REST API documentation from Microsoft, it shows that the headers for a specific request should include a host name. I'd like to know what this is and how do I find it?
Microsoft says that these are the request headers:
POST https://testrest.cloudapp.net/api/Channels('nb:chid:UUID:2c30f424-ab90-40c6-ba41-52a993e9d393')/Start HTTP/1.1
DataServiceVersion: 3.0;NetFx
MaxDataServiceVersion: 3.0;NetFx
Accept: application/json;odata=minimalmetadata
Accept-Charset: UTF-8
x-ms-version: 2.11
Content-Type: application/json;odata=minimalmetadata
Host: <host URI>
User-Agent: Microsoft ADO.NET Data Services
Authorization: Bearer <token value>
I'm having trouble connecting due to receiving a 400 error and without the Host URI. The reason I didn't use it at first is because Postman doesn't use one however their API call was successful. Does anyone know if the Host URI is necessary and if so, where can I find it in Microsoft Azure? Specifically for Media Services.
In Http 1.1, The Host header is necessary.
Main points of Http:
HTTP/1.0 does not bring host, and HTTP/1.1 adds host head.
Host can be a domain name, or IP, or port number.
Host can be customized by programs. Some programs can define false host in order to prevent operators or bypass firewalls.
Host in HTTP/1.1 can be null value but not without. If no host head is taken, 400 Bad request will be returned.
The HTTP response header does not contain the host field.
Some sites do not check host and can pass arbitrary values.
In Postman, it will automatically fills the host header with the host (domain name) in URL.
In your case, we can fill the host header with testrest.cloudapp.net:433
According to this MSDN article https://msdn.microsoft.com/en-us/library/ms525396(v=vs.90).aspx these variables are set based on headers. I'm curious if the HTTP_HOST variable is spoofable. I've run a few tests that indicate it's not spoofable, but I'd like to be sure.
EDIT: For clarity, I'm curious if something like a server proxy, man in the middle, or just someone who knows how to use netcat could forge the appropriate headers in order to manipulate HTTP_HOST within my scripts.
Yes it is spoofable.
A malicious user for your website can set any host header they want in their HTTP request and the HTTP_HOST variable will reflect that:
GET / HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)
The only caveat is that it must be bound on your webserver. For example, if you use an IIS webserver you specify which hosts your website is bound to. This can be blank for "any" or you can set it to a specific domain name. If the latter, then at attacker sending
GET / HTTP/1.1
Host: www.foo.com
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)
to your example.com domain would not hit your example.com website but would hit the default IIS website if that itself was running and if this has a blank binding. If it wasn't running then an error is returned instead. These measures will protect you from spoofing in attacks such as cache poisoning or spoofing malicious password reset emails.
Also note that HTTPS sites do not use the host header. They either bind directly to a single IP, or they use Server Name Indication (SNI), which is sent as part of the TLS/SSL handshake to determine which website the request is made to. IIS 8 and above support SNI and this introduces a per binding certificate that is interpreted in the same way as the host header for plain HTTP. Note that this can be spoofed in the same way by an attacker at the browser end because they can send whichever domain name they want.
However, SNI information cannot be altered by a Man-In-The-Middle attacker like it can with a plain HTTP request. This is because the browser will check that the domain name matches the requested site and will warn the user if this is not the case. There is no such authentication with plain HTTP. The only attack I could think of in a MITM scenario with HTTPS is one where wildcard certificates are used and that a MITM could make the user hit a different site than expecting with no browser warning. However the TLS handshake FINISHED message hash would not calculate if this had been altered by a MITM, so that should mitigate this attack.
I'm trying to get Wireshark output that is as close as possible to using a browser
manually, via wget or urllib.
The output is different, and I was wondering why, and how do I overcome this?
Thanks!
wget is used primarily to grab whole or partial web sites for offline viewing, or for fast download of single files from HTTP or FTP servers instead.
A browser request contains HTTP headers like User Agent, Referer, etc.
If you want to mimic wget to a browser like request, you can pass HTTP headers with your wget request.
Something like this-
# wget http://www.remote.co.in/images/myimage.jpg --header="User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:23.0) Gecko/20100101 Firefox/23.0" --header="Accept: image/png,image/;q=0.8,/*;q=0.5" --header="Accept-Language: en-US,en;q=0.5" --header="Accept-Encoding: gzip, deflate" --header="Referer: http://www.mywebsite.com"
There are a couple things...
A browser:
May have several specific headers (useragent, cookies, referer, misc. pplugins, no-track)
Requests all child elements/scripts/resources, possibly on the same connection (keep-alive)
May request gzipped datastream in return
WGet:
Has minimal headers by default (useragent), but can use/alter others with parameters
Is generally a 1-off, requesting only the main html only and not its child resources
It may be if you are seeing different main HTML that the site is server-side scripting tailored content based on useragent and/or cookies (e.g. "logged in")
I am interested in trying to figure out exactly what is going on when a user types in, for example
https://www.bing.com
which lands them on
http://www.bing.com
If you'll notice, www.bing.com apparently doesnt support https, so the page returned has no cert associated with it. Shouldn't the browser complain about this? What's more, is that when looking at the HTTP headers, I never actually see a ridirect or anything that indicates this page returned is not the https version (guess I was expecting some indication this happened).
For another example, gmail does something similar -
I go to https://gmail.com
and I end up on mail.google.com or accounts.google.com depending on whether I'm logged in or not. At least these sites give me a cert, unlike bing, but how come the browser doesn't complain that the URL's are mismatched? It seems like I should also get a cert for gmail.com is that case, right? (the cert on the gmail redirect is good for mail.google.com, but makes no mention wildcard or otherwise of gmail.com)
There's nothing special going on. It's a simple HTTP redirect, but you'll only see it if you ignore the SSL certificate error. (https://www.bing.com currently serves a certificate issued to akamai.) Remember, once you tell your browser to ignore the cert error, it will generally remember that choice for the rest of the session.
If you instruct your browser to ignore the SSL certificate error, the following happens inside a SSL-encrypted connection:
GET https://www.bing.com/ HTTP/1.1
Host: www.bing.com
Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.73 Safari/537.36
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8,es;q=0.6
HTTP/1.1 302 Moved Temporarily
Server: AkamaiGHost
Content-Length: 0
Location: http://www.bing.com/
Date: Thu, 02 May 2013 22:02:28 GMT
Connection: keep-alive
There's no rule against a HTTPS site redirecting to plain HTTP1, so the browser just does a normal request for http://www.bing.com. Since we're now on a plain HTTP page, there's nothing to display (warning or otherwise) regarding certificates.
1 - except in certain situations involving POST requests, where some browsers issue warnings.
The other sites you mention work similarly, except the redirect from gmail.com is to https://mail.google.com. mail.google.com has its own certificate, distinct from https://www.gmail.com's certificate.
Reading over
http://getpocket.com/api/docs/
Is it safe to pass a password through the HTTP string? My understand is that this is not safe, even though it's HTTPS. Correct?
The API documentation states that you're passing over HTTPS. Actually all of the information whether GET or POST in the HTTP Header is part of the SSL Transport therefore the URL parameters are encrypted as well, so your GET parameters are encrypted. What can't be guaranteed is what your client will retain. Or if there was some other process that exposed some information such as when your server did a DNS lookup for the host name. Another example is if you have a browser and it keeps a history of everything you type in it including your https urls then you may compromise your security.
Below is the HTTP Header, your client will initiate a TCP connection and send something like the following:
GET /tutorials/other/top-20-mysql-best-practices/ HTTP/1.1
Host: net.tutsplus.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Cookie: PHPSESSID=r2t5uvjq435r4q7ib3vtdjq120
Pragma: no-cache
Cache-Control: no-cache
SSL will dictate that all that information is encrypted along with anything that is sent back. I would say you're safe using this API, the only difference between the GET and the POST methods would be that in the POST the parameters would be in the body whereas with the GET the parameters are in the header. In both cases all the sensitive information is encrypted.
I agree in principle that it sounds unsafe. URLs can end up in all kinds of funny places in plain text (even over HTTPS), like logs. It would be best to avoid having it in plaintext anywhere.
You should probably talk to the API authors about whether there is an alternative strategy. For example, it looks like some of those methods support both POST and GET, in which case you could possibly POST password details, which is a relatively safe thing to do over an HTTPS connection.