i'm trying to use reCaptcha v2.0 with php, in the server verification i use this code:
if(isset($_POST['Direccion_Email']) AND ($_POST['enviar'])) {
if(isset($_POST['g-recaptcha-response'])){
$mensaje_error = "";
include 'config-formulario.php';
require_once __DIR__ . '/recaptcha-master/src/autoload.php';
$recaptcha = new \ReCaptcha\ReCaptcha($secret);
$resp = $recaptcha->verify($_POST['g-recaptcha-response'], $_SERVER['REMOTE_ADDR']);
if (!$resp->isSuccess()) {
$mensaje_error .= "Control Anti SPAM no es válido <br />";
$errors = $resp->getErrorCodes();
} else {
//DO SOMETHING;
}
But when i try to send a simple contact me form with name, email and comments, it's return this warnings:
Warning: file_get_contents(): SSL operation failed with code 1. OpenSSL Error messages: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed in /home/diego/www/systec/scripts/recaptcha-master/src/ReCaptcha/RequestMethod/Post.php on line 68
Warning: file_get_contents(): Failed to enable crypto in /home/diego/www/systec/scripts/recaptcha-master/src/ReCaptcha/RequestMethod/Post.php on line 68
Warning: file_get_contents(https://www.google.com/recaptcha/api/siteverify): failed to open stream: operation failed in /home/diego/www/systec/scripts/recaptcha-master/src/ReCaptcha/RequestMethod/Post.php on line 68
I'm testing this on localhost.
Any suggestions.
Thanks.
Change
$verify=file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret={$secret}&response={$response}");
To
$ch = curl_init("https://www.google.com/recaptcha/api/siteverify?secret={$secret}&response={$response}");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$verify = curl_exec($ch);
The answer from #jww works form me:
For step (1), see How do you sign Certificate Signing Request with your Certification Authority?. For (2), see How to create a self-signed certificate with openssl?. The latter also shows you how to create a signing request (as opposed to a self signed certificate). They are the same steps - the only thing that differs is the lack of the -x509 option for a signing request.
Related
I want to validate license in my plugin.
User on his website enters token (provided by me) and I want to validate this by contacting my server using curl.
For example,
Code in plugin:
function curl_url( $url ) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $url );
$cr = curl_exec($ch);
curl_close($ch);
return $cr;
}
$confirm = 'https://my-website.com/some_folder/some_file.php?token=' . $token;
$response = json_decode( curl_url( $confirm ) );
Code on my website in some_file.php:
if(isset($_GET['token'])){
validate();
}
function validate(){
$token= $_GET['token'];
//check if valid, provide response...
}
MY questions:
How good or bad approach is this, what do you advise to me?
What is some advanced user sees code in my plugin and then uses this url for some malicious attacks?
https://my-website.com/some_folder/some_file.php
Currently if I try to reach my server from another domain, I dont get
any errors and request works so I ma not sure why I need
CURLOPT_CAINFO. – Toniq
Compare the results between the two domains.
curl_getinfo is very useful.
CURLINFO_HEADER_OUT
echo curl_getinfo($ch,CURLINFO_HEADER_OUT);
Other useful curl info.
CURLINFO_SSL_VERIFYRESULT
CURLINFO_HTTPAUTH_AVAIL
CURLOPT_HTTPAUTH the HTTP authentication method(s) to use.
CURLINFO_SSL_ENGINES
CURLINFO_CERTINFO true to output SSL certification information to STDERR on secure transfers
CURLINFO_APPCONNECT_TIME
Options
CURLOPT_UNRESTRICTED_AUTH
CURLOPT_SSLVERSION Your best bet is to not set this and let it use the default.
CURLOPT_SSL_OPTIONS
CURLOPT_KEYPASSWD
CURLOPT_PINNEDPUBLICKEY
CURLOPT_SSH_PRIVATE_KEYFILE
CURLOPT_CAPATH A directory that holds multiple CA certificates
CURLOPT_CAINFO The name of a file holding one or more certificates to verify the peer with.
CURLOPT_SSL_VERIFYHOST 0 to not check the names. 1 should not be used. 2 to verify that a Common Name field
CURLOPT_SSL_VERIFYPEER false to stop cURL from verifying the peer's certificate.
CURLOPT_SSL_VERIFYSTATUS true to verify the certificate's status.
CURLOPT_CERTINFO true to output SSL certification information to STDERR on secure transfers.
CURLOPT_FRESH_CONNECT true to force the use of a new connection instead of a cached one.
CURLOPT_SSL_ENABLE_NPN
CURLOPT_SSL_ENABLE_ALPN
CURLOPT_SSL_FALSESTART true to enable TLS false start.
CURLOPT_SSH_AUTH_TYPES
CURLOPT_LOGIN_OPTIONS
CURLOPT_SSL_CIPHER_LIST
CURLOPT_SSLCERTPASSWD
CURLOPT_SSLKEY
CURLOPT_SSLENGINE
CURLOPT_SSLKEYPASSWD
CURLOPT_SSLKEYTYPE
CURLOPT_SSL_CIPHER_LIST
CURLOPT_SSH_PRIVATE_KEYFILE
CURLOPT_SSH_PUBLIC_KEYFILE
CURLOPT_USERNAME
CURLOPT_PASSWORD
CURLOPT_USERPWD [username]:[password]
CURLOPT_XOAUTH2_BEARER Specifies the OAuth 2.0 access token.
CURLOPT_VERBOSE
CURLOPT_STDERR A file handle to output errors to instead of STDERR.
$errno = curl_errno($ch)
$error_message = curl_strerror($errno);
You should be checking for errors.
CURLOPT_VERBOSE
CURLOPT_STDERR A file handle to output errors to instead of STDERR.
$errno = curl_errno($ch)
$error_message = curl_strerror($errno);
CURLError codes
CURLE_SSL_CONNECT_ERROR (35)
CURLE_SSL_ENGINE_NOTFOUND (53)
CURLE_SSL_ENGINE_SETFAILED (54)
CURLE_SSL_CERTPROBLEM (58)
CURLE_SSL_CIPHER (59)
CURLE_PEER_FAILED_VERIFICATION (60)
CURLE_SSL_ENGINE_INITFAILED (66)
CURLE_LOGIN_DENIED (67)
CURLE_SSL_CACERT_BADFILE (77)
CURLE_SSH (79)
CURLE_SSL_CRL_BADFILE (82)
CURLE_SSL_ISSUER_ERROR (83)
CURLE_SSL_PINNEDPUBKEYNOTMATCH (90)
CURLE_SSL_INVALIDCERTSTATUS (91)
CURLE_AUTH_ERROR (94)
CURLE_SSL_CLIENTCERT (98)
Can you provide this header example? – Toniq
Add header to curl:
$token = 'token';
$request = array();
$request[] = "X-Token: $token";
curl_setopt($ch, CURLOPT_HTTPHEADER, $request);
When received by the server:
Content-Length: 55098
Content-Type: application/x-www-form-urlencoded
Connection: close
X-Token: token
The code for server to read header:
foreach (getallheaders() as $key=> $value) {
$header[$key] = $value;
}
$token = $header['X-Token'];
It appears you may be in over your head. You should have known this considering what you are trying to do. This is the very easy part. You still need to deal with the SSL (CURLOPT_CAINFO).
You probably need to specify the SSL certificate or the path to the CA. From PHP manual's curl_setopt page
Alternate certificates to verify against can be specified with the
CURLOPT_CAINFO option or a certificate directory can be specified with
the CURLOPT_CAPATH option.
In the url script try this code to get the details of your request.
It should help you find the problem in your request.
I've been using it for years and it has helped so many times.
I copied this code a PHP script, here is the script.
You could use this link as your curl URL.
LINK to the code below
<?php
header('Content-Type: text/plain; charset=UTF-8');
$decode = false;
foreach (getallheaders() as $name => $value) {
if(strpos($value,'urlenc')){$decode = true;};
echo "$name: $value\n";
}
echo "\nBODY\n";
$body = file_get_contents('php://input');
//if($decode){$body = urldecode($body);}
echo $body;
echo "\n\n\$_SERVER['QUERY_STRING'])\n";
echo urldecode($_SERVER['QUERY_STRING']);
echo "\n\nargv\n";
foreach($_SERVER['argv']as $key=>$value){
echo "\n$key = " . urldecode($value) . "\n";
}
echo "\n\$_POST\n";
var_export($_POST);
echo "\n\$_GET\n";
var_export($_GET);
echo "\n\$_REQUEST\n";
var_export($_REQUEST);
echo "\n\$_FILES\n";
var_export($_FILES);
echo "\n\$_SERVER\n";
var_export($_SERVER);
exit;
When trying to add a reCaptcha on my contact form, i get this error :
Warning: file_get_contents(): php_network_getaddresses: getaddrinfo
failed: Name or service not known in *******/MyClass.php on line 79
$secret = "*********************";
$response = $_POST['g-recaptcha-response'];
$remoteip = $_SERVER['REMOTE_ADDR'];
$api_url = "https://www.google.com/recaptcha/api/siteverify?secret=" . $secret. "&response=" . $response. "&remoteip=" . $remoteip ;
$decode = json_decode(file_get_contents($api_url), true);
Line 79 is "$decode = json_decode(file_get_contents($api_url), true);"
I have checked my php.ini, allow_url_fopen = ON.
So .. can't figure out what is wrong. Any idea ?
I struggled with DNS settings for a while before discovering http just needed a restart to kick php:
service httpd restart
recaptcha works again now.
I've just noticed the new vulnerability discovered in Wordpress and I'm trying to fix it with the following code (but with any success
<?php
$url = 'https://mywebip/wp-login.php?action=lostpassword';
$data = 'user_login=admin&redirect_to=&wp-submit=Get+New+Password';
// use key 'http' even if you send the request to https://...
$options = array(
'http' => array(
'header' => "Host: mailserver\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: ". strlen($data) ."\r\n",
'method' => 'POST',
'content' => $data,
'ssl'=>array('verify_peer'=>true, 'capath'=>'/etc/ssl/certs')
)
);
$context = stream_context_create($options);
//$result = file_get_contents($url, false, $context);
$fp = stream_socket_client($url, $errno, $errstr, 30);
//stream_socket_enable_crypto($fp, true, STREAM_CRYPTO_METHOD_SSLv23_CLIENT);
$fp = fopen($url, 'r', false, $context);
if ($fp === FALSE) { /* Handle error */ }
var_dump($result);
?>
The error log I got is just like this:
PHP Warning: stream_socket_client(): unable to connect to https://mywebip/wp-login.php?action=lostpassword (Unable to find the socket transport "https" - did you forget to enable it when you configured PHP?) in /home/jorge/Escritorio/joomla.php on line 18
PHP Warning: fopen(): Peer certificate CN=`website` did not match expected CN=`mywebip' in /home/jorge/Escritorio/joomla.php on line 21
PHP Warning: fopen(): Failed to enable crypto in /home/jorge/Escritorio/joomla.php on line 21
PHP Warning: fopen(https://mywebip/wp-login.php?action=lostpassword): failed to open stream: operation failed in /home/jorge/Escritorio/joomla.php on line 21
Where mywebip represents the actual ip that hosts my website and website and mailserver the DNS directions of the services.
Thank you.
Via socket you do not specify a protocol.
http://php.net/stream_socket_client
First parameter:
remote_socket
Address to the socket to connect to.
Adress is only mywebip.
You should use CURL instead.
See http://php.net/manual/en/curl.examples.php
The other problem (with fopen(), which can handle streams with protocols!) is a malformed/wrong certificate issued by your webserver.
Use this service to debug problems with your webservers certificate:
https://www.ssllabs.com/ssltest/
I have trouble with establishing a SSL connection.
These warnings are displayed:
Warning: stream_socket_client() [function.stream-socket-client]: Unable to set local cert chain file `D:\path\cert.pem'; Check that your cafile/capath settings include details of your certificate and its issuer in D:\path\testSll.php on line 23
Warning: stream_socket_client() [function.stream-socket-client]: failed to create an SSL handle in D:\path\testSll.php on line 23
Warning: stream_socket_client() [function.stream-socket-client]: Failed to enable crypto in D:\path\testSll.php on line 23
Warning: stream_socket_client() [function.stream-socket-client]: unable to connect to ssl://host.tld:700 (Unknown error) in D:\path\testSll.php on line 23
So I read all the question about the "Unable to set local cert chain file", but all the answer I found didn't work for me.
Here is the code I use :
$host = 'host.tld';
$port = 700;
$cert = dirname(__FILE__).'\\cert.pem'; //
$passe_phrase = 'pass';
$opts = array(
'ssl'=>array(
'local_cert' => $cert,
'passphrase' => $passe_phrase,
'verify_peer' => false
)
);
$context = stream_context_create($opts);
$fp = stream_socket_client('ssl://'.$host.':'.$port, $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $context);
if ($fp) {
echo "OK";
} else {
echo "ERROR: $errno - $errstr<br />\n";
}
The certificate is the good one.
The script can access to the file cert.pem.
I cant find what I am missing here.
PHP version : 5.2.6
You should look at include details of your certificate and its issuer. In my case I accidentally deleted header of a file. When I return it back, the script is connecting successfully.
Before:
-----BEGIN CERTIFICATE-----
MIIFCBG+gAwIBAg...
After
Bag Attributes
friendlyName: ...
localKeyID: ...
subject=...
issuer=/C=US/... CN=Apple Worldwide Developer Relations Certification Authority
-----BEGIN CERTIFICATE-----
MIIFCBG+gAwIBAg...
I'm currently working on a tool to integrates link of different social networks:
Facebook: https://www.facebook.com/jonathan.parentlevesque
Google plus: https://plus.google.com/+JonathanParentL%C3%A9vesque
Instagram: https://instagram.com/mariloubiz/
Pinterest: https://www.pinterest.com/jonathan_parl/
RSS: https://regex101.com
Twitter: https://twitter.com/arcadefire
Vimeo: https://vimeo.com/ondemand/crashtest/135301838
Youtube: https://www.youtube.com/user/Darkjo666
I'm using very basic regex like this one:
/^https?:\/\/(?:[a-z]{2}|[w]{3})?\.pinterest.com\/[\S]{5,}$/i
on client and server side for minimal domain validation on each links.
Then, I'm using this function to validate that the page really exists (it's useless to integrate social network links that don't work after all):
public static function isUrlExists($url){
$exists = false;
if(!StringManager::stringStartWith($url, "http") and !StringManager::stringStartWith($url, "ftp")){
$url = "https://" . $url;
}
if (preg_match(RegularExpression::URL, $url)){
$headers = get_headers($url);
if ($headers !== false and !empty($headers)){
if (strpos($headers[0], '404') === false){
$exists = true;
}
}
}
return $exists;
}
Note: In this function I'm using Diego Perini's regex for validating the URL before sending the request:
const URL = "%^(?:(?:https?|ftp)://)(?:\S+(?::\S*)?#|\d{1,3}(?:\.\d{1,3}){3}|(?:(?:[a-z\d\x{00a1}-\x{ffff}]+-?)*[a-z\d\x{00a1}-\x{ffff}]+)(?:\.(?:[a-z\d\x{00a1}-\x{ffff}]+-?)*[a-z\d\x{00a1}-\x{ffff}]+)*(?:\.[a-z\x{00a1}-\x{ffff}]{2,6}))(?::\d+)?(?:[^\s]*)?$%iu"; //#copyright Diego Perini
All the tested links so far didn't generate any error, but testing Pinterest produce me this quite scary series of error messages:
get_headers(): SSL operation failed with code 1. OpenSSL Error messages: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
Array
(
[url] => https://www.pinterest.com/jonathan_parl/
[exists] =>
)
get_headers(): Failed to enable crypto
Array
(
[url] => https://www.pinterest.com/jonathan_parl/
[exists] =>
)
get_headers(https://www.pinterest.com/jonathan_parl/): failed to open stream: operation failed
Array
(
[url] => https://www.pinterest.com/jonathan_parl/
[exists] =>
)
Is anyone has an idea what I'm doing wrong here?
I mean, ain't Pinterest a popular social network with a valid certificate (I don't use it personally, I just created an account for testing)?
Thank you for your help,
Jonathan Parent-Lévesque from Montreal
I tried to create a self-signed certificate for my development environment (Xampp) as suggested by N.B. in his comment. That solution didn't worked for me.
His other solution was to use cUrl or guzzle instead get_headers(). Not only it worked, but, according to this developper's tests:
http://php.net/manual/fr/function.get-headers.php#104723
it is also way faster than get_headers().
For those interested, here's the code of my new function for those interested:
/**
* Send an HTTP request to a the $url and check the header posted back.
*
* #param $url String url to which we must send the request.
* #param $failCodeList Int array list of codes for which the page is considered invalid.
*
* #return Boolean
*/
public static function isUrlExists($url, array $failCodeList = array(404)){
$exists = false;
if(!StringManager::stringStartWith($url, "http") and !StringManager::stringStartWith($url, "ftp")){
$url = "https://" . $url;
}
if (preg_match(RegularExpression::URL, $url)){
$handle = curl_init($url);
curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($handle, CURLOPT_HEADER, true);
curl_setopt($handle, CURLOPT_NOBODY, true);
curl_setopt($handle, CURLOPT_USERAGENT, true);
$headers = curl_exec($handle);
curl_close($handle);
if (empty($failCodeList) or !is_array($failCodeList)){
$failCodeList = array(404);
}
if (!empty($headers)){
$exists = true;
$headers = explode(PHP_EOL, $headers);
foreach($failCodeList as $code){
if (is_numeric($code) and strpos($headers[0], strval($code)) !== false){
$exists = false;
break;
}
}
}
}
return $exists;
}
Let me explains the curl options:
CURLOPT_RETURNTRANSFER: return a string instead of displaying the calling page on the screen.
CURLOPT_SSL_VERIFYPEER: cUrl won't checkout the certificate
CURLOPT_HEADER: include the header in the string
CURLOPT_NOBODY: don't include the body in the string
CURLOPT_USERAGENT: some site needs that to function properly (by example : https://plus.google.com)
Additional note: I explode the header string and user headers[0] to be sure to only validate only the return code and message (example: 200, 404, 405, etc.)
Additional note 2: Sometime validating only the code 404 is not enough (see the unit test), so there's an optional $failCodeList parameter to supply all the code list to reject.
And, of course, here's the unit test to legitimates my coding:
public function testIsUrlExists(){
//invalid
$this->assertFalse(ToolManager::isUrlExists("woot"));
$this->assertFalse(ToolManager::isUrlExists("https://www.facebook.com/jonathan.parentlevesque4545646456"));
$this->assertFalse(ToolManager::isUrlExists("https://plus.google.com/+JonathanParentL%C3%A9vesque890800"));
$this->assertFalse(ToolManager::isUrlExists("https://instagram.com/mariloubiz1232132/", array(404, 405)));
$this->assertFalse(ToolManager::isUrlExists("https://www.pinterest.com/jonathan_parl1231/"));
$this->assertFalse(ToolManager::isUrlExists("https://regex101.com/546465465456"));
$this->assertFalse(ToolManager::isUrlExists("https://twitter.com/arcadefire4566546"));
$this->assertFalse(ToolManager::isUrlExists("https://vimeo.com/**($%?%$", array(400, 405)));
$this->assertFalse(ToolManager::isUrlExists("https://www.youtube.com/user/Darkjo666456456456"));
//valid
$this->assertTrue(ToolManager::isUrlExists("www.google.ca"));
$this->assertTrue(ToolManager::isUrlExists("https://www.facebook.com/jonathan.parentlevesque"));
$this->assertTrue(ToolManager::isUrlExists("https://plus.google.com/+JonathanParentL%C3%A9vesque"));
$this->assertTrue(ToolManager::isUrlExists("https://instagram.com/mariloubiz/"));
$this->assertTrue(ToolManager::isUrlExists("https://www.facebook.com/jonathan.parentlevesque"));
$this->assertTrue(ToolManager::isUrlExists("https://www.pinterest.com/"));
$this->assertTrue(ToolManager::isUrlExists("https://regex101.com"));
$this->assertTrue(ToolManager::isUrlExists("https://twitter.com/arcadefire"));
$this->assertTrue(ToolManager::isUrlExists("https://vimeo.com/"));
$this->assertTrue(ToolManager::isUrlExists("https://www.youtube.com/user/Darkjo666"));
}
I hope this solution will help someone,
Jonathan Parent-Lévesque from Montreal