Connection to secure FTP Server from PHP - php

This question is in line with this question, I am trying to connect to secure FTP Server and it is not able to connect, wierd part is that I am able to do ssh and connect to the server but when I try to do it from php code using few different approaches but it is not working
Approaches:
FTP Wrappers
ftp_connect & ftp_login
ftp_ssl_connect
ssh2_sftp
ssh2-scp-send & ssh2-scp-receive -- Have not tried this approach yet but recommended in comments portion and so would work on this and will post updates later.
Code for Approach 1:
$ftp_server = "ftp://username:password#192.168.1.1:21/{$log_file_name}";
$opts = array('ftp' => array('overwrite' => TRUE));
$context = stream_context_create($opts);
$put_file = file_put_contents($ftp_server, $response, LOCK_EX,$context);
Here also am not able to connect to secure FTP Server, any suggestions as to why it is not able to connect ?
Code for Approach 2:
ftp_server = 'www.server.com';
$conn_id = ftp_connect($ftp_server) or die ("Cannot connect to host");
//Program dies out here and give error message "Cannot connect to host",
//but why ftp_login does not work here, Any Suggestions ?
$ftp_user_name = "login";
$ftp_user_pass = "password";
// login with username and password
$login_result = ftp_login($conn_id, $ftp_user_name, $ftp_user_pass);
// check connection and login result
if ((!$conn_id) || (!$login_result))
{ echo "FTP connection has encountered an error!";
echo "Attempted to connect to $ftp_server for user $ftp_user_name....";
//exit;
} else
{
echo "Connected to $ftp_server, for user $ftp_user_name".".....";
}
Code for Approach 3:
Here am using same code as approach 1 but instead of ftp_connect, am using ftp_ssl_connect
Code for Approach 4:
$connection = ssh2_connect('www.server.com', 22);
ssh2_auth_password($connection, 'login', 'password');
$sftp = ssh2_sftp($connection);
//exit();
$stream = fopen("ssh2.sftp://$sftp/path/to/file", 'r');
Can anyone advise why am I not able to connect to secure FTP Server using above approaches but still am able to do so using ssh ?
Are there any other approaches to connect to secure FTP Server using php ?
UPDATE:
Q1. I tried again using ftp_connect but it just died out and why does it dies out, what are the scenarios in which ftp_connect dies out ?
Q2. Do we have only this approaches to connect to the server or are there any other which we can implement ?
Q3. Is this php language related that it does not support secure FTP Connection ? OR there is any other way of doing this using php, if yes than do provide different approaches as it would be very helpful.
UPDATE 1:
I was trying to google more on the issue and it seems that if ftp_connect does not work than firewall could be one of the reason for it. I am not totally sure if that is the case but I am researching more on it and post an update in here if I find anything useful.
Possible Solution :
Problem
If I remove the "or die" then you get the error:
When running from a webpage:
Warning: ftp_login() expects parameter 1 to be resource, boolean given in /var/www/ftp_test.php on line 28
var_dump($conn_id); returns bool(false).
From command line /usr/bin/php /var/www/ftp_test.php
var_dump($conn_id); returns resource(4) of type (FTP Buffer).
Script completes.
Solution 1
This could be one solution :
Try to turn off selinux and here is the way or Search : How to disable selinux for turning it off temporarily or permanently.
Solution 2
If you don't want to turn off selinux completely, you might get what you need by just setting the httpd_can_network_connect using the setsebool command.
Verify that it was previously set to "off":
getsebool httpd_can_network_connect
Set it to "on":
setsebool httpd_can_network_connect=1
Turn selinux back on:
setenforce 1
Check to be sure php ftp_connect still works when running under httpd.
Set the policy (-P) to "on" so it persists over a reboot:
setsebool -P httpd_can_network_connect=1
Solution 3
There could also be issue with company firewall. Make sure it is configured properly and has access rights set properly.
Solution 4
Another approach is to use cURL : libcurl as it can be used to connect and communicate to many different types of servers with many different types of protocols
Solution 5
There is open source project called PHP Secure Communication Library (phpspeclib) which can be also used to establish secure connection to FTP Server.

Many cheap webhoster will not give you ssh (hence no ftp via ssh aka
sftp) but only ssl-secured ftp aka ftps (see here). You might
have that problem. As others suggested, use filezilla or
another ftp client to test your credits and chosen security method
beforehand.
ftp_ssl_connect() at least under windows will be a long journey,
since you have to compile your own php binaries, see here.
As this php contributor rightfully points out, no secure
connection is secure, as long as you don't know, who you are talking
too, aka „peer certification“ through valid certificates.
phpseclib is probably your best bet. But I haven't figure out, how to
ensure, it uses peer verification (guessing, the truth is in
openssl.conf ...)
So even at the time of writing, I wonder more than ever, if
peer-validated ftps (ftp with ssl/tls authentification) is possible... also see my question here.

As for ´ftp via ssh´ alias ´sftp´: No direct advice, but note, that many cheap 'non-dedicated server' webhosts do not support it (which is bad). Company firewalls might block the relevant ports.
As for 'ftp using ssl/tls' alias 'ftps': Your answer is here. Don't waste time on ftp_ssl_connect() :-)
(Yes, it's poorly documented on the php site, to say the least)

This page has what you seek (I think)
http://kevin.vanzonneveld.net/techblog/article/make_ssh_connections_with_php/
and here are the manual pages
http://php.net/manual/en/book.ssh2.php

I, too, encountered quite a lot of issues when dealing with encrypted connections.
First thing is to check the protocol you are looking to use. Secure FTP is most commonly refearing to FTP over SHH but can also mean SCP, SFTP or FTPS.
One way to figure out is to check connecting using a client like filezilla.
If the protocol is handled via a PHP module, the best approach is indeed, to use it. In this case, you need to make sure that, in addition to the protocol-related one, the OPENSSL module is installed for php.
There are some cases where the module support still won't work. In this case, using the libcurl module is one option. This is the case for instance when you need to use a client certificate.
Unfortunately, here again, you may encounter some problems due to the partial support of libcurl in the php module. One scenario I experimented is when the server certificate is judged invalid by the module.
The last solution I usually use is to run the curl binary from an exec statement, for the later case using the "-k" switch.

I tried the phpseclib library and it works in Windows and Linux.
If you are using composer, just add in your require section :
"phpseclib/phpseclib": "0.3.*#dev"
And then, you can do this : http://phpseclib.sourceforge.net/sftp/examples.html#put

Related

ftp_nlist(): data_accept: SSL/TLS handshake failed

Once upon a time, there was a normalish error in PHP land:
Warning: ftp_nlist(): data_accept: SSL/TLS handshake failed in [path] on line 29
But here's the catch, "line 29" is not the connection or login, note how it referenced the ftp_nlist() function:
$ftp = ftp_ssl_connect($cred['host'], $cred['port'], 180);
if (!ftp_login($ftp, $cred['user'], $cred['pass'])) {die("Login Failed");}
ftp_pasv($ftp, true);
$files = ftp_nlist($ftp, '');
OpenSSL is compiled and enabled in phpinfo() as suggested here:
ftp_login() : SSL/TLS handshake failed
Other posts I've seen all seem to reference error in the ftp_ssl_connect() or ftp_login() commands which work for me. What can I check when ftp_login() returns true?
Or... are there any logs to get more details on what is wrong?
I'm using php 5.3.29. The code does work properly on my desktop (php 7), but I'm hoping I don't have to upgrade the server to 7 for this to work
12-28-2017 update:
Upgrading to 5.6 resolved, so looks like Martin is on point.
Although this question is quite old, but in case someone else hits this problem:
If your ftp_ssl_connect and ftp_login works fine but functions like ftp_nlist, ftp_put, ftp_fput don't works the problem might be that your FTP server is using port 21 for Connection but different port ranges for data transfer, that explains why you can connect and login but you can't upload or download data, and you need to allow the Out-going connections to those port range in your firewall
The ftp_nlist opens a data connection. That connection needs TLS/SSL handshake too.
As the control connection handshake succeeded, the problem indeed cannot be with an absent TLS/SSL support in PHP. Neither the problem can be with anything like the server and PHP not being able to find a cipher to agree on.
When TLS/SSL handshake on data connection fails after handshake on control connection succeeded, it's quite usually because the client (PHP) did not reuse TLS/SSL session from control connection on the data connection (see Why is session reuse useful in FTPS?). Some servers do require that. PHP supports the reuse only since 5.6.26. See PHP Bug 70195. So make sure you use that version of PHP at least.

How to perform a LDAP SASL bind to Active Directory using GSS-API mech in PHP from Windows?

I have an Active Directory server and a Windows WAMP server hosting PHP web applications that need to be able to authenticate to Active Directory using Kerberos.
I was able to easily connect and bind to the Active Directory host using some sample PHP code, but I'm not sure how to do so with Kerberos. I have see many forums and blogs detailing how to do this on *NIX machines, but that doesn't help me with my situation.
I did use Wireshark and Fiddler to confirm that there is no Kerberos or NTLM negotiating happening.
Sample code I used to connect and bind to LDAP:
<?php
$ldaphost = "example.domain.com";
$ldapport = 389;
$ldapuser = "user";
$ldappass = "password";
$ldapconn = ldap_connect( $ldaphost, $ldapport )
or die( "Unable to connect to the LDAP server {$ldaphost}" );
if ($ldapconn)
{
$ldapbind = ldap_bind($ldapconn, $ldapuser, $ldappass);
if ($ldapbind)
{
echo "LDAP connection successful";
}
else
{
echo "LDAP connction failed";
}
}
?>
Any help will be greatly appreciated, thanks!
Update: I've been wrestling with this all day and I think I need to use ldap_sasl_bind(), possibly using GSSAPI as the mechanism... No matter what parameters I put in to ldap_sasl_bind(), I get the following error: 'Unable to bind to server: Unknown authentication method'
I'm not sure how to implement GSSAPI, but some examples I've seen show using ldap_start_tls(), but I keep getting a 'Unable to start TLS: Server is unavailable' error.
I don't know if anyone knows anything about ldap_sasl_bind() (which is undocumented by PHP) or ldap_start_tls, but if this is the way I should be going, please point me in the right direction.
I cannot help with the Kerberos issue yet, as I am still struggling with it myself. However, I can point you in the right direction for TLS. TLS will at least prevent your credentials from being transmitted over the network in clear text. TLS requires proper configuration of OpenLDAP. At the very least, you can configure your client to not request or check any server certificates. You do this by adding the following line to the top of your ldap.conf configuration file.
TLS_REQCERT never
Your ldap.conf file should be located in C:\ or C:\openldap\sysconf, depending on your version of PHP and OpenLDAP. The file most likely does not yet exist in your setup. You may also be able to set the configuration via an environment variable as well putenv(TLS_REQCERT=never);, but I have not tried that myself, and there appear to be mixed results reported by others.
What you need to do: Make sure that the LDAP interface in PHP is compiled against SASL, supports GSS-API mech and either uses keytabs or the Windows-own SSPI interface. Good luck.
I solved this problem on windows by creating executable based on c++ ldap_bind_s. I use this executable as a command line with the parameters: host, username,password. This is the only way I got it work for GSSAPI.
WINLDAPAPI ULONG LDAPAPI ldap_bind_s(
LDAP *ld,
const PSTR dn,
const PCHAR cred,
ULONG method
);
I used LDAP_AUTH_NEGOTIATE.

"Connection refused" error on socket_connect in php

I am trying to convert some code from perl to php.
Perl code looks like below:
my $handle = Connect($port, $host);
and I am trying to use socket to do the same thing in php.
I have tried socket_create and socket_connect,
socket_create and socket_bind, and fsocketopen.
As a result, I'm stuck with error messages saying "Connection refused" or "permission denied":
socket_connect() [function.socket-connect]: unable to connect [111]: Connection refused in
I am not sure if this is the problem I need to solve, or the problem of permission because the code in perl works fine (I did not write that code).
my php code looks like below:
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if(!$socket){
die('Error: socket_create()');
}
if(!socket_connect($socket,$host,$port)) {
die('Error: socket_connect()');
}
I'm not the one who manages the server, so I will need to ask someone else for the access if it is a permission issue. What should I ask for specifically?
Or should I use some other function to connect to the server? I am new to perl, so I am not sure if socket_connect is the equivalent function to use or not.
Thanks.
If your perl code is able to establish the connection, no additional permissions should be needed to do the same in php. Connection refused means the remote host doesn't let you in (you probably connect to wrong address/port). Permission denied is more surprising, a lot of people have this kind of problem while running httpd scripts with SELinux enabled. If you're one of them, refer to the SELinux manpage:
SELinux policy can be setup such that httpd scripts are not allowed to connect out to the network. This would prevent a hacker from breaking into you httpd server and attacking other machines. If you need scripts to be able to connect you can set the httpd_can_network_connect boolean on:
setsebool -P httpd_can_network_connect 1
I have a few concers to your examples though. Connect from your Perl snippet doesn't seem to be the standard socket connect; I don't know which module it belongs to, but are you sure there is no magic behind the call? As socket_connect takes address in dotted-quad notation (for IPv4), make sure you're not passing a hostname (you would need to make a DNS lookup first). At the very end check if it's really a TCP socket you need, not UDP.

How to Send File over secure FTP SSL Protocol

I appreciate any help that can be offered on the subject. At the end of an online enrollment, I am taking customer data (several fields), putting them in a CSV file and trying to submit to another client over SSL protocol but have no idea how this is done. I am also storing the information on a local database and am hoping the process is somewhat similar.
I have already been sent links to view the SSH2 instructions from php.net SSN2
but to be honest this is like reading Chinese to me. I do not understand the instructions and am not looking to install any extensions, modify the PHP.ini file or anything of the sort (especially since we do not own the server the information is being sent through).
Is there a simple, secure way of transmitting this file to the SSL protocol provided to us?
Thanks!
Perhaps you could use ftp_ssl_connect for that matter, which is used to open a secure SSL-FTP connection, and to upload a file is just a straight forward process, just create the connection to the server, and put the file up there. A basic example could be:
//Create your connection
$ftp_conn = ftp_ssl_connect( $host, $you_can_provide_a_port );
//Login
$login_result = ftp_login($ftp_conn, $user, $pass);
if( $login_result )
{
//Set passive mode
ftp_pasv( $ftp_conn, true );
// Transfer file
$transfer_result = ftp_put( $ftp_conn, $dest_file_path, $source_file_path, FTP_BINARY );
//Verify if transfer was successfully made
if( $transfer_result)
{
echo "Success";
}
else
{
echo "An error occured";
}
}
For reference purposes http://www.php.net/manual/en/function.ftp-ssl-connect.php
The only way I've managed to do ftp over SSL using php was to use php's exec() function to execute a curl command. PHP's curl library would not work because at the time, the skip-pasv-ip option did not exist and it was something that was absolutely required. Something like:
curl --user <username:password> --disable-epsv --ftp-pasv --ftp-skip-pasv-ip --ftp-ssl --sslv2 --cert <path/to/certificate> -T <path/to/uploadfile> <hostname>
You may need to modify the curl options to suit your needs.

How do you proxy though a server using ssh (socks…) using php’s CURL?

I want to use ssh, something like this:
ssh -D 9999 username#ip-address-of-ssh-server
But within php CURL, but I don't really see how this could be done?
I noticed “CURLPROXY_SOCKS5” as a type in the php site, but guess that wouldn’t work since it isn’t really socks, it’s ssh…
I’m currently using this code:
curl_setopt($ch, CURLOPT_PROXY, ‘ip:port');
But I'm using a free proxy and it’s rather slow and unreliable, I'm also sending sensitive information over this proxy. This is why I want to proxy it over a save server I trust, but I only have ssh setup on it and it’s unable to host a proper proxy.
You can use both libssh2 and curl from within a PHP script.
First you need to get the ssh2 library from the PECL site. Alternatively, the PEAR package has SSH2 support too.
After installing you can then read the ssh2 documentation on setting up a tunnel.
In your script you can then set up the tunnel.
After the tunnel is set up in the script you can specify the CURL proxy.
Perform your CURL operation.
Release the tunnel resource and close the connection in your script.
I'm not a PHP expert, but here's a rough example:
<?php
$connection = ssh2_connect(ip-address-of-ssh-server, 22);
ssh2_auth_pubkey_file($connection, 'username', 'id_dsa.pub', 'id_dsa');
$tunnel = ssh2_tunnel($connection, '127.0.0.1', 9999);
curl_setopt($ch, CURLOPT_PROXY, ‘127.0.0.1:9999');
// perform curl operations
// The connection and tunnel will die at the and of the session.
?>
The simplest option
Another option to consider is using sftp (ftp over ssh) instead of CURL... this is probably the recommended way to copy a file from one server to another securely in PHP...
Even simpler example:
<?php
$connection = ssh2_connect(ip-address-of-ssh-server, 22);
ssh2_auth_password($connection, 'username', 'password');
ssh2_scp_send($connection, '/local/filename', '/remote/filename', 0644);
?>
according to manpage the -D does create a socks proxy.
-D [bind_address:]port
Specifies a local ``dynamic'' application-level port forwarding.
This works by allocating a socket to listen to port on the local
side, optionally bound to the specified bind_address. Whenever a
connection is made to this port, the connection is forwarded over
the secure channel, and the application protocol is then used to
determine where to connect to from the remote machine. Currently
the SOCKS4 and SOCKS5 protocols are supported, and ssh will act
as a SOCKS server. Only root can forward privileged ports. Dy-
namic port forwardings can also be specified in the configuration
file.
You could use ssh2 module and ssh2_tunnel function to create ssh tunnel throu remote server.
Examples available: http://www.php.net/manual/en/function.ssh2-tunnel.php
See my comment on Qwerty's proposed solution. I think you are looking in the wrong direction to try to solve this question. Instead, you should just use cURL and create a personal certificate for yourself. You say you want to use SSH for safety, but why not a certificate instead?
This site will let you easily create one
http://www.cacert.org/
Since it's just for you, you can add an exception to your browsers so they won't complain of a bad certificate. No need for ssh!
To open the SSH tunnel only for the duration of your script, you probably would need to use PHP forks. In one process, open the SSH tunnel (-D - you need to do some work to make sure you're not colliding on ports here), and in the other process, use CURL with socks proxy config. When your transfer is done, signal the ssh fork to terminate so the connection gets torn down.
Keep in mind that while the tunnel is open, other users on the same machine can also proxy on that port if they wanted to. With that in mind, it might be a better idea to use the -L 1234:remotehost:80 flag, and just get the URL http://localhost:1234/some/uri
If things go wrong with this, you may find orphaned SSH tunnels on your server though, so I would call this somewhat fragile.

Categories