How to Send File over secure FTP SSL Protocol - php

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.

Related

Why can I obtain file size and the time stamp with FTP but not be able to retrieve the actual file?

I've been working on this for about 20 hours now and I need some major help. I'm able to get the file size and the timestamp on the file but I am unable to actually obtain the data.
The server I'm trying to get the data from requires FTP over explicit TLS
I'm receiving the same error(s) with both FTP_BINARY and FTP_ASCII in the ftp_fget()
The server the file is coming from is UNIX
If I refresh the page every few hours the errors I get from PHP are different with no change in code
Error 1: 'ftp_fget(): Transfer mode set to BINARY if ftp_get is binary
or it's 'ftp_fget(): Transfer mode set to ASCII' if ftp_get is ascii
Error 2: 'ftp_fget(): Entering Passive Mode(12.345.678.90.12.34)'
On the above errors I read that PASV mode being FALSE is what triggers Error 1, so I think the switching between the errors is for pasv mode working or not working. Not positive though.
<?php
$server = "12.345.678.90";
$local_file = 'inv3.txt';
$file = 'inventory-alp.txt';
$con = ftp_ssl_connect($server,21) or die("Could not connect to $server");
ftp_login($con,"xxxxxx","xxxxxx") or die("Could not login");
ftp_pasv($con,true);
$fsize = ftp_size($con, $file); // works
if ($fsize != -1)
{
echo "</br>$file is $fsize bytes.</br></br>";
}
else
{
echo "</br>Error getting file size.</br></br>";
}
$lastchanged = ftp_mdtm($con, $file); //works
if ($lastchanged != -1)
{
echo date("F d Y H:i:s.",$lastchanged)."</br></br>";
}
else
{
echo "Could not get last modified</br></br>";
}
if (ftp_get($con,$local_file,$file,FTP_ASCII)) //fails
{
echo "successfully written to $local_file";
}
else
{
echo "There was a problem while downloading $file to $local_file";
}
$var = error_get_last();
echo '<pre>';
var_dump($var);
echo '</pre>';
ftp_close($con);
?>
EDIT 1: Solution: I ended up not being able to access what I needed to change the firewall settings and such in php. While this is not the true answer, I did make it work and it is relatively easy.I ended up running across WINSCP, having the ability to connect to the server in a filezilla type layout and then save the session url was nice. All i did was access the saved session in the .exe and was able to set up my connection in half an hour.
What Martin indicated is very true, the SIZE and MDTM commands run synchronized over the main FTP Command Connection only. The transferring of data files, and usually the directory listing also (unless MLST/MSLD is used) requires a separate connection, the Data Connection, which is negotiated by the client and server over the Control Connection using a series of commands, most notably PORT and PASV.
Without going into a ton of detail (There's a link to our white paper later), when the Client & Server negotiate the terms of the Data Connection, one of the end points will tell the other endpoint the specific IP address and Port number for the connection. One endpoint will listen and wait for a connection from the other endpoint. This works great unless there is a firewall in front of the endpoint that is waiting for the inbound connection. If the client/server session is running in Active mode, the Server will actively connect back to the client on the IP/Port which was received by the server from the client in the form of the PORT command. In Passive mode, the Server will passively wait for the client to connect on the IP/Port which was sent by the server to the client in the response to the PASV command sent by the client to the server.
Again, firewalls tend to block FTP data connections, unless the firewall does active FTP NAT'ing or unless Port Forwarding has been set up on the Firewall and a set of passive-ports has been opened and routed to the endpoint specifically.
So check the firewall settings on the client if you want to use Active/Port mode; check the firewall settings on the server if you want to use Passive/PASV mode.
Here's a link to our white paper which outlines the basics of FTP/PASV/PORT, hopefully it'll help you with your issue.
http://www.webdrive.com/wp-content/uploads/FTP_Explained1.pdf
Best of Luck!
Michael
With the FTP protocol, it's perfectly possible that you are able to obtain the file size and the modification timestamp (using SIZE and MDTM commands respectively), but not the file itself.
The SIZE and MDTM commands use the FTP control connection only.
While a file transfer (or a directory listing) requires a separate data connection. And it's likely that there's something that prevents the data connection from being opened.
See (my) article on the FTP connection modes for more details and typical issues with data connections.
Typically a culprit would be a firewall on your webserver. If you have an SSH/terminal access to the webserver, are you able to connect from it to the FTP server?
Another possibility is a misconfigured FTP server. Is the IP address in "Error 2" routable from your web server? (=Is it the real IP address you connect to?)
It is unlikely this is related to an ASCII/BINARY mode. The messages you are getting (Transfer mode set to ...) are status messages, not error messages. They are not related to your problem. It's indeed strange that you got no other message/error.
You can try to use the active mode, instead of the passive.
ftp_pasv($con, false);
But usually the active mode is more problematic.

ssh or cURL to send data to remote server

I'm creating a app to sync my local mysql database to a remote mysql database, so I'm generating a dump file, sending it via the sFTP, then executing it on the server.
However, I am aware that there are other available methods like cURL. I like to send data to the remote server and execute it on the sever when it is accepted (TRUE), but I don't know much about security issues associated with using cURL in this regard. Can anyone advise on the cURL solution, else suggest any alternative methods?
Firstly, instead of generating the dump file, you should read the data from the file using file_get_contents(), fread() etc.
Store the result of this in a variable, then send that raw data over the pipeline (via cURL, if you wish), and have the code on the server-side generate the dump file instead.
Using cURL, you can specify a private certificate file for authentication - so the security of this is the same as using a certificate over ssh - it's not something you need to be worried about.
You can set the pem file with the following cURL option examples:
curl_setopt($ch, CURLOPT_SSLCERT, $pemfile);
curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');
curl_setopt($ch, CURLOPT_SSLKEY, $keyfile);
There are tutorials for the above all over the internet. Use private key authentication and your security issues are sorted. Just make sure you don't set CURLOPT_SSL_VERIFYPEER to false (you don't want any MiTM (man in the middle) attacks now, do you).
I use Curl for doing this.
I have an export script which generates json or xml (depends on what mood i'm in more than anything else) I then post this file to the remote server and the remote server uses ignore_user_abort so that processing can continue even if the parent internal system script times out / completes whatever.
Works like a charm syncing changes to a 2.6gb table between local web server and remote web server.
I use phpseclib, a pure PHP SFTP implementation, to do stuff like this. eg.
<?php
include('Net/SFTP.php');
$sftp = new Net_SFTP('www.domain.tld');
if (!$sftp->login('username', 'password')) {
exit('Login Failed');
}
$sftp->put('filename.remote', 'filename.local', NET_SFTP_LOCAL_FILE);
?>
It has a number of advantages over libssh2, including speed and portability:
http://phpseclib.sourceforge.net/ssh/compare.html
This is a basic solution using ssh2 / libssh.
This code assumes that you already have a method of creating your database dump, and will just be reading it on the current server, with the aim of loading it on the remote server.
It connects to the remote host via SSH, writes your sql_dump to a file on the remote server, then executes a command to load it into the database.
I wouldn't recommend storing the username/password for connecting, this is simply a quick way to test the code.
You would be better using ssh2_auth_pubkey_file to authenticate:
http://php.net/manual/en/function.ssh2-auth-pubkey-file.php
// remote host authentication details. hostname/ip, user, pass
$host = 'REMOTE_HOST';
$user = 'REMOTE_USER';
$pass = 'REMOTE_PASS';
// check if we have ssh2 installed first
if (function_exists("ssh2_connect")) {
//connect to remote host
$connection = ssh2_connect($host, 22);
// if connection successful, proceed
if ($connection) {
// authenticate on remote connection
$auth = ssh2_auth_password($connection, $user, $pass);
// if we have authenticated, proceed with remote commands
if ($auth) {
// load our dump file to a string
$sql_str = file_get_contents('dump_file.sql');
// bash command to cat our dump string to a file
$write_remote_file_command = "cat <<'EOF' > /home/tmp_file.sql \n$sql_str \nEOF";
// call our execute ssh function to execute above command
executeSSHCommand($connection, $write_remote_file_command);
// command to load our temp dump file into the database
// - you may need to add additional commands to drop the existing db, etc
$remote_load_command = "mysql -Uroot -p -h localhost database_name < /home/tmp_file.sql";
// remotely execute load commands
executeSSHCommand($connection, $remote_load_command);
}
}
}
// basic function to execute remote shell commands via our authenticated $connection
function executeSSHCommand($connection, $command) {
$output = array();
$ssh_data = "";
$stream = ssh2_exec($connection, $command);
if ($stream) {
stream_set_blocking($stream, true);
while ($buffer = fread($stream, 65536)) {
$ssh_data .= $buffer;
}
fclose($stream);
$output = explode(PHP_EOL, $ssh_data);
}
return $output;
}

PHP Script Won't Upload to FTP Server -

Having spent hours on this, I am out of luck. This script worked perfectly until yesterday. The script generates XML and dumps it as a file (5kb) to a remote FTP server. The script has not changed, nor has our host changed anything. The FTP server company has changed something (they said IP change yesterday) (but claims nothing apart from this). This IP resulted in a different ftp_server which has worked fine.
When I attempt to run the script, I get the following error regardless of whether "ftp_pasv($conn_id, true);" is there or not / disabled:
Warning: ftp_fput() [function.ftp-fput]: Opening ASCII mode data connection in ...
Then it gives the line which contains "FTP_ASCII" below.
When I have the ft_pasv section there only (as per original script), an additional error of the following still appears with the following:
Warning: ftp_fput() [function.ftp-fput]: data_accept: SSL/TLS handshake failed in ...
This is for the same line as the above error.
They were originally on a self-signed SSL. Now, due to my issue, they are now on a 'correct' SSL issued by a well known company. No errors display on Filezilla upon connecting.
Importantly, I can upload via Filezilla with no issues, with or without passive mode
Code above the below code in the script is correct for generating the file as it appears on the script page, once loaded. It just won't dump the file on the server. Here is the connecting to the server bit:
//Connect to the FTP server
$ftp_server = 'import.ftpserverdomain.com';
$ftp_user_name = 'CORRECT-USERNAME';
$ftp_user_pass = 'CORRECT-PASSWORD';
// set up basic ssl connection
$conn_id = ftp_ssl_connect($ftp_server) or die("CONNECTION ERROR");
// login with username and password
$login_result = ftp_login($conn_id, $ftp_user_name, $ftp_user_pass) or die("LOGIN ERROR");
$directory = ftp_pwd($conn_id); // /
ftp_pasv($conn_id, true);
$fp = fopen($filename, 'w');
fputs($fp,$file_contents);
fclose($fp);
$fp = fopen($filename, 'r');
$path_with_file = $directory.$filename;
if (ftp_fput($conn_id, $path_with_file, $fp, FTP_ASCII)) {
echo "Successfully Uploaded $File\n";
} else {
echo "There was a problem while uploading $File\n";
}
fclose($fp);
unlink($filename);
ftp_close($conn_id);
Any help is much appreciated. Sorry if I lacked any information. I'll be happy to provide any.
It sounds to me like PHP can't find your CA Certs, if you are running this on a linux box, this is something I have encountered before. Some searching should help but basically PHP's OpenSSL integration needs pointing at your cacerts directory so it can use these to validate the SSL connection it is attempting to make.
I fixed this issue. Hopefully this helps someone. The issue turned out to be server (HostGator). They do not allow FTP over TLS on a shared account.
Despite this working for a year, switching hosts resolved the issue.

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 to secure FTP Server from 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

Categories