Apache勉強会

## Apache HTTP Server
SNS,ブログ,動画配信,オンラインショッピングサイトなどWebサイトの配信に欠かせないのでがWebサーバである。その中でも主要なWebサーバであるApacheの設計に関して項目分けして備忘録とする。

Webサービスで利用されるHTTP(Hyper Text Transfer Protocal)はWebコンテンツを配信するサーバと、それをクライアントとの間でやり取りされるサーバクライアント方式のネットワークプロトコルである。

##1.httpd.conf,.htaccessの基本
```ruby:httpd.conf項目

-１行１項目(ディレクティブ)を指定する
###全体設定
Listen 80              #リスンポート
User apache            #実行プロセスユーザ
Group apache           #実行プロセスグループ
ServerName www.example.com      #apacheが自分のホスト名を識別するホスト名。例えば、エラー画面を返す際に画面へ表示
ServerAdmin foo@gmail.com       #サイト管理者のメールアドレス

###特定のファイル、ディレクトリ、URLに設定を限定する際はコンテナ指示子を利用する
<Directory ディレクトリパス>
~</Directory>
指定したディレクトリ配下へその設定を適用する

<Files ファイル名>
~</Files>
指定したファイルのみに設定を適用する

<Location URL>
~</Location>
指定したURL以下のリクエストのみに設定を適用する。URL例:/status

<VirtualHost アドレス>
~</VirtualHost>
IPアドレスベースのバーチャルホストを利用するのに使用する。ポートによる分割も可能mm
```
#####ディレクティブ一覧: https://httpd.apache.org/docs/2.4/ja/mod/directives.html

```ruby:基本設定一例
## 待ち受けポート
Listen 80
##　設定ファイルを格納するTOPディレクトリ
ServerRoot "/etc/httpd"
###公開コンテンツを格納するTOPディレクトリ
DocumentRoot "/var/www/html"
###　apache実行プロセスユーザ
User apache
###　apache実行プロセスグループ
Group apache
### エラー時の問い合わせ先メールアドレス
ServerAdmin xxx.example.com

###ログの設定
####エラーログ
ErrorLog /logs/websrv1_error.log
Loglevel warn

###アクセスログ
LogFormat "%h %l %u %t ¥"%r¥" %>s %b" common

CustomLog /logs/websrv1_access.log common
例：
10.128.0.2 - - [04/Nov/2018:16:19:06 +0900] "GET / HTTP/1.1" 200 329
```
`超参考`: ApacheとNginxのログフォーマット比較
https://qiita.com/teco_naka/items/f42671850122ed69d0c5


##2.パフォーマンス
```ruby:①流量制御
Timeout 300
各イベントについて、リクエストを失敗させるまでにサーバが 待つ時間を設定。TCP タイムアウト。
クライアント接続要求を受け取ってから、コンテンツを提供するまでの連続してパケットを送信する時間の最大値を指定します。単位は秒単位です。ここで設定した時間を過ぎてもパケットが送信されない場合、ブラウザはエラーメッセージを表示するようになる。

・GETリクエストにかかる総時間
・POSTやPUTメソッドにおける次のTCPパケットが届くまでの待ち時間
・レスポンスを返す際に、TCPのACKが返ってくるまでの待ち時間


例1： cgiスクリプトで以下を仕込むとsleep時間がtimeout時間より大きい場合にタイムアウトエラー(504)になる。
#!/bin/sh
sleep 300
echo "Context-type: text/plain"
echo
echo 'XXX'

例1： telnetでapacheとやりとり
[root@ap1 cgi]# telnet localhost 80
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
GET /repo/rhel/rhel65 HTTP/1.1 →ここを入力して１回だけEnterした後に二度目を押さないと指定時間でタイムアウトする
HTTP/1.1 408 Request Timeout
Date: Sun, 04 Nov 2018 13:25:43 GMT
Server: Apache/2.4.6 (CentOS) OpenSSL/1.0.2k-fips
Content-Length: 221
Connection: close
Content-Type: text/html; charset=iso-8859-1

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>408 Request Timeout</title>
</head><body>
<h1>Request Timeout</h1>
<p>Server timeout waiting for the HTTP request from the client.</p>
</body></html>
Connection closed by foreign host.
```

##3.SSL/TLS over HTTP
通信の暗号化をするためにSSL/TLSを実装してセキュリティ性を向上させる。
暗号化の流れは以下
1.サーバへリクエスト送信@クライアント
2.サーバ証明書をクライアントへ送付@サーバ
3.サーバ証明書からサーバ公開鍵を取得@クライアント
4.共通鍵生成@クライアント
5.サーバ公開鍵で共通鍵を暗号化@クライアント
6.サーバ公開鍵で暗号化した共通鍵をサーバへ送付@クライアント
7.暗号化された共通鍵をサーバ秘密鍵で複合@サーバ
8.クライアントへの送信データを共通鍵で暗号化して送付@サーバ
9.受信データを共通鍵で複合化@クライアント
※7で共通鍵を複合できるのはサーバの秘密鍵だけで秘密鍵はサーバしか持っていない点が重要

```ruby:SSL証明書作成&https実装
#サーバ秘密鍵の作成
-RSA形式、256bitのAES形式、かつ2048bitの鍵長で作成
openssl genrsa -aes256 2048 > server.key

#CSRの作成
req CSRファイル作成
-new 新規にCSR作成
-key 秘密鍵ファイル指定
openssl req -new -key server.key > server.csr

#サーバ証明書作成
x509           X.509形式証明書
-in CSRファイル  CSRファイル指定
-days          証明書有効期限
-req           入力ファイルがCSRであること明示
-signkey秘密鍵  秘密鍵ファイル指定      
openssl x509 -in server.csr -days 3650 -req -signkey server.key > server.crt

 Tips:サーバ秘密鍵からパスフレーズ削除
openssl rsa -in server.key_org > server.key

-httpd.conf　または ssl.confに以下追記
<VirtualHost *:443>
# SSL有効化
    SSLEngine on
#SSL/TLSプロトコル
    SSLProtocol -all +TLSv1.2
#暗号化スイートをサーバ側で決定する設定。SSLダウングレード防止のためon
    SSLHonorCipherOrder on
#ブラウザとの HTTPS 接続に SSL/TLS データ圧縮を使っている場合に中間者攻撃者が平文の HTTP ヘッダを取得する可能性があるので圧縮は無効化
    SSLCompression off
#暗号化スイート
    SSLCipherSuite ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS

#サーバ秘密鍵パス
    SSLCertificateKeyFile   /etc/httpd/ssl/server.key
#サーバ証明書パス
    SSLCertificateFile      /etc/httpd/ssl/server.crt


    ServerAdmin  (設定値)
    DocumentRoot (設定値)
    ServerName   (設定値)
    ErrorLog     (設定値)
    CustomLog    (設定値)
</VirtualHost>
```
SSLプロトコルや暗号化スイートを検査↓
https://www.ssllabs.com/ssltest/

# 4. 認証

正しいアクセス元からのアクセスを保証する上での認証機能は Web システムで必要不可欠である。
Apache でも様々な認証方式をとることができるので、試してみる。

- 認証用の Apache パラメータ

`AuthType` 　　　使用する認証方式
`AuthName`　　   ここで指定した文字列は認証画面の中で表示される
`AuthUserFile`　 パスワードとIDを明記したファイルの格納場所を記述
`require`　　　　 有効なユーザーに認証させるという意味。Basic 認証、Digest認証で正に指定する

## Basic 認証
ユーザ・パスワード情報による最も基本的な認証方式。
実装難易度は低いが、ユーザ・パスワード情報をクライアントからサーバへbase64でハッシュ化した値を送るので暗号化されていない通信の場合は平文で流れてしまう形になる。あくまで簡易的に認証機能を試したい場合に使うべき。

- Basic 認証設定例

```
# .htpasswd作成
htpasswd -c /etc/httpd/conf/.htpasswd <user> 

# httpd.conf
# Authentication
<Directory "/appl/html1/basic">
    AuthType Basic
    AuthName "basic authentication"
    AuthUserFile /etc/httpd/conf/.htpasswd
    require valid-user
</Directory>
```

- curlでのBasic認証

リクエストヘッダーに、Authorization ヘッダー有。base64 でハッシュ化されている。

```
curl -v -u <user>:<password> http://web1/basic/index.html 

# リクエストヘッダー
> GET /basic/index.php HTTP/1.1
> Host: web1
> Authorization: Basic xxxxxxxxxxxxxxxx
> User-Agent: curl/7.61.1
> Accept: */*

# レスポンスヘッダー
< HTTP/1.1 200 OK
< Date: Sat, 28 Mar 2020 09:21:44 GMT
< Server: Apache/2.4.41 () OpenSSL/1.0.2k-fips SVN/1.7.14
< Upgrade: h2,h2c
< Connection: Upgrade
< Last-Modified: Fri, 27 Mar 2020 15:41:30 GMT
< ETag: "139-5a1d7ef725313"
< Accept-Ranges: bytes
< Content-Length: 313
< Vary: Accept-Encoding
< Content-Type: text/html; charset=UTF-8
```

## Digest 認証
ユーザ・パスワード情報を非可逆暗号であるMD5で暗号化して送信する。
ハッシュ情報が漏洩しても、base64のように複合される可能性が低いため、Basic 認証よりもセキュリティレベルが高い

- Digest 認証設定例

```
# .htpasswd作成
htdigest -c /etc/httpd/conf/.htdigest <AuthName> <username>

# httpd.conf
# Authentication
<Directory "/appl/html1/digest">
    AuthType Digest
    AuthName "digest0"
    AuthUserFile /etc/httpd/conf/.htdigest
    require valid-user
</Directory>
```

- curlでのDigest 認証

リクエストヘッダーに、Authorization ヘッダー有。Digest 認証形式となると様々なパラメータがついている。
またcurl でのリクエスト時だが、リクエスト-レスポンスが2回行われている模様。1回目は401で返り、2回目は200で返る。

仕組み的には以下のため2回リクエスト・レスポンスが発生している。

1. ユーザ名・パスワード・1度目のレスポンスでサーバから返されるランダム文字列(サーバからのレスポンスのHTTPステータスコードは401)に対してクライアントで作成したランダムな文字列を合わせてMD5暗号化。
1. 1で生成した情報を2回目のリクエストでサーバへ送付
1. サーバ側でも1と同様の手順でMD5暗号化文字列を作る
1. 2と3の情報を照合して同一であれば、認証成功とみなし、レスポンスをHTTP ステータスコード200で返す。同一でなければ、レスポンスをHTTPステータスコード401で返す。


下記は2回目のリクエスト・レスポンスヘッダー。

```
curl -v --digest -u <user>:<password> http://web1/basic/index.html 

# リクエストヘッダー
> GET /digest/index.php HTTP/1.1
> Host: web1
> Authorization: Digest username="root", realm="digest0", nonce="xxxxxxxxxxxxxxxxxxxxxxxxxx", uri="/digest/index.php", cnonce="xxxxxxxxxxxxxxxxxxxxxxxxxxxxx", nc=00000001, qop=auth, response="b4a7ee62ab8a2a877615aef61708cd04", algorithm="MD5"
> User-Agent: curl/7.61.1
> Accept: */*

# レスポンスヘッダー
< HTTP/1.1 200 OK
< Date: Sat, 28 Mar 2020 09:45:28 GMT
< Server: Apache/2.4.41 () OpenSSL/1.0.2k-fips SVN/1.7.14
< Authentication-Info: rspauth="xxxxxxxxxxxxxxxxxxxxxx", cnonce="xxxxxxxxxxxxxxxxxxxxx", nc=00000001, qop=auth
< Last-Modified: Fri, 27 Mar 2020 15:41:30 GMT
< ETag: "139-5a1d7ef725313"
< Accept-Ranges: bytes
< Content-Length: 313
< Vary: Accept-Encoding
< Content-Type: text/html; charset=UTF-8
```


#4.Apache+SVNでバージョン管理環境を構築
ApacheにSVNのクライアントを組み合わせてSVNによるバージョン管理システムを構築

```ruby:SVN
#SVNモジュールをインストールする
yum -y install svn

#Apache httpdでSVNリポジトリを参照するモジュールmod_dav_svnをインストール
yum -y install mod_dav_svn

#レポジトリ用のディレクトリ作成
mkdir -p /var/apps/svn/repos/

#下記をhttpd設定の一部として作成
/etc/httpd/conf.d/subversion.conf
#########################################################################
<IfModule dav_svn_module>
    <Location /svn>
        SSLRequireSSL
        DAV                     svn
        SVNListParentPath       on
        SVNParentPath           /var/apps/svn/repos/

        #BASIC認証
        AuthType                Basic
        Require                 valid-user
        AuthName                "Suvbersion Repository"
        AuthUserFile            /var/apps/svn/htpasswd
        AuthzSVNAccessFile      /var/apps/svn/authz

    </Location>
</IfModule>
#########################################################################

#htpasswdコマンドで/var/apps/svn/htpasswdにユーザー情報を作成します。
htpasswd -bc /var/apps/svn/htpasswd hoge P#ssw0rd

#Subversionリポジトリの作成
#svnコマンドで、リポジトリ(プロジェクトごとファイルを管理する領域)を作成。Subversionのお作法的に、trunk, branches, tagsの3つのディレクトリを作成

svnadmin create /var/apps/svn/repos/sample
svn mkdir -m '' file:///var/apps/svn/repos/sample/trunk
svn mkdir -m '' file:///var/apps/svn/repos/sample/branches
svn mkdir -m '' file:///var/apps/svn/repos/sample/tags

#パーミッションの調整
chown -R apache:apache /var/apps/svn

```