WCF security using client IP address - wcf

I have a WCF service that provides access to some data. Our client has requested that this service be limited such that a given user can only make so many calls within a certain time period. My thinking was to establish a request rate limit and issue a temporary ban to that IP address once it exceeded that limit.
However, there appears to be only one way to get the caller's IP using WCF:
var context = OperationContext.Current;
var props = context.IncomingMessageProperties;
var endpoint = props[RemoteEndpointMessageProperty.Name];
return ((RemoteEndpointMessageProperty)endpoint).Address;
This is not useful to me at all because the RemoteEndpointMessageProperty is set using the Request.UserHostAddress property of the HttpContext under which it is being served. Normally, that'd be fine, except our web services are sitting behind a load balancer which causes Request.UserHostAddress to always show the IP of the load balancer, not the original caller.
I know about using X-Forwarded-For and such, and actually already have that configured on our load balancer, but there doesn't seem to be any way for me to hook into the http request to access the headers short of setting the WCF service to operate in ASP.NET compatibility mode. Is this REALLY my only option?

You can access HTTP headers in the same way. Instead of RemoteEndpointMessageProperty you have to use HttpRequestMessageProperty. This property contains Headers name value collection so you should be able to get any HTTP header from incoming request.

How do you reliably tie up an user with an IP address specially if the user is behind an ISP NAT (or Company NAT), you will only get the ISP's public IP Address. Instead how about identifying your user using an API Key (which many majors such as Google and Twitter are doing) or by other means (such as client certificate) and then track the usage in a persistence store for throttling.
Another option would be to introduce this sort of mechanism of restrictions by IP address at network layer using firewall rules (I am not experienced by assuming it is possible)

Related

How do I get the website subdomain url that calls my API?

I have A.Mysite.com and B.Mysite.com all calling my API.
Is there a way for my API to know where the request came from? (A.Mysite.com vs B.Mysite.com)
Thank you.
If you have control over the two sites calling the API, you can configure the two to send an additional parameter to identify themselves, and use this to track them. You would need to modify the API to accept this additional parameter. This is the ideal solution.
Additionally, there are numerous http parameters that may be used to track the origin of a http request. If the two callers use two different static ip addresses, this would probably be the most reliable method. For example, if the API is written in PHP you could access the remote IP address using $_SERVER['REMOTE_ADDR'].
The domain/subdomain of a website is only used during DNS resolution, when you try to send to the domain. Each domain will always send as it's ip address. If they both originate from the same ip address, they will be indistinguishable unless you add an identifying parameter.

How do I go about setting up SSL for my API and my Web Client in a Azure Cloud Service?

I have 2 web roles in a cloud service; my API and my Web Client. Im trying to setup SSL for both. My question is, do I need two SSL certificates? Do I need 2 domain names?
The endpoint for my api is my.ip.add.ress. The endpoint for my webclient is my.ip.add.ress:8080.
Im not sure how to add the dns entrees for this as there is nowhere for me to input the port number (which I have learned is because its out of the scope of the dns system).
What am I not understanding? This seems to be a pretty standard scenario with Azure Cloud Services (it is set up this way in the example project in this tutorial, for instance http://msdn.microsoft.com/en-us/library/dn735914.aspx) but I can't find anywhere that explains explicitly how to handle this scenario.
First, you are right about DNS not handling port number. For your case, you can simply use one SSL certificate for both endpoints and make the two endpoints have the same domain name. Based on which port is used by user request, the request will be routed to the correct endpoint (API vs. Web Client). Like you said this is a relative common scenario. There is no need to complicate things.
Let's assume you have one domain www.dm.com pointing to the ip address. To access your Web API, your users need to hit https://www.dm.com, without port number which defaults to 443. To access your web client, your users need to hit https://www.dm.com:8080. If you want users to use default port 443 for both web api and web client, you need to create two cloud services instead of one, then web api on one cloud service and web client on the other cloud service. Billing wise, you will be charged the same as one cloud service.
Are there any reasons you want to make 2 different domains and in turn 2 SSL certificates? If so, it is still possible. Based on your requirements, you may have to add extra logic to block requests from the other domain.

Using a RESTful API - Is it secure?

We are partnering with a service provider which exposes their services via RESTful API.
We can authenticate with the API by passing a username and password as URL parameters.
Example: https://example.com/api/service.json?api_user=Username&api_key=Password
I know this is using SSL. However, since the username and password are part of the URL, couldn't this be intercepted by a third party?
No, a third party will only be able to see the destination (example.com). The rest of the URL is actually embedded inside the request.
It helps to understand the process of how an HTTP (or HTTPS) request is made.
determine protocol (in this case HTTPS, using port 443)
get IP address of server using DNS
establish a TCP connection to server (if SSL is involved, it's a bit more complicated)
issue a request to server on the new connection which will look something like
GET /api/service.json?api_user=Username&api_key=Password
Since the actual request is part of the encrypted data stream, there's no way for someone monitoring the connection to extract sensitive information.
The previous answers are both technically correct; if you're using HTTPS, the URL and querystring data will be encrypted prior to transmission and can be considered secure.
However, the fact that an API is asking for a username and password as querystring parameters may indicate a somewhat lax approach to security.
For example, many webservers will log the request querystring parameters by default , which means that your plain-text credentials might be lying around on disk somewhere (and many companies will store, or back up, webserver logs in insecure ways).
In short: passing credentials as querystring parameters isn't a security risk per se, but is generally a bad practice and may be symptomatic of larger security issues.
However, since the username and password are part of the URL, couldn't
this be intercepted by a third party?
The URL is sent under encryption as well. In other words, the process that secures the channel occurs before the URL is sent to the server.
You're safe.

How can I limit access control for my apps running on cloudbees? (Limit which IP addresses can access the services via browser or api)

I have deployed my application on cloudbees, and was wondering how I can create a whitelist of allowed IPs which can access the application via browser requests or API requests.
Thanks
This is not possible on RUN#Cloud shared server pool.
Such IP restriction can be configured on "dedicated" servers as they provide more configuration option with isolated setup
You could write a filter (eg a servlet filter) which looks at the http://en.wikipedia.org/wiki/X-Forwarded-For header - this is the IP of the client - and filter it that way if you like.
(you have to use that header as the routing layer will provide it).

Is a HTTPS query string secure?

I am creating a secure web based API that uses HTTPS; however, if I allow the users to configure it (include sending password) using a query string will this also be secure or should I force it to be done via a POST?
Yes, it is. But using GET for sensitive data is a bad idea for several reasons:
Mostly HTTP referrer leakage (an external image in the target page might leak the password[1])
Password will be stored in server logs (which is obviously bad)
History caches in browsers
Therefore, even though Querystring is secured it's not recommended to transfer sensitive data over querystring.
[1] Although I need to note that RFC states that browser should not send referrers from HTTPS to HTTP. But that doesn't mean a bad 3rd party browser toolbar or an external image/flash from an HTTPS site won't leak it.
From a "sniff the network packet" point of view a GET request is safe, as the browser will first establish the secure connection and then send the request containing the GET parameters. But GET url's will be stored in the users browser history / autocomplete, which is not a good place to store e.g. password data in. Of course this only applies if you take the broader "Webservice" definition that might access the service from a browser, if you access it only from your custom application this should not be a problem.
So using post at least for password dialogs should be preferred. Also as pointed out in the link littlegeek posted a GET URL is more likely to be written to your server logs.
Yes, your query strings will be encrypted.
The reason behind is that query strings are part of the HTTP protocol which is an application layer protocol, while the security (SSL/TLS) part comes from the transport layer. The SSL connection is established first and then the query parameters (which belong to the HTTP protocol) are sent to the server.
When establishing an SSL connection, your client will perform the following steps in order. Suppose you're trying to log in to a site named example.com and want to send your credentials using query parameters. Your complete URL may look like the following:
https://example.com/login?username=alice&password=12345)
Your client (e.g., browser/mobile app) will first resolve your domain name example.com to an IP address (124.21.12.31) using a DNS request. When querying that information, only domain specific information is used, i.e., only example.com will be used.
Now, your client will try to connect to the server with the IP address 124.21.12.31 and will attempt to connect to port 443 (SSL service port not the default HTTP port 80).
Now, the server at example.com will send its certificates to your client.
Your client will verify the certificates and start exchanging a shared secret key for your session.
After successfully establishing a secure connection, only then will your query parameters be sent via the secure connection.
Therefore, you won't expose sensitive data. However, sending your credentials over an HTTPS session using this method is not the best way. You should go for a different approach.
Yes. The entire text of an HTTPS session is secured by SSL. That includes the query and the headers. In that respect, a POST and a GET would be exactly the same.
As to the security of your method, there's no real way to say without proper inspection.
SSL first connects to the host, so the host name and port number are transferred as clear text. When the host responds and the challenge succeeds, the client will encrypt the HTTP request with the actual URL (i.e. anything after the third slash) and and send it to the server.
There are several ways to break this security.
It is possible to configure a proxy to act as a "man in the middle". Basically, the browser sends the request to connect to the real server to the proxy. If the proxy is configured this way, it will connect via SSL to the real server but the browser will still talk to the proxy. So if an attacker can gain access of the proxy, he can see all the data that flows through it in clear text.
Your requests will also be visible in the browser history. Users might be tempted to bookmark the site. Some users have bookmark sync tools installed, so the password could end up on deli.ci.us or some other place.
Lastly, someone might have hacked your computer and installed a keyboard logger or a screen scraper (and a lot of Trojan Horse type viruses do). Since the password is visible directly on the screen (as opposed to "*" in a password dialog), this is another security hole.
Conclusion: When it comes to security, always rely on the beaten path. There is just too much that you don't know, won't think of and which will break your neck.
Yes, as long as no one is looking over your shoulder at the monitor.
I don't agree with the statement about [...] HTTP referrer leakage (an external image in the target page might leak the password) in Slough's response.
The HTTP 1.1 RFC explicitly states:
Clients SHOULD NOT include a Referer
header field in a (non-secure) HTTP
request if the referring page was
transferred with a secure protocol.
Anyway, server logs and browser history are more than sufficient reasons not to put sensitive data in the query string.
Yes, from the moment on you establish a HTTPS connection everyting is secure. The query string (GET) as the POST is sent over SSL.
You can send password as MD5 hash param with some salt added. Compare it on the server side for auth.