0

My client's site provides a certificate to their customers on a per IP basis, when those servers pass our test. This certification is only good for the IP that was tested. So we need to be the ones to serve the certificate so we can validate that the site that is displaying our certificate was indeed tested by us. So when the customer's users click on the link to the certificate, they can trust that that site really was tested by us (that the site isn't being served by another server which wasn't tested by us, but is claiming to be).

The user is directed to our site via a link that looks something like this:

siteB.com/certificate.php?companyid=1234&serverid=4321

The process simplified:

  • User is on site A
  • User clicks on a link directing to my site (site B) to view site A's certificate.
  • My site, site B needs to validate that it really is site A that's trying to display the certificate earned by site A.

Initially, I thought that the $_SERVER var might have a value to indicate who the referring server is, but the answers I received to posting a question about that indicated that while that information is stored in $_SERVER["HTTP_REFERER"], it isn't reliable (plugins or the user may modify this value).

Since I can't rely on that, I need another way to validate that the referring server is who they claim to be. I considered using a one-time use token, but then the valid server could simply circulate tokens to other servers owned by the customer (which haven't been tested), and the customer could that way claim any number of their servers as being certified by us for just the price of one test (as well as damage the integrity of the certificate).

I'm wondering if this problem is impossible to make a foolproof solution for, and that the best that can be done is to obfuscate the uncontrolled endpoint's (the customer's server) means of posting the key for indicating that they're the one the certificate was meant for (e.g., a sneaky customer would have to read some messy obfuscated javascript, or disassemble a closed-source client-side program in order to cheat the system).

My idea thus far is this (and it's terrible):


I'd need to make a closed-source program to run client-side, perhaps via Native Client which would be initiated upon clicking the certificate link on the customer website (site A), that would first validate itself with my site (site B), then open a 3-way line of communication with site A's server, site B's server, and the user, in which site B would validate that site A is who they say they are, and then return to the user either the certificate or an error message stating why the certificate couldn't be loaded (e.g. connection timed-out).

The script on site B with an open stream to the user NaCl program would use curl to get the IP address(es) of site A's server(s) and validate.


To me, this is an awfully crude solution (if it even is a solution), and while most users wouldn't care to look at someone's certificate, making the users who do care go through hoops (installing and running the NaCl program) just to look at a certificate is just madness.

This feels like a bit of a dumb question, but would running this as flash instead be just as safe/unsafe as running a NaCl program?

Surely, there's a better way to go about doing all this...

Community
  • 1
  • 1
Brad T.
  • 252
  • 4
  • 17

2 Answers2

2

Your best bet is to either trust the REFERER or use the ORIGIN header (you would need to setup an AJAX script which can be dropped into the sites to use ORIGIN).

Anything your server receives can easily be spoofed by the client computer, but not by the server they are visiting (without the client's consent). Since your service seems to be for the client, they have no reason to fake the credentials. You would have potential problems with certain plugins and proxies, but your warning message can explain that.

There is no such thing as closed-source client-side code. Anyone could simply decompile it or emulate the runtime, so you would get no extra security.

Public/private keys would also not work (your site generates a thing to encode, the server in question must use its private key to encode it, the client uses the public key to check it). They are still vulnerable to the same issues: a fake site could forward the request, along with perfectly copied headers, to the real site for processing.

Things to remember:

  • AJAX allows headers to be modified by the client and/or server, except the ORIGIN header which is guaranteed by modern browsers (but can be changed by the client with some work)
  • Any standard URL request has all headers generated by the browser, so they can be trusted (can only be changed by the client)
  • Any code or secret (even if compiled, obfuscated, or whatever) which is sent to client computers should be considered public.
  • Any request which isn't from a browser can be faked in every regard, except for the IP address (and even that can be proxied)
Dave
  • 44,275
  • 12
  • 65
  • 105
  • Wonderful! I didn't know about the ORIGIN header. Simply using ajax to validate and redirect to the URL of the certificate page with a one-time use token (provided in validation response) in the querystring sounds perfect. Like you said, there's no reason for the client to want to change this header value. Thanks, Dave! – Brad T. Mar 05 '13 at 02:12
  • Cool!!! If you need any help programming this let me know. I'd love to do it! haha – Phillip Berger Mar 05 '13 at 03:05
1

My idea.. if possible, get the certificate issuing server to create a cookie with a hash based on that referring server's name and a salt based on another set of criteria which is generated in a dynamic, but predictable way, such as using the user's IP address plus day of the week and maybe throw in the number of the hour or current minute (too short of period on the criteria will result in SOME false-positive authentication failures so be careful). Then, when the user arrives at your site, read the cookie's hash and compare it with one generated from the $_SERVER[“HTTP_REFERER”] and the pre established criteria. The downside to this is that the referring servers could publish the secure algorithm if they wanted to be dicks.

Another possible more secure option is to create a JavaScript app which you give to the referring servers that sends your server an AJAX call and in turn your server returns a hash based on the same kind of criteria I mentioned above. The cookie is then set by the referring server based on your AJAX returned hash and when they come to your site it's checked the same way I mentioned before. But since all the processing took place on your server it's totally secure. Sounds like a cool project, good luck with it.

Phillip Berger
  • 2,317
  • 1
  • 11
  • 30
  • 1
    This would not work. Suppose the user visits a fake site, the fake site's server sends a request directly to the good site's server (CURL or whatever), pulls out the cookie information, and forwards it to the client, along with their evil content. The fake site now has a "good" cookie, and whatever encryption / hashing you used is moot. – Dave Mar 05 '13 at 01:44
  • 1
    Also the AJAX idea (and remember that the only safe AJAX header is the ORIGIN) is no more secure than using the REFERER header in a standard URL. However it may be more robust to proxies and other things which might try to hide referrers (makes it work in more cases, does *not* make it more or less secure). – Dave Mar 05 '13 at 01:47