Tiếp tục lọat bài về cấu hình nginx cơ bản nào. Trong phần này, tôi sẽ giới thiệu cách cấu hình nginx để hỗ trợ https. Trước khi đi vào cách làm, tôi sẽ trình bày sơ lược một chút về https. Về phần này, các bạn có thể tham khảo trước bài viết này.

Sơ lược về https

Secret key (symmetric key): Đây là phương thức mã hóa đối xứng. Đối xứng ở đây nghĩa là tôi mã hóa bằng key K thì tôi dùng chính key K để giải mã.

  • Nhược điểm: Cả hai đầu nhận và gửi đều phải biết về key K. Khi hai đầu cách nhau quá xa về mặt địa lý thì việc trao đổi key thành nhược điểm. Bạn không thể đi nửa vòng Trái Đất đến Mỹ để trao secret key cho một người bạn của bạn được. Nếu vận chuyện key đó qua internet thì lại quá thiếu an toàn.
  • Ưu điểm: Tốc độ giải mã, mã hóa nhanh

Public key cryptography (asymmetric key): Đây là phương thức mã hóa bất đối xứng. Bất đối xứng ở đây nghĩa là tôi mã hóa bằng key A nhưng tôi chỉ có thể dùng key B để giải mã. Trong cơ chế này, tôi luôn có một cặp khóa. Vai trò của khóa phụ thuộc vào cách sử dụng và có thể hoán đổi cho nhau. Một key tôi cần phải giấu kín. Key này gọi là private key. Một key tôi có thể thoải mái chia sẻ với cộng đồng. Key này gọi là public key. Nếu tôi dùng key A để mã hóa thì tôi chỉ có thể giải mã dùng key B và ngược lại.

  • Nhươc điểm: Tốc độ giải mã, mã hóa chậm hơn
  • Ưu điểm: Phương thức mã hóa bất đối xứng được sử dụng để giải quyết bài toán vận chuyển key trong môi trường đầy rủi ro và cạm bẫy như trên internet.

Tại sao tôi lại trình bày hai loại phương thức mã hóa trên ? Vì chính hai phương thức mã hóa này tham gia vào qua trình hoàn tất một kết nối https.

Trong thực tế, để website hỗ trợ https, system admin phải thực hiện tạo một certificate signing request (CSR). Thông tin trong này gồm common name và public key của website. Sau đó, system admin gửi CSR đến một certificate authority (CA) để họ chứng nhận. Thực chất của hành vi chứng nhận này là một tổ chức uy tín (ở đây là CA) đứng ra xác nhận các thông tin của website là chính xác. Người sử dụng khi truy cập vào website vhost.example.com có thể tin tưởng là họ đang truy cập vào đúng website vhost.example.com chứ không phải là một website giả mạo nào đó. Hành vi chứng nhận được thể hiện ở dạng một chữ ký điện tử. Sau khi nhận CSR, CA sẽ kết xuất từ CSR ra một certificate bao gồm các thông tin gần giống như CSR kèm với đó là một digital signature. CA cho các thông tin certificate đi qua một hash function để tạo ra một mã không thể đảo ngược (từ mã này tôi không thể tìm ra plain text mà đi qua hash funcrtion để sinh ra mã này). Sau đó dùng private key để mã hóa mã này. Kết quả cuối cùng là một thứ mà người ta gọi là digital signature. Lý do sử dụng hash function để tạo mã một chiều chỉ để đảm bảo tính toàn vẹn của thông tin trong certificate ( Nếu thông tin trong này bị sửa đổi có thể căn cứ kết quả chạy hash function trên certificate nhận được với giá trị hash function sau khi giải mã digital signature để biết được. Nếu trùng thì không có gì sửa đổi. Nếu không trùng thì certificate này không còn đáng tin nữa ) Chính việc sử dụng private key để mã hóa thông điệp là dấu vết mà client dùng để xác nhận chính CA là chủ thể ký nhận

Giờ đây, làm cách nào client (cụ thể là browser) có thể biết certificate mà server đưa cho nó được xác nhận bởi CA ? Bản thân trong mỗi browser đều có một cơ sở dữ liệu về các CA trên thế giới cùng với public key của mỗi CA. Từ certificate, browser biết được CA nào có thể đã ký xác nhận (Tại bước này nó chỉ biết chứ không thể khẳng định chắc chắn). Để chắc chắn, browser sẽ sử dụng public key của CA này lấy từ cơ sở dữ liệu của nó để giải mã digital signature. Cơ chế mã hóa bất đối xứng phát huy tác dụng ở đây. Nếu giải mã không được thì browser biết certificate này là một mạo nhận. Nếu giải mã thành công thì browser sẽ tin chắc certificate này do CA đó ký. CA đó cũng được browser tin tưởng nên do đó nó sẽ tin tưởng rằng nó đang nói chuyện với website chính chủ.

Bây giờ browser có thể lấy thông tin trong certificate ra để dùng. Một thông tin cực kỳ quan trọng trong certificate đó chính là public key của chính website. Browser sẽ tự tạo ra một secret key, còn gọi là session key – Key là là key đối xứng được dùng để mã hóa và giải mã thông tin trong toàn bộ một phiên https. Sau đó, browser mã hóa session key này bằng public key của website và gửi cho website. Do mã hóa bằng public key nên thông điệp chỉ có thể giải mã bởi private key của website. Bất cứ ai có bắt được thông điệp này cũng không thể giải nổi. Vậy là bài toán phân phối key qua internet được giải. Từ đấy, client và server sẽ dùng chính session key này để nói chuyện với nhau.

Tôi đã trình bày những gì xảy ra trong thực tế nhưng để phục vụ cho bài viết này tôi không mua certificate đâu, tốn xiền lắm 😛 Thay vì vậy tôi sẽ tự tạo certificate (self certificate). Coi như tôi tự làm CA để xác nhận cho chính website của tôi, mỗi tội browser sẽ chẳng thể tìm được CA nào nên nó sẽ cảnh báo người dùng khi họ ghé website của tôi. Người dùng vẫn có thể lờ đi và tiếp tục.

Tạo certificate

Đầu tiên, tôi tạo private key.

openssl genrsa -des3 -out server.key 1024

Tôi phải nhập passphrase. Tôi phải nhớ passphrase này nếu không tôi sẽ không thể sử dụng được certificate

Sau đó, tôi tạo certificate signing request.

openssl req -new -key server.key -out server.csr

Tôi phải nhập passphrase để bắt đầu quá trình tạo csr

Cuối cùng, tôi tạo certificate từ certificate signing request và tự ký luôn dùng private key.

openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

Tất cả các lệnh trên tôi thực hiện trong /usr/local/nginx/certificate. Hai file tôi sẽ sử dụng trong khi cài đặt sẽ là private key và certificate. File csr chỉ là file trung gian.

Cài đặt certificate

Tôi bổ sung thêm vào cấu hình vhost ba dòng sau:

ssl on; ssl_certificate /usr/local/nginx/certificate/server.crt; ssl_certificate_key /usr/local/nginx/certificate/server.key; 

Và chuyển port 80 thành 443.

Cấu hình cuối cùng của /usr/local/nginx/conf.d/vhost.example.com.conf

server{ listen 443; server_name vhost.example.com www.vhost.example.com; root /home/www/vhost.example.com; error_log /var/log/nginx/vhost.example.com_error.log error; access_log /var/log/nginx/vhost.example.com_access.log main; auth_basic "private site"; auth_basic_user_file /usr/local/etc/.vhost.example.com.htpasswd; ssl on; ssl_certificate /usr/local/nginx/certificate/server.crt; ssl_certificate_key /usr/local/nginx/certificate/server.key; allow 192.168.3.0/24; deny all; location /{ index index.html index.php; } location /public/{ auth_basic off; } location ~ .php { fastcgi_pass unix:/tmp/php_fpm.sock; fastcgi_index index.php; include /usr/local/nginx/conf/fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name; } } 

Chạy test

Vì tôi sửa port nên phải restart nginx service. Bất tiện khi sử dụng passphrase cho private key là tôi phải nhập PEM pass phrase mỗi lần stop/start/reload nginx service.

service nginx restart Enter PEM pass phrase: nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful Stopping nginx: [  OK  ] Starting nginx: Enter PEM pass phrase: [  OK  ] 

Trên browser, tôi nhập
https://vhost.example.com/test.php

alt text

Tuy sử dụng passphrase sẽ an toàn hơn nhưng lại kém tiện dụng. Tôi có thể loại bỏ passphrase đi bằng cách:

backup private key:
cp server.key server.key.org

Loại bỏ passphrase khỏi private key:
openssl rsa -in server.key.org -out server.key

Từ lúc này tôi có thể reload/restart nginx service mà không cần nhập passphrase nữa.

Kết thúc phần 4. Trong phần tới, tôi sẽ trình bày về cấu hình load balancin cho nginx.

Nguồn tham khảo:

https://www.digitalocean.com/community/tutorials/how-to-create-a-ssl-certificate-on-nginx-for-centos-6

Comments

comments