In this tutorial, I will introduce how to upgrade your website from http to https using 2 different method, Let's Encrypt or self-signed certificate. Then I will introduce how to use mitmproxy to intercept / decrypt a https connection.
- Preparation
- 1 - HTTPS with Perfect Forward Secrecy
- 2 - HTTPS with Self-signed Certificate
- 3 - Decrypt HTTPS Encryption
Before getting started, you should prepare a web server to test. We can use nginx to set up a simple web server quickly.
sudo apt update
sudo apt install nginx
systemctl restart nginx
Visit http://localhost to see if nginx is work
In this chapter, you will learn how to set up a web server supporting https with perfect forward secrecy. And we will use Let's Encrypt to get a free certificate for your web server.
Automatic Certificate Management Environment, ACME, is a protocol that make it possible to set up an HTTPS server and have it automatically obtain a browser-trusted certificate, without any human intervention. This is accomplished by running a certificate management agent on the web server. [1]
For HTTP-01 challenge, Let's Encrypt gives a token to the ACME client, and the client should puts a file which contains the token, plus a thumbprint of the account key, on your web server at http://<your-domain>/.well-known/acme-challenge/<token>
. After putting the file, the ACME client tells Let's Encrypt that the file is ready, then Let's Encrypt will try to retrieve this file via the url mentioned above. [2]
If you want to use Let's Encrypt to get the certificate for your website, you should get your own domain name first. There are many online services that allows us to apply a free domain name. In this tutorial, I use nctu.me to apply for a domain name linyj.nctu.me
.
As mentioned above, Let's Encrypt uses the ACME protocol to verify domain name and to issue the certificate. So we need to install a ACME client first. Let's Encrypt recommends to use Certbot.
sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install certbot python3-certbot-nginx
Add the following lines to /etc/nginx/sites-available/default
location ~ /.well-known {
allow all;
}
After the modification, remember to reload Nginx
sudo systemctl reload nginx
NOTE: in the following document, please replace linyj.nctu.me with your own domain name
For security reason, Let's Encrypt will deny requests if you failed too many times. To avoid this situation, before sending a real request to Let's Encrypt, we can use the test environment provided by Let's Encrypt to test if our network configuration(firewall setting, port forwarding for VM, etc) is setting correctly.
To use this test environment, use --dry-run
option in the command:
sudo certbot certonly --nginx -d linyj.nctu.me --dry-run
if there is no error in the output, we can send a real request now:
sudo certbot certonly --nginx -d linyj.nctu.me
Once you pass the authentication, you will see a congratulation message in the output. Then the certificate and the related files will be saved at /etc/letencrypt/live/linyj.nctu.me/
We have already get the website's certificate and related files through Let's Encrypt. Now we need to configure Nginx to start using https with perfect forward secrecy on our web server.
To enable perfect forward secrecy feature, we need a Diffie-Hellman parameters. We can use openssl to generate one.
sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048
-
Edit
/etc/nginx/snippets/ssl-linyj.nctu.me.conf
- Add the following lines to the file
ssl_certificate /etc/letsencrypt/live/linyj.nctu.me/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/linyj.nctu.me/privkey.pem;
-
Edit
/etc/nginx/snippets/ssl-params.conf
- Add the following lines to the file
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !MEDIUM"; ssl_dhparam /etc/ssl/certs/dhparam.pem;
-
Edit the server block in
/etc/nginx/sites-available/default
- Comment the following 2 lines
listen 80 default_server; listen [::]:80 default_server;
- Add the following lines
listen 443 ssl http2 default_server; listen [::]:443 ssl http2 default_server; include snippets/ssl-linyj.nctu.me.conf; include snippets/ssl-params.conf;
- Add a new server block with the following setting, this will let Nginx redirect http to https automatically
server { listen 80 default_server; listen [::]:80 default_server; server_name linyj.nctu.me; return 301 https://$server_name$request_uri; }
You can look an example configure file here
- Comment the following 2 lines
sudo nginx -t # check if there is any error with your config file
sudo systemctl reload nginx
After reload Nginx, you can visit https://linyj.nctu.me to see if https is work
And when you visit http://linyj.nctu.me, you can see that Nginx redirect you to https://linyj.nctu.me automatically.
- [1] 教學 - 申請Let’s Encrypt憑證與啟用https (Nginx)
- [2] Implementing SSL Perfect Forward Secrecy in NGINX Web-Server
- [3] Configuring Apache, Nginx, and OpenSSL for Forward Secrecy
In the previous chapter, we have learned how to apply for a certificate for our own web server by using Let's Encrypt. This chapter will teach you how to use openssl genarate and use self-signed certificate to enable https on the web server.
Before generate a self-signed certificate for your website, you need to create a Root CA by yourself, then use this Root CA to issue yourself a certificate for your website. So this tutorial will be divided to two parts: the first part is the tutorial for generating a Root CA certificate and the second part is the tutorial for generating a web server certificate. Finally, because this Root CA is created by yourself, you need to add the certificate of this Root CA to the browser so that the browser can trust the certificates issued by this Root CA.
openssl genrsa -out RootCA.key 2048
openssl req -new -key RootCA.key -out RootCA.req
At this step, openssl will ask you to input the information about this certificate, like Country name
, Organization Name
, etc.
openssl x509 -req -days 3650 -sha256 -extensions v3_ca -signkey RootCA.key -in RootCA.req -out RootCA.crt
openssl genrsa -out ServerCert.key 2048
openssl req -new -key ServerCert.key -out ServerCert.req
Again, it will ask you to input some information. And
notice that Common Name
field in the certificate must match the IP address or the domain name of your web server, otherwise the web browser will distrust your website.
openssl x509 -req -days 3650 -sha256 -extensions v3_req -CA RootCA.crt -CAkey RootCA.key -CAcreateserial -in ServerCert.req -out ServerCert.crt
Edit /etc/nginx/sites-available/default
and add the following lines to the server block
# https need port 443 for ssl usage
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
ssl_certificate /path/to/ServerCert.crt; # change the path to your own
ssl_certificate_key /path/to/ServerCert.key; # change the path to your own
After modification, reload nginx
sudo nginx -t # check if there is any error with your config file
sudo systemctl reload nginx
-
Firefox -> Preferences -> Privacy & Security -> View Certificates
-
Import your
RootCA.crt
to the Authorities -
After importing
RootCA.crt
, you can see Firefox says that your website isConnection secure
now
In this chapter, we will use mitmproxy to decrypt https traffic flow, and this tutorial will demo on Linux.
You can install mitmproxy from here.
mitmproxy
By default, mitmproxy will run a proxy server at http://127.0.0.1:8080.
Or you also can assign a port by -p
option
mitmproxy -p 12345 # the proxy server will listen on port 12345
Now you can see mitmproxy GUI from the terminal
Firxfox -> Preferences -> General -> Network Settings
To use mitmproxy to intercept https traffic, we need to install mitmproxy certificate on the web browser so that the connection can established successfully.
Visit http://mitm.it and follow the installation guide to install certificate
Now, open the web browser and visit any website, mitmproxy will intercept the traffic and show the flow on its GUI
You can type ?
to get the help about commands and interact with mitmproxy
You also can use mitmweb
to use web-based interface
By using mitmproxy, you can intercept a https packet, modify its content, then send the modified one to the server.
For more information, please reference mitmproxy documentation