AQ Tech Blog

Linux × Security 暗号化編

作成者: tsuyoshi.watanabe|2023年11月21日

はじめに

クラウドインテグレーション部の渡邊です。

本記事のシリーズでは、サーバの構築・運用に最低限必要なセキュリティの体系的知識習得を目的としています。

本シリーズの全体像と今回執筆の内容の位置づけは以下の通りです。

環境

nginx/1.22.1
OpenSSL 1.0.2k-fips 26 Jan 2017
Google Chrome
macOS 13.4
Amazon Linux 2

暗号化概要

暗号化とはデータや通信を保護するセキュリティの要素です。基本的には、データおよび通信を暗号化し、第三者に情報を読み取られないことを目的としています。こちらは情報セキュリティの三要素(CIAに含まれる、「機密性」(Confidentiality)に該当します。

今回はLinuxにおける暗号化の以下機能を紹介します。

  • 通信の暗号化
  • ファイル暗号化
  • ディスク暗号化

通信の暗号化

通信の暗号化は、クライアントとサーバ間のデータのやり取りを盗聴や改ざんから守るために使用されます。主要なプロトコルとしてSSL/TLSが広く利用されています。
SSL/TLSはセキュアな通信を提供するためのプロトコルで、後に述べる公開鍵・共通鍵暗号を用いてデータを暗号化します。
TLSはSSLの後継のプロトコルであり、SSLには脆弱性があるため、実際の運用ではTLSが広く用いられています。
クライアントとサーバ間の通信は、TLSハンドシェイクによってセッションが確立され、暗号化の設定および鍵交換が行われます。

代表的なSSL/TLSを利用したプロトコルを以下に示します。

  • HTTPS(HTTP over SSL/TLS)
    • HTTPプロトコルをセキュアに拡張
    • クライアントとサーバ間の通信を暗号化することで、データの保護が行われる
  • SMTPS(SMTP over SSL/TLS)
    • 電子メールの送信をセキュアにする
  • IMAPS/POP3S(IMAP over SSL/TLS、POP3 over SSL/TLS)
    • 電子メールの受信をセキュアにする
  • FTPS(FTP over SSL/TLS)
    • ファイルの転送をセキュアにする

ちなみに、SFTPはSSHを用いてFTPをセキュアに拡張したプロトコルです。
SSL/TLSを使っているわけではありませんので、ご注意ください。

保管時の暗号化

データ暗号化

暗号化手法はいくつかありますが、大別して以下2種類があります。

  • 共通鍵暗号
  • 公開鍵暗号

それぞれの概要やメリットデメリット、通信の流れなどを説明します。

共通鍵暗号

共通鍵暗号では、暗号化と復号化に同じ鍵を用います。
また、データを暗号化するために、情報を送信・受信する側が同一の鍵を用います。
よって、双方が公開していけない鍵を持っている点で漏洩のリスクが高いため、適切な管理が必要です。
共通鍵暗号のメリットデメリットは以下の通りです。

  • メリット
    • 暗号化・復号化に伴う計算コストが低く、リソースが限られた環境などで利用可能
    • 計算コストが低いため、速度を求められる状況で利用可能
  • デメリット
    • 暗号化・復号化に用いる鍵が同一なため、鍵管理・鍵配送が難しい

※現在、共通鍵は短命なセッションキーとしての利用が主となります。
例:ユーザ認証、IoTデバイス間通信

公開鍵暗号

公開鍵暗号は情報を安全に送受信するための暗号化手法です。
共通鍵暗号とは違い、2つの異なる鍵(暗号化用の鍵・復号化用の鍵)を用いデータを暗号化します。
公開鍵は暗号化用の鍵で誰に公開してもよいですが、秘密鍵は復号化用の鍵で公開してはいけません。
これらの用途の違いは正しく認識する必要があります。

公開鍵暗号を使った通信の流れは以下の通りです。
※公開鍵の通信に直接関係のない部分(3ウェイ・ハンドシェイクなど)は省略しています。

[公開鍵暗号を使った通信の流れ]

①鍵ペア(公開鍵・秘密鍵)を作成

受信者側で鍵ペアを作成します。

②公開鍵を送信

鍵ペアのうち秘密鍵は送信していないことに注意してください。

③受信した公開鍵でメッセージを暗号化

暗号化は公開鍵で実施するため、送信者側で暗号化します。

④受信者に暗号文を送信

この時点でメッセージが暗号化されているため第三者に内容を盗聴や改ざんをされないようになっています。

⑤暗号文を秘密鍵で復号化

受信者側は秘密鍵をもっているためデータを復号化できます。

[公開鍵暗号と共通鍵暗号による通信の流れ]
現在では、公開鍵暗号が共通鍵暗号に比べ処理速度が遅い点から、公開鍵暗号方式と共通鍵暗号方式を組み合わせた暗号方式である、ハイブリッド暗号方式という方法が、SSL/TLSを使った通信で用いられています。
そちらの場合の通信の流れを公開鍵暗号方式のみを使用した場合と対比して説明します。

① 鍵ペア(公開鍵・秘密鍵)を作成

② サーバ証明書を送信
サーバとクライアントで通信する場合(主に、SSL/TLS通信を指す)は、基本的に公開鍵の情報が含まれるサーバ証明書を送付します。

③-1 共通鍵でメッセージを暗号化
公開鍵暗号方式のみの場合と異なり、メッセージの暗号化は、送信者(クライアント)が作成した共通鍵によって行います。

③-2 公開鍵で共通鍵を暗号化
受信者側へ安全に送信するために共通鍵を暗号化します。

④ 暗号文と共通鍵を送信
この時点で、メッセージと共通鍵が暗号化されているため、第三者に内容を盗聴や改ざんをされないようになっています。

⑤-1 秘密鍵で共通鍵を復号化
公開鍵で暗号化したものは共通鍵であるため、復号化するのは共通鍵です

⑤-2 共通鍵で暗号文を復号化 共通鍵が復号化されたため、そちらを用いて暗号文(メッセージを暗号化したもの)を復号化します

公開鍵暗号のメリットデメリットは以下の通りです。

  • メリット
    • 暗号化・復号化に用いる鍵が異なるため、鍵の管理が容易
    • 公開鍵のみを共有すればよいため、鍵交換が安全
  • デメリット
    • 暗号化・復号化に伴う計算コストが高く、リソースがある環境でしか利用できない

ファイルの保管時の暗号化を確認してみましょう。

[保管時の暗号化・復号化デモ]

ルートユーザで暗号化と復号化を行います。

# echo アジアクエストはお客様のデジタルトランスフォーメーションを支援するデジタルインテグレーターです > plain.txt
# ls
plain.txt
# openssl enc -aes-256-cbc -e -in plain.txt -out encrypted.txt
enter aes-256-cbc encryption password:
Verifying - enter aes-256-cbc encryption password:

暗号化したファイルの中身を確認してみます。

# cat encrypted.txt
Salted__��"�4��T�wb �&�55���<�#SHj
���us}$�Zp'��>��i F������
�x�:>�]�Ǘ�)�s��d첛N03c�Wn!|ƫ!��{rH�a2���
��ٚ�vsI�46��G���c
~;EZ�-AD���C
n����

平文の内容が確認できないため、暗号化されていることがわかります。
では、復号化して中身を確認します。

# openssl enc -aes-256-cbc -d -in encrypted.txt -out
enter aes-256-cbc decryption password:
# cat decrypted.txt
アジアクエストはお客様のデジタルトランスフォーメーションを支援するデジタルインテグレーターです

復号化に成功しました。
次に、応用として通信の暗号化についても動作確認をしましょう。

[通信の暗号化デモ]
以下の順番で実施します。

①SAN/秘密鍵/CSRの作成

②サーバ証明書の作成

③nginxで①、②の情報を使うように設定

①SAN/秘密鍵/CSRの作成

サーバ証明書用のディレクトリを作成し、SAN(Subject Alternative Name)を用意します。
SANの説明は以下の通りです。

SANはサーバー証明書のSubjectAltNameフィールドを指し、そのサーバー証明書を設定・使用するサーバーを示すドメイン名・IPアドレス・URIなどを記述し、それらの識別子(ID)をその証明書に関連付けます。

引用元:https://jprs.jp/glossary/index.php?ID=0268

今回の場合、nginxを利用したWebサーバのIPアドレスを、SANに記述します。

$ sudo mkdir /etc/nginx/ssl
$ IP=XX.XXX.XXX.XXX
$ echo "subjectAltName = IP:${IP}" | sudo tee /etc/nginx/ssl/san.txt
subjectAltName = IP:XX.XXX.XXX.XXX

サーバ証明書の作成に必要な、秘密鍵と証明書署名リクエスト(CSR)を作成します。
CSRには公開鍵の情報が含まれております。
CSR作成時に入力する情報は任意で構いませんが、サーバ証明書に反映されますのでその点ご留意ください。

$ sudo openssl genrsa -out /etc/nginx/ssl/server.key 2048
Generating RSA private key, 2048 bit long modulus
........................................+++
............................+++
e is 65537 (0x10001)
$ sudo openssl req -new -key /etc/nginx/ssl/server.key -out /etc/nginx/ssl/server.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:
State or Province Name (full name) []:
Locality Name (eg, city) [Default City]:
Organization Name (eg, company) [Default Company Ltd]:nginx-ssl-test
Organizational Unit Name (eg, section) []:

Common Name (eg, your name or your server's hostname) []:Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

②サーバ証明書の作成

①で作成した情報をもとに、サーバ証明書を作成します。
サーバ証明書には公開鍵が含まれており通信の暗号化の際に利用します。

$ sudo openssl x509 -days 3650 -req -signkey /etc/nginx/ssl/server.key -in /etc/ nginx/ssl/server.csr -out /etc/nginx/ssl/server.crt -extfile /etc/nginx/ssl/san.txt
Signature ok
subject=/C=XX/L=Default City/O=nginx-ssl-test
Getting Private key

③nginxで①、②の情報を使うように設定

nginxの設定ファイルで、秘密鍵、サーバ証明書のパス、SSL通信の設定などを記述します。
一応、nginxの設定ファイルをバックアップします。

$ sudo cp /etc/nginx/nginx.conf{,_`date "+%Y%m%d"`}
$ sudo vi /etc/nginx/nginx.conf

$ diff /etc/nginx/nginx.conf{,_`date "+%Y%m%d"`}
57,67c57,67
<
< server {
< listen 443 ssl http2;
< listen [::]:443 ssl http2;
< server_name _;
< root /usr/share/nginx/html;
<
< ssl_certificate "/etc/nginx/ssl/server.crt";
< ssl_certificate_key "/etc/nginx/ssl/server.key";
< ssl_session_cache shared:SSL:1m;
< ssl_session_timeout 10m;
---
> #
> # server {
> # listen 443 ssl http2;
> # listen [::]:443 ssl http2;
> # server_name _;
> # root /usr/share/nginx/html;
> #
> # ssl_certificate "/etc/pki/nginx/server.crt";
> # ssl_certificate_key "/etc/pki/nginx/private/server.key";
> # ssl_session_cache shared:SSL:1m;
> # ssl_session_timeout 10m;
69,81c69,81
< ssl_prefer_server_ciphers on;
<
< # Load configuration files for the default server block.
< include /etc/nginx/default.d/*.conf;
<
< error_page 404 /404.html;
< location = /40x.html {
< }
<
< error_page 500 502 503 504 /50x.html;
< location = /50x.html {
< }
< }
---
> # ssl_prefer_server_ciphers on;
> #
> # # Load configuration files for the default server block.
> # include /etc/nginx/default.d/*.conf;
> #
> # error_page 404 /404.html;
> # location = /40x.html {
> # }
> #
> # error_page 500 502 503 504 /50x.html;
> # location = /50x.html {
> # }
> # }
$ sudo systemctl restart nginx

設定が完了したため、以下URLからブラウザで動作確認します。

https://<WebサーバのIPアドレス>

「詳細設定」をクリックするとページにアクセスできるためアクセスします。

左上の「許可されていない通信」をクリックし、「証明書が無効です」と出ていますね。
これはブラウザが信頼していない証明書で通信していることが原因です。

証明書ビューアの「詳細」から「エクスポート」を押すと、証明書をダウンロードできるので、中身を見てみましょう。
Macのキーチェーンアクセスから見てみると画像のようになっていました。
CSR作成時に組織名をnginx-ssl-testとしたので想定通り反映されておりました。

こちらの証明書の「信頼」から証明書を信頼するように設定すると、信頼できる証明書としてブラウザが認識し、警告なくHTTPS通信をすることができました。 

 

ディスク暗号化

ディスク暗号化とはHDD/SSDなどを丸ごと暗号化する仕組みです。
ディスクなどを丸ごと暗号化するためファイルの個数/種類/サイズなども秘匿できます。

代表的なディスクの暗号化手法であるLUKS(Linux Unified Key Setup)について述べます。

LUKSはLinuxでディスク暗号化を行うツールで、マスターキーとdm-cryptを使用して暗号化します。
※dm-cryptはDevice-Mapperに含まれるデバイスを暗号化するための機能
暗号化に使うマスターキーを暗号化するためにパスワードまたはユーザキー(鍵)を使用します。
鍵は複数登録することができるため、管理・更新が容易です。
LUKSを使用する際には、起動時に、ディスクのロック解除と、マウントを自動化するための設定をするとよいと思います。

ファイル 説明
/etc/crypttab ディスク(パーティション)のロック解除設定
/etc/fstab マウント設定

まとめ

今回は暗号化で以下を説明しました。

  • 通信の暗号化
    • クライアントとサーバ間のデータのやり取りを盗聴や改ざんから守るために使用される
    • プロトコルはSSL/TLSが主要で、公開鍵と共通鍵を使ってデータを暗号化する
    • クライアントとサーバ間の通信は、TLSハンドシェイクにてセッションを確立
  • 保管時の暗号化
    • 共通鍵暗号は暗号に際して、同一の鍵を使用
    • 公開鍵暗号は暗号に際して、2種類の鍵を使用
    • ディスク暗号化手法としてLUKSが広く使用される

次回の記事では検知について執筆予定です。ぜひそちらも御覧ください!

【参考】

SFTP

SSL暗号化通信の仕組み

今さら聞けないSSL/TLSとは? HTTPSにすると何が良いの?

【図解】ディスク暗号化とファイル暗号化の違いと仕組み