Home >Backend Development >PHP Problem >How to implement https two-way authentication in php

How to implement https two-way authentication in php

藏色散人
藏色散人Original
2020-08-11 09:12:114594browse

How to implement https in php: first modify the openssl configuration; then create the CA root certificate and set the certificate password to be greater than or equal to 6 characters; then create the server certificate and client certificate; finally configure nginx and perform php Just curl the test.

How to implement https two-way authentication in php

Recommended: "PHP Video Tutorial"

php implements https (tls/ssl) two-way authentication

Normally, when deploying https, it is based on SSL one-way authentication, which means that as long as the client authenticates the server, the server does not need to authenticate the client.

But in some scenarios with higher security, such as banking, finance and other fields, client authentication is usually required. This enables two-way authentication of SSL.

Since the ssl_client_certificate parameter of nginx can only specify one client public key, if you add a client for communication, you will need to reconfigure a server. The

n:1 mode is implemented through the CA's cascade certificate mode. First, generate a set of CA root-level certificates yourself, and then use it to generate a secondary certificate as a client certificate.

At this time, the client private key signature can be verified not only by the corresponding client public key, but also by the public key of the root certificate.

You should be enlightened after seeing this. Here is a brief introduction on how to operate:

1 Preparation work

1.1 Openssl directory preparation

General situation The configuration files of openssl are all in this directory /etc/pki/tls, so:

mkdir /etc/pki/ca_linvo
cd /etc/pki/ca_linvo
mkdir root server client newcerts
echo 01 > serial
echo 01 > crlnumber
touch index.txt

1.2 openssl configuration preparation

Modify openssl configuration

vi /etc/pki/ tls/openssl.cnf

Comment out this sentence and replace it with the following sentence

#default_ca      = CA_default
default_ca      = CA_linvo

Copy the entire part of [CA_default] and change it to the name above [CA_linvo]

Modify the following parameters inside:

dir = /etc/pki/ca_linvo
certificate = $dir/root/ca.crt
private_key = $dir/root/ca.key

Save and exit

2 Create CA root certificate

生成key:openssl genrsa -out /etc/pki/ca_linvo/root/ca.key
生成csr:openssl req -new -key /etc/pki/ca_linvo/root/ca.key -out /etc/pki/ca_linvo/root/ca.csr
生成crt:openssl x509 -req -days 3650 -in /etc/pki/ca_linvo/root/ca.csr -signkey /etc/pki/ca_linvo/root/ca.key -out /etc/pki/ca_linvo/root/ca.crt
生成crl:openssl ca -gencrl -out /etc/pki/ca_linvo/root/ca.crl -crldays 7

The generated root certificate files are all in /etc/pki/ Under the ca_linvo/root/ directory

Note: When creating a certificate, it is recommended that the length of the certificate password is >= 6 characters, because the Java keytool tool seems to have requirements for it.

3 Create server certificate

生成key:openssl genrsa -out /etc/pki/ca_linvo/server/server.key
生成csr:openssl req -new -key /etc/pki/ca_linvo/server/server.key -out /etc/pki/ca_linvo/server/server.csr
生成crt:openssl ca -in /etc/pki/ca_linvo/server/server.csr -cert /etc/pki/ca_linvo/root/ca.crt -keyfile /etc/pki/ca_linvo/root/ca.key -out /etc/pki/ca_linvo/server/server.crt -days 3650

Instructions:

1. The crt generated here is the cascade certificate under the ca root certificate just now. In fact, the server certificate is mainly used for configuration. Normal one-way https, so you can do it without using cascade mode:

openssl rsa -in /etc/pki/ca_linvo/server/server.key -out /etc/pki/ca_linvo/server/server.key
openssl x509 -req -in /etc/pki/ca_linvo/server/server.csr -signkey /etc/pki/ca_linvo/server/server.key -out /etc/pki/ca_linvo/server/server.crt -days 3650

2. The -days parameter can set the validity period of the certificate as needed, for example, the default is 365 days

4 Create client certificate

生成key:openssl genrsa -des3 -out /etc/pki/ca_linvo/client/client.key 1024
生成csr:openssl req -new -key /etc/pki/ca_linvo/client/client.key -out /etc/pki/ca_linvo/client/client.csr
生成crt:openssl ca -in /etc/pki/ca_linvo/client/client.csr -cert /etc/pki/ca_linvo/root/ca.crt -keyfile /etc/pki/ca_linvo/root/ca.key -out /etc/pki/ca_linvo/client/client.crt -days 3650

Note:

1. You must use cascading certificates here, and you can repeat this step to create multiple sets of client certificates

2. You may encounter this when generating crt The following error is reported:

openssl TXT_DB error number 2 failed to update database

You can refer to here for operation.

I am using method one, which is to configure nginx with unique_subject = no

5 in index.txt.attr

Only the key parts of the server segment are listed here:

ssl_certificate  /etc/pki/ca_linvo/server/server.crt;#server公钥
ssl_certificate_key  /etc/pki/ca_linvo/server/server.key;#server私钥
ssl_client_certificate   /etc/pki/ca_linvo/root/ca.crt;#根级证书公钥,用于验证各个二级client
ssl_verify_client on;

Restart Nginx

6 Test

6.1 Browser test

Due to two-way authentication, accessing the https address directly through the browser will result in a 400 Bad Request ( No required SSL certificate was sent), the client certificate needs to be installed on the local machine.

The certificate installed on windows needs to be in pfx format, also called p12 format. The generation method is as follows:

openssl pkcs12 -export -inkey /etc/pki/ca_linvo/client/client.key -in /etc/pki/ca_linvo/client/client.crt -out /etc/pki/ca_linvo/client/client.pfx

Then double-click it in windows to install it. During the installation, you will be prompted to enter the time to generate the certificate. Password set.

After the installation is successful, restart the browser and enter the URL to access. The browser may prompt you to select a certificate. Just select the certificate you just installed.

At this time, some browsers will prompt the user that the certificate is not trusted, the address is not secure, etc. This is because our server certificate is issued by ourselves, not by a real authoritative CA organization (usually very Expensive~), just ignore it.

6.2 PHP curl test

Only the key curl parameters that need to be set are listed here:

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 信任任何证书,不是CA机构颁布的也没关系  
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1); // 检查证书中是否设置域名,如果不想验证也可设为0  
curl_setopt($ch, CURLOPT_VERBOSE, '1'); //debug模式,方便出错调试  
curl_setopt($ch, CURLOPT_SSLCERT, CLIENT_CRT); //client.crt文件路径,这里我用常量代替  
curl_setopt($ch, CURLOPT_SSLCERTPASSWD, CRT_PWD); //client证书密码  
curl_setopt($ch, CURLOPT_SSLKEY, CLIENT_KEY); //client.key文件路径  
 
CURLOPT_TIMEOUT:超时时间
CURLOPT_RETURNTRANSFER:是否要求返回数据
CURLOPT_SSL_VERIFYPEER:是否检测服务器的证书是否由正规浏览器认证过的授权CA颁发的
CURLOPT_SSL_VERIFYHOST:是否检测服务器的域名与证书上的是否一致
CURLOPT_SSLCERTTYPE:证书类型,"PEM" (default), "DER", and"ENG".
CURLOPT_SSLCERT:证书存放路径
CURLOPT_SSLCERTPASSWD:证书密码,没有可以留空
CURLOPT_SSLKEYTYPE:私钥类型,"PEM" (default), "DER", and"ENG".
CURLOPT_SSLKEY:私钥存放路径
 
 
function curl_post_ssl($url, $vars, $second=30,$aHeader=array())
{
    $ch = curl_init();
    //curl_setopt($ch,CURLOPT_VERBOSE,'1');
    curl_setopt($ch,CURLOPT_TIMEOUT,$second);
    curl_setopt($ch,CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch,CURLOPT_URL,$url);
    curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false);
    curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,false);
    curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
    curl_setopt($ch,CURLOPT_SSLCERT,'/data/cert/php.pem');
    curl_setopt($ch,CURLOPT_SSLCERTPASSWD,'1234');
    curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
    curl_setopt($ch,CURLOPT_SSLKEY,'/data/cert/php_private.pem');
 
    if( count($aHeader) >= 1 ){
            curl_setopt($ch, CURLOPT_HTTPHEADER, $aHeader);
    }
 
    curl_setopt($ch,CURLOPT_POST, 1);
    curl_setopt($ch,CURLOPT_POSTFIELDS,$vars);
    $data = curl_exec($ch);
    curl_close($ch);
    if($data)
            return $data;
    else   
            return false;
}

The verification failed, and the following information will be in the nginx error log

2017/06/05 17:45:07 [crit] 16084#0: *27458991 SSL_do_handshake() failed (SSL: error:04067084:rsa routines:RSA_EAY_PUBLIC_DECRYPT:data too large for modulus e
rror:1408807A:SSL routines:ssl3_get_cert_verify:bad rsa signature) while SSL handshaking, client: 116.255.208.194, server: 0.0.0.0:443

6.3 php soap test

First you need to build the client's pem format certificate. You can also use the openssl command, but because we already have crt and key, manual merging is also very simple:

Create a new file and copy the base64 content (including these two dividing lines) between -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- in crt. , then copy the content between -----BEGIN RSA PRIVATE KEY----- and -----END RSA PRIVATE KEY----- in the key, and then save it as client.pem. .

In fact, if it is more trouble-free, you can directly merge the two files with the following command:

cat /etc/pki/ca_linvo/client/client.crt /etc/pki/ca_linvo/client/client.key > /etc/pki/ca_linvo/client/client.pem

With the pem file, you can use the built-in SoapClient in php to call it. The constructor needs to set the second parameter :

$header = array(          
    'local_cert' => CLIENT_PEM, //client.pem文件路径  
    'passphrase' => CRT_PWD //client证书密码  
    );  
$client = new SoapClient(FILE_WSDL, $header); //FILE_WSDL为要访问的https地址

The last blog mentioned that if local_cert is set to a remote path, an error will be reported. It seems that the client certificate is not used when obtaining the wsdl for the first time. The wsdl needs to be kept as a local file. Call;

But this time there was no problem in the test. There is no need to save it as a local file, just get it remotely.

I originally thought there was a problem with the previous certificate, but I can still use the previous set of certificates, which is very strange~~~~~

The above is the detailed content of How to implement https two-way authentication in php. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn