Php verify ssl connection

Use PHP to check if page was accessed with SSL

Is there a way to check if the current page was opened with SSL? For example, I want my login page (login.php) to check if it was accessed using SSL (https://mywebserver.com/login.php). If not, redirect them to the SSL version of the page. Pretty much, I want to enfore that the user uses the page securely.

9 Answers 9

You should be able to check that $_SERVER[‘HTTPS’] is set, e.g.:

Be careful. On my IIS server, $_SERVER[‘HTTPS’] is not empty but has the value ‘off’.

if (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != 'on') < // no SSL request >

I personally do not perform this check because I am sure my script will never run on Microsoft IIS. I think this applies to most users having a standard webspace.

You’ll find this may not work if you are working over forwarded protocols. For example, Amazon’s ELB can handle SSL negotiation and interact with your app servers over port 80.

IIS returns $_SERVER[‘HTTPS’] = «off» when there’s no SSL so you have to use if (!empty( $_SERVER[‘HTTPS’] && $_SERVER[‘HTTPS’] != ‘off’) to make sure it works on IIS 😉

@Pacrerier It’s a bug you need to fix, if you support IIS. Or not, if you don’t. Nothing in the question indicates that IIS is unsupported, therefore without the amendment by Wh1T3h4Ck5, this is not a complete answer as it will give the wrong result in some situations.

Читайте также:  Tooltips with html content

Well, Here is another chunk of code. The code will return full url with https/http.

 else < return false; >> /** * Example Use */ define('APP_URL', (isSecure() ? 'https' : 'http') . "://".str_replace(basename($_SERVER['SCRIPT_NAME']),"",$_SERVER['SCRIPT_NAME'])); echo APP_URL; /** * +++++++++++++++++++++++++ * OR - One line Code * +++++++++++++++++++++++++ */ define('APP_URL', ((( ! empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || ( ! empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') || ( ! empty($_SERVER['HTTP_X_FORWARDED_SSL']) && $_SERVER['HTTP_X_FORWARDED_SSL'] == 'on') || (isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443) || (isset($_SERVER['HTTP_X_FORWARDED_PORT']) && $_SERVER['HTTP_X_FORWARDED_PORT'] == 443) || (isset($_SERVER['REQUEST_SCHEME']) && $_SERVER['REQUEST_SCHEME'] == 'https') ) ? 'https' : 'http') . "://".str_replace(basename($_SERVER['SCRIPT_NAME']),"",$_SERVER['SCRIPT_NAME'])); echo APP_URL; ?> 

great answer! Caveat: $_SERVER[‘HTTP_HOST’] instead of $ .. is better since it reflects what the client requested, including the port number.

This is the wrong way round, isn’t it? If I check for !empty on https I get into the else part and vice versa.

@FooBar, On HTTPS it is supposed (totally SAPI dependent) to get you into the if part, not the else part.

Another method is to check for the existence of HTTPS cookies. First your server needs to send the browser a cookie with the secure flag:

Set-Cookie:some_key=some_value;secure 

After your server has sent the browser the cookie, whenever the browser requests a page from your server, it will send along the secure cookie some_key=some_value only if it is requesting a HTTPS page. This means that if you see the existence of the cookie some_key=some_value you know that the browser is requesting a HTTPS page. Voila!

Browser support is very good, as this is fundamental to security. Browsers without support for HTTPS cookies are Firesheepable when users request pages from non-HSTSed domains.

Can this not be spoofed on the client-side, i.e. by manually adding the cookie into a non-secure page?

I don’t like using secure cookies to find out if a page is secured with TLS. The server may have set the cookie with the secure flag, however on receipt of the cookie from the client there is no way to tell if the connection is in fact secure or that the secure flag was indeed set. All you get from the client is a name-value pair. And absence of the cookie also in no way means that TLS is not enabled.

Just to add that in case of nginx, the way to check for https is:

if (isset($_SERVER['SERVER_PORT']) && ($_SERVER['SERVER_PORT'] === '443'))

=== ‘443’ looks wrong — it’s checking for a type match also, but providing a string value for an integer.

@QStudio === ‘443’ is actually correct in this case if you evaluate gettype($_SERVER[‘SERVER_PORT’]) == ‘string’

@My1 This solution also «fails» if your SSL connection is terminated anywhere before reaching its final destination (i.e. reverse proxies, load balancer, and even CloudFlare’s Flexible SSL option). In and of itself, however, it doesn’t actually fail and could even be used to do a sanity check to verify end-to-end «Full SSL» connection.

To use PHP to check if the page was accessed without SSL you can check the port number.

// Most encrypted web sites use port 443 if ($_SERVER['SERVER_PORT']==443) < // Tell browser to always use HTTPS header('strict-transport-security: max-age=126230400'); >elseif (isset($_SERVER['SERVER_PORT'])) < // Redirect current page to https with 301 Moved Permanently response header('location: https://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'], true, 301); exit; >

This assumes your server is configured with the SERVER_PORT environment variable and that the encrypted version of your web site is hosted on port 443. It also assumes your server is not behind a load balancer. If your server is behind a load balancer, you might need a more advanced solution such as this one that does not rely on custom HTTP headers which can vary from one load balancer to the next:

// Set secure cookie to detect HTTPS as cookie will not exist otherwise. header('set-cookie: __Secure-https=1; expires='.substr(gmdate('r', ($_SERVER['REQUEST_TIME']?: time())+126230400), 0, -5).'GMT; path=/; secure', false); // Tell browser to always use HTTPS header('strict-transport-security: max-age=126230400'); if (!isset($_COOKIE['__Secure-https']) && !isset($_GET['https'])) < // Redirect to secure version of site and add https=1 GET variable in case cookies are blocked header('location: https://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'].(strpos($_SERVER['REQUEST_URI'], '?')===false? '?': '&').'https=1', true, 307); exit; >

If the above solution is problematic because it adds ?https=1 to your URL then you can always use JavaScript. Add this to the top of your page right after :

  

Then add the following to your PHP script if you want browsers to remember to always use HTTPS when accessing your site:

header('strict-transport-security: max-age=126230400'); 

or if you want browsers to have your preferences preloaded use:

header('strict-transport-security: max-age=126230400; preload');// HTTPS will always be used! 

If you use the preload feature you will need to submit your web site to be included in Chrome’s HSTS preload list so that browsers come preloaded with your web site preferences. If you use preload, it’s also advisable to host your site on the naked domain without the www. This is because it’s usually easier for most people to type in your domain without the www, and with preload your web site loads without the need of a tedious redirect since https is already the default.

Источник

How to check what certificate is being used in the connection with PHP?

I have a web site written in PHP and I want to be sure that my visitors use my SSL certificate, I mean I want to be sure that there is no man in the middle. How I’ll do it? Edit: Any trick to send certificate name from POST or GET? Edit: Or I’ll send a hash to a user computer, the user computer will hash the cert name with a javascript, and compare both of them whether they mach or not. Not best solution but better than nothing.

3 Answers 3

You cannot do that: MitM attack is based on the fact that the person between server and valid client already has all the valid certificates. So for your server he behaves like any other valid client.

But if I visit Google and if it is used trusted CertIsrl which is being used by Mossad (MitM) at a cafe then no one will get any certificate error message (because everyone will see the blue line) and they catch my password. It means that every time I visit Gmail I have to click the cert to is see if it is Thawte Consulting or not.

@george: yes, but it is a client commitment if the certificate is issued by any trusted certification center. This has nothing to do with google’s severs — it’s only about your browser and Thawte

Yes, it is not much related, sorry, but it is a security issue, I don’t trust anything else anymore. I want to cross check everything.

Assuming that there is a man in the middle, all information that «your visitor» provides (which you might somehow use to identify what certificate they are using) would actually be information that the man in the middle provides. That means you cannot trust it (which is a good rule of thumb really even when there is no MITM).

In other words, this is not possible.

Another way you could reach this conclusion is this: if this were somehow possible, «man in the middle» would not be a term we all know today.

@george: How could you possibly know anything about the certificate your user «sees» unless the user told you? And how could you trust anything the user tells you since he’s the MITM?

@george: how would it help for you? Man in the middle is the same client for you. You cannot determine MitM attack from the server

@george: MITM «forgets»? He goes to all the trouble of hijacking the user’s internet connection and then forgets? Why not say the MITM forgets to attack you at all and leave it at that?

@george: Both me and zerkms have spent a lot of time already telling you that this is not technically possible. Let’s please end this discussion here.

As @Jon and @zerkms have already said, it’s the client’s responsibility to check the server certificate.

One way you could make sure, as a server, that the client is using a connection that has presented your server certificate is to request client-certificate authentication. Indeed, during the handshake with a client certificate, the CertificateVerify TLS message contains the signature of a digest of all the handhsake messages that have been exchanged so far, including the server certificate. If the TLS handhsake succeeds, the client will have sent the correct signature, verifiable against its certificate.

Of course, from the server point of view, this only works if you trust the client certificate.

This wouldn’t completely solve the problem, in particular because it’s not advisable for a client to accept to authenticate using its certificate against a server it cannot verify (even if the private key wouldn’t be leaked, the identity of the certificate would be sent to the rogue party).

Again, at the end of the day, it’s still the user’s responsibility to decide whether it trusts the identity of the server.

Источник

How to know if connection to Database is using SSL or not

I’m using mysqli on PHP to connect to a mysql database. The database have open connection both with ssl and not. I have produced this code:

$db = mysqli_init(); $db->ssl_set(NULL, NULL,'rds-combined-ca-bundle.pem',NULL,NULL); $db->real_connect($hostname,$username,$password,$database); $res = $db->query('SHOW TABLES;'); print_r ($res); $db->close(); 

The output I get it’s pretty fine, I get what I want, but I don’t understand if my connection is goin out with SSL or not. If I change the cert name to xyzrds-combined-ca-bundle.pem, it keeps working with no errors. so I guess it just switch on no-ssl when the cert fail. Any clue on how I can know if I’m connected with SSL or not? Thanks a lot

The manual says that if SSL connect fails, then real_connect should fail. But it seems it doesnt. Just by chance, what if you add this line above your code? mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

Thanks for the info, it gave me better info, but nothing relative to what I was using, the solution proposed as answer worked fine.Ty

3 Answers 3

You can configure SSL for each client, so you can have SSL and NON SSL connections the same time.

You can chech if SSL is configured by sending the following command: mysql> show variables like ‘%ssl%’;

The output should look like this:

+---------------+----------------------------------+ | Variable_name | Value | +---------------+----------------------------------+ | have_openssl | YES | | have_ssl | YES | | ssl_ca | /etc/mysql/ca-cert.pem | | ssl_capath | | | ssl_cert | /etc/mysql/server-cert.pem | | ssl_cipher | | | ssl_key | /etc/mysql/server-key.pem | +---------------+----------------------------------+ 

You can set the following configuration to your mYSQL user:

REQUIRE X509: a valid SSL certificate must be used

REQUIRE ISSUER / REQUIRE SUBJECT: a SSL certificate with specific ISSUER and/or SUBJECT must be used

REQUIRE SSL: the connection is forced to use SSL, authentification can be done by password or valid SSL certificate

With the following comamnd you can check the status of your connected clients:

mysql> SHOW STATUS LIKE ‘Ssl_cipher’;

Output should look like this:

+---------------+--------------------+ | Variable_name | Value | +---------------+--------------------+ | Ssl_cipher | DHE-RSA-AES256-SHA | +---------------+--------------------+ 

Источник

Оцените статью