Server and SSL API Security - php

Currently I'm developing an REST API
my API access are only between my server and my client server(B2B, business to business). example : myserverapi.com(My REST API Server) and myclientserver.com(My Client Server who access My API) *no 3rd connection/application
we are implementing api_key(of course it a must), and domain name(so the client specific the domain name that he will access the api, so my server api will only accept from that)
for myserverapi.com, how to only receive connection from myclientserver.com ? is only using $_SERVER['REMOTE_ADDR'] ? Is that enough ? but after reading from a few place, that i can't use that because the IP may be wrong if it under proxy or loadbalancer farm. What's the solution ?
and how if i installed SSL Certificate ? is i must change my code ? or just buy and install on the server side that automatically my api will be secure ?
is openssl-verify function only the secure way to realy get know that the access are from specific server or not ? http://php.net/manual/en/function.openssl-verify.php Is that mean i must change my code to encrypt and decrypt data like in this link http://3stepsbeyond.co.uk/2010/12/openssl-and-php-tutorial-part-two/
so basically i just want to make sure for myserverapi.com to only get access from myclientserver.com. and the myclientserver.com only accept data from myserverapi.com. how to do that ?
I hope some one give me a good explain.
Thank You

There's a series of things you can do. The most code agnostic is HTTPS client certificates. If you don't care about who the user exactly is, but just want to make sure that is an allowed one let apache handle that. It's only a few lines in the config file, and you won't have to touch your code.
Your second option is ACLs, which you can handle again within Apache even at the path level. And of course at an OS level you can apply them as well to IPs and ports. Same applies to a firewall in or in front of your server/servers.
If you don't want to deal with managing certificates or IP/port firewalling and ACLs you can implement 2 legged Oauth. The clients can use a library since they exists in virtually any language already, and the code for the server is not too complicated.

For the SSL Certificate, you don't have to alter your code. You may, however, want to check the server port and throw an exception if not SSL:
if ($_SERVER['SERVER_PORT'] != 443) {
header('405 Method Not Allowed');
exit();
}
Of course, you could accomplish similar restrictions using Apache, by simply not serving out on port 80.
For the IP restrictions, $_SERVER['REMOTE_ADDR'] should work under most conditions. Unfortunately, I don't think there's a way around proxies. However, an API key should be sufficient for most security requirements.

A little late for an answer, but for checking remote_addr for requests that might come via proxy you can check if
X-forwarded-for header is set, and use that if it exists.
http://en.wikipedia.org/wiki/X-Forwarded-For

Related

PHP security concern

I'm using multiple services to accept mobile payments for stuff like virtual currency.
Many companies will include an MD5 signature in the POST or GET callback which I can calculate to verify that the request is authentic and then reward the user with the purchased credits.
This method is very secure as it's nearly impossible to guess the signature.
Other companies will not provide a signature and just tell me to check if the call is from their server IP like the following code:
<?php
if(!in_array($_SERVER['REMOTE_ADDR'],array('xxx.xx.x.xx'))) {
header('HTTP/1.0 403 Forbidden');
die('Error: Unknown IP');
}
?>
Is this IP check secure enough?? Isn't it now very easy to spoof an IP address and make a GET or a POST request using that IP?
The other answers are incorrect. So I'll write my own.
With the exception of exceedingly rare situations, REMOTE_ADDR is 100% trust worthy. It comes from the TCP connection to the server, so it's practically impossible to forge without actually compromising something on the network (like the router the IP belongs to) or without having your server misconfigured (severely, Apache doesn't even let you misconfigure it like that).
So, there are two questions that I can see:
Is it safe to trust REMOTE_ADDR
Yes.
If the REMOTE_ADDR variable in PHP indicates the request came from their server, then it came from their server.
If you're using a remote proxy, then X-HTTP-FORWARDED-FOR is not to be trusted. That's where you can get into problems if you're not careful.
Is MD5() of the request safer than REMOTE_ADDR verification
NO!!!
It's a lot easier to forge an MD5 signature than it is to forge an IP address (which requires you to breach specific network hardware). And if the attacker breaches the network hardware, the game is over anyway.
What's The Best Solution?
The best solution is three fold:
Use HTTPS with Certificate Pinning
On your app, store the public key of their server. Then force the peer verification to use that certificate. That means that an attacker would need to steal the certificate of the remote server to be able to connect.
Verify IP Addresses
Using REMOTE_ADDR
Sign requests using HMAC+SHA2
Use HMAC with SHA-256 or SHA-512.
But yes, the IP check alone is quite secure.
To go deeper, we'd need to go into what types of attacks you're defending from.
Relying on server remote address is not a secure way since IP spoofing can breach the security.
But yes there are some ways by which you can prevent it like key exchange between the machines but still there is no assurance.
Better you should not rely on IP based security.

How i change my ip address to a given address and access a website

How to change ip address such that it does not reveal our original address when using $_SERVER['REMOTE_ADDR']; in php
You need to use a proxy server if you're trying to access a website from a different IP than your own. Wikipedia has more information.
There are several options I have in mind for this. I will go from the simpler to the more complicated one.
First, you could use a proxy server and ask him through an HTTP request made by your program or your browser, to fetch a resource for you. The proxy server will take the role of querying a resource in your place to the target service.
Example :
You want to retrieve the main page of the domain stackoverflow.com. You ask the proxy server to ask stackoverflow's HTTP server to send him the main page and he will forward it back to you.
To SO webserver, the superglobal $_SERVER['REMOTE_ADDR'] variable will correspond to the proxy server's IP address and not yours. However, the HTTP protocol implements some fields such as HTTP_VIA, HTTP_X_FORWARDED_FOR, or HTTP_FORWARDED which can be used to know if the current HTTP request is made by a proxy or not.
A transparent proxy will not specify those fields and will not modify your request whereas a non-transparent proxy may reveal the original IP address of the original requester. You got to use a reliable proxy which will act as you intends it to act. Another thing to consider is the use of an SSL tunnel between you and the proxy to avoid eavesdropping.
The second solution is to use a VPN (Virtual private network) server. It would be too complicated to fully explains how this works, but remember this, when you are connected to a computer using a VPN service (like l2tpd, pptpd ...) it's like you were on the same LAN with this computer. So you can transparently make requests to a webserver and he will never find out what's your real IP address.
A third solution could be to use linked nodes based network such as TOR. It's a free network you can connect to, and you will be completely anonymous to regular people. The TOR network power is to provide a network of many nodes and each nodes doesn't know anything about other nodes, so even people connected to the TOR network cannot know anything about you. I suggest you to read more about this if you're interested.
There are more complicated other solutions such as TCP session hijacking which is generally used to fake IP addresses and literally steal another computer's TCP connection, but this is out of the scope of this answer.

How to fake $_SERVER['REMOTE_ADDR'] variable?

Is it possible to fake or hijack a content of $_SERVER['REMOTE_ADDR'] variable?
I would like to fake a request with:
$_SERVER['REMOTE_ADDR']='127.0.0.1';
How could I do that with PHP? Can CURL do that somehow?
I assume that you mean faking it remotely. The short answer is yes you can. The long answer about how easy it is depends on how you want to fake it.
If you don't care about receiving a response, it's as trivial as opening a raw socket to the destination and forging the source IP address. I'm not sure if it's really easy to do in PHP since all of PHP's socket implementations are at or above the TCP level. But I'm sure it's possible. Now, since you're not in control of the network, the response will not go back to you. So that means that you cannot (reliably anyway) create a TCP connection via a trivial forged TCP header (since the syn-ack does prevent this by requiring two-way communication).
However, if you can compromise the gateway the IP is off of, you can do whatever you'd like. So if you compromise the wifi router a computer is connected to, you can pretend to be that computer, and the server won't tell the difference. If you compromise the ISP's outbound router, you can (in theory at least) pretend to be the computer and the server won't tell the difference.
For some more info, see these following links:
ServerFault Question
Symantec Article
Linux Security Article
However, you will only be able to forge the 127.0.0.1 loopback address under TCP if you actually compromise the local machine/server. And at that point does it really matter?
Important
If you're using a framework to access this information, be absolutely sure that it does not check the X-HTTP-FORWARDED-FOR header! Otherwise it's trivial to fake the IP address. For example, if you're using Zend Framework's Zend_Controller_Request_Http::getClientIp method, be absolutely sure that you pass false as the parameter! Otherwise someone just needs to send an HTTP header: X-Http-Forwarded-For: 127.0.0.1 and they now appear to be local! This is one case where using a framework without understanding how it works in the backend can really be bad...
Edit: Relevant
I wrote a blog post recently about how I stumbled across a vulnerability in StackOverflow's application. It's very relevant here, since it exploits a very similar mechanism to what this question is looking for (although the circumstances around it are somewhat narrow):
How I Hacked StackOverflow
The remote address is not something added out of courtesy, it's used in the IP protocol to route packages, so if you send a package with a fake address, you will not receive a response, and since you're talking about a HTTP request, which is delivered over a TCP connection, which takes several IP packets (and the matching responses) to set up:
No, that's impossible (except of course by actually sending the request from the same host via the loopback interface).
Apache populates $_SERVER['REMOTE_ADDR'] from a TCP socket that it uses to communicate with your browser. It is IMPOSSIBLE to influence this variable over the open internet because of the three-way-handshake. If the client and the server is on a broadcast network, like wifi, then you can sniff the wire and complete the handshake.
If you browse via a proxy, $_SERVER['REMOTE_ADDR'] may be set to the proxy's IP address rather than the end user's.
There are other headers which you can use instead in this case: This page gives a function which checks all the possibilities and provides the address most likely to be the end user's:
http://roshanbh.com.np/2007/12/getting-real-ip-address-in-php.html
However if the user is proxying using a badly configured proxy, or a malicious one, or one designed to anonymise the end user, then you won't be able to guarantee any of the headers other than REMOTE_ADDR (which would only lead you as far as the proxy).
If your end user is browsing via HTTPS, then REMOTE_ADDR will always be his IP address; you can't use proxy forwarding via HTTPS. Therefore, the one way to be absolutely sure of his address is to get him to open your site in HTTPS.
You can overwrite any item in the $_SERVER array, including the one you mention, in your server; of course, not in someone else's.
However, it won't change your computer's IP address.
REMOTE_ADDR
The IP address from which the user is viewing the current page.
You can request script using proxy, etc. to change IP address but you cannot set there any text you want.
That is a variable set by apache or whatever server you're using. You cannot spoof it.
You may run $_SERVER['REMOTE_ADDR']='127.0.0.1'; at the beginning of the scripts, but i doubt thats what you're trying to do

Are there any good beginner tutorials for using SSL with your web app?

I have a program written in PHP, and I'd like to make sure that login pages etc. are all served over SSL. Is there any good start to finish tutorial for doing so?
Also, does this affect my code in any way, or is it just a matter of getting a SSL cert, and setting up a server correctly?
If your html code contains absolute urls ("http://my-domain.com/...") to:
stylesheets
images
javascripts
Browsers will complain "This page contains both secure and non-secure items".
Use relative urls if you can, or link to "https://my-domain.com/..." urls.
Use free certificates
You don't have to spend money to get valid SSL certificate:
Let’s Encrypt
Let’s Encrypt is a free, automated, and open Certificate Authority.
It depends on the hosting how easy this is to setup, it could be just a checkbox.
The process is well documented on https://letsencrypt.org/
StartSSL
For more traditional certificates, you can get a "StartSSL™ Free" from StartCom.
The site also contains information on installing the certificate.
Firstly a word of warning. if you are considering using SSL its because you have something to protect. Therefore take the time to understand what you are doing every step of the way. Security (not just SSL) is a minefield even for the experienced.
I don't know of any tutorials, but there are plenty of gotcha's you have to be aware of.
Rolling your own ssl cert for testing purposes is free, but you will need to install it on your server.
Most of the time your code does not need to be any different for an ssl page or non ssl as the code itself is ssl agnostic, but as Bob says you must be careful of things like images.
Also redirects can cause popups to warn the user of redirections.
To test if the code is being called from a browser using SSL check for the SSL flag $_SERVER['HTTPS'] this should be a non empty value if SSL is being used.
$ssl_is_on = $_SERVER['HTTPS'] ? true:false;
Personally I prefer to keep my SSL code in a separate folder altogether and use apache to direct all SSL connections to that folder. that way I can be confident a script that should be protected by SSL is not called from a non SSL connection.
If you are logging them in under SSL and then redirecting them to non SSL pages you may need to account for domains and cookies
for example I always use a different domain for ssl normally https;//secure.blah.com and then redirect them to the non secure domain http;//www.blah.com so your cookie domain will need to be blah.com the default is the full domain name which means cookies for secure.blah.com won't be sent to www.blah.com and therefore your users will never be logged in.
Don't use this technique if you use a shared domain name otherwise you could have a problem with cookie information being leaked.
DC
It should not affect your code. Add modrewrite rules to your Apache config. Yes, just obtain an SSL cert (you'll need to pay to have it signed by Verisign or another certificate authority).

Setting up a web interface to http proxies?

I want a way to allow users to go through my http proxy server (Squid, Privoxy, etc.) without having to type the IP/port in web browser settings. I was hoping I could use a simple web interface.
I'm envisioning this:
User goes to a website on my server (http://proxy.com) and types a URL
into the form.
The user's browser URL looks like (http://proxy.com/url=URL)
All connections to any future links are passed through my http proxy
running on a different port.
And I do NOT want to use existing php/cgi web proxy scripts.
My only reasoning for that is I feel it would be much more efficient re-routing connections through a native proxy server than having many php instances proxy the connections. Please tell me if you think this would not actually be the case.
Are there any simple ways of doing this? Thanks!
You may want to setup a transparent proxy. That way the clients do not know they are using a proxy so they do not have to set the proxy IP in their browsers. This obviously does not work for https. Some information for squid here: http://www.cyberciti.biz/tips/linux-setup-transparent-proxy-squid-howto.html

Categories