views:

108

answers:

6

I have written several PHP web services where I pass in arguments via the URL. To prevent unauthorized access, I pass in a unique key as one of the arguments. I call the PHP file via HTTPS, and I am wondering if there's a way I can prevent the script from running if HTTPS is not used.

+2  A: 
if(empty($_SERVER['HTTPS'])) {
    // ....
    exit;
}
Paolo Bergantino
`// Make sure it's a secure connection.``if ($_SERVER['HTTPS'] != 'on')` `header("location: https://{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}");`
Mark Tomlin
A: 
if ($_SERVER['SERVER_PORT']!=443) {
  /* Do something / report something / redirect user to https version */
  exit;
}

The $_SERVER['HTTPS'] variable may also work in your case - but according to comments in PHP documentation it may not work across all servers (it's a property set by the webserver after all... appears to work with Apache, but not sure about IIS, Nginx, lighttp, etc)

Rudu
That wouldn't cover cases where the server is running plain HTTP on port 443 (not very sensible!) or running HTTPS on another port. There doesn't seem to be an ideal solution for this.
Bruno
Well true, but that's an extreme edge case, and as the script writer you can confirm with `phpinfo();` whether that's happening (and indeed whether `$_SERVER['HTTPS']` is defined). The script can be modified if it `HTTPS` is being served from 8080 or some other port. Only if it's a package to be distributed to other developers on different machines configured differently do non-standard config issues really become worrysome.
Rudu
(-1) the port is *mostly*, but not *always* an indication of the protocol used. As long as there is an explicit possibility to check the *protocol*, this is not a good solution
Pekka
Just like `$_SERVER['HTTPS']` is sometimes undefined? That seems unreasonable Pekka. This port is supposed to be used for this purpose only - again, if he's writing code to catch it, he can write code to test it.
Rudu
@Rudu if `$_SERVER['HTTPS']` is undefined, it's not an SSL connection, is it? That can be tested against. The fact remains that the port is *not* indicative of a certain protocol. What if I'm building a portable PHP script that needs to do something specific when called through SSL? What if a customer decides to run the script on port 8443 because 443 is already taken by something else? That's how bugs are born.
Pekka
@Pekka `HTTPS` is only defined by **some** web servers - on others you need to find other methods (Apache 1.x doesn't supply). Your suggestion will bug out on these servers, hence the port approach. A combination of all is going to be best. Hence: *There is no explicit check*.
Rudu
@Rudu point taken. A combination of your and @Paolo's suggestion would indeed be the best thing then. Downvote removed
Pekka
+5  A: 

Slightly off topic, but if you're using PHP with Apache Httpd and mod_ssl, you can force SSL access to files (and PHP scripts) by placing the SSLRequireSSL directive in .htaccess or in the Directory configuration.

Bruno
+1, solving the problem at the root. Even better would be to not even listen to port 80 on that address.
Wrikken
Thanks for your help. I'll give this a shot.
Quenton Jones
A: 

If you are using Apache, you could use mod_rewrite to redirect http requests to be https ones.

For e.g. This is what we use:

RewriteCond %{HTTPS} !=on
RewriteRule ^account(.*) https://%{SERVER_NAME}/account$1   [R=301,L]

This redirects http://domain/account to https://domain/account

letronje
How does this prevent the URL (and its secret token) from being sent to the plain HTTP server before rewrite?
Bruno
@Bruno: True, this doesn't prevent the secret token from being sent. Wrong answer :)
letronje
+1  A: 

To clarify: You want that a client doesn't call a url containing a secret token over a non-encrypted connection, is that right? If so, then the problem is mainly not with you, but with the browser of the client. You may redirect the client to a secure connection if he isn't using one yet, but even if you do so the client already made an insecure, interceptable request to your server, before he get's redirected!

Mozilla is making an effort to solve this problem. As of Firefox 4 a server may send a Strict-Transport-Security header which will prevent an unencrypted access subsequently (though obviously before the header was sent an unencrypted access could still happen.)

Further reading at hacks.mozilla.org

nikic
+1 for talking about STS + the link
Bruno
A: 

You can prevent the server responding to an unencrypted request, but you cannot prevent the client sending it, which is just as bad for password security. And that is not by far the worst problem with putting a secret token in the URL: it remains in the browser history, it can be seen in the referer when the user leaves your site, and any website the user visits can launch a brute-force or dictionary attack via the :visited CSS pseudo-class. All in all, it is a pretty horrible idea - you are better off using SSL-only cookies.

Tgr