[squidでhttpsプロキシ] url_regexでhttpsのホワイトリストを表現する方法

# はじめに
sslインターセプトするhttpsプロキシで使うためのホワイトリストの作成を少しちゃんとしてみました。
利用する環境は、前回構築した以下のものです。
**[squidでActiveDirectory連携とSSLインターセプトするProxyをdockerで手軽につくる](https://qiita.com/bashaway/items/6adc75265973de9b5fcc)**


# 要するにどうすればいいのか
ホワイトリストやブラックリストのURLを url_regex で表現すると、以下となりました。

**サブドメインを含む、特定のドメインを表現する場合**
以下の例では、サブドメインを含む qiita.com というドメインを表現しています。

```:whitelist
^(https*://)*([^/][^/]*\.)*qiita\.com(:443|:80)*(/.*)*$
```

**サブドメインを含む、特定のドメインを表現する場合。で、複数のドメイン文字列に共通点があってまとめたい場合**
以下の例では、サブドメインを含む slack.comもしくはslack-edge,com というドメインを表現しています。

```:whitelist
^(https*://)*([^/][^/]*\.)*slack(-edge)*\.com(:443|:80)*(/.*)*$
```

上記ホワイトリストをテキストファイルで準備しておき、 `squid.com` で url_regex として読み込めばOKです。

```:squid.com
acl whitelist  url_regex -i "/etc/squid/whitelist"
http_access allow whitelist
```

# 書き方を見つけるまでの過程

## 例：qiita.comの場合

fqdnだけをホワイトリストに書いても悪意に満ちたサイトへ接続できてしまう。

例えば、ホワイトリストにこう書いたとする。

```:whitelist
qiita\.com
```

でもこれは、フルパスやサブドメインに同じ文字列があった場合にマッチしてしまう。

```:match_url
https://example.com/qiita.com/exploit.js
https://qiita.com.example.com/exploit.js
```

じゃあ、サブドメインを含めながら、特定のドメイン名を許可するために、先頭のプロトコルからの連続性を利用して、こう書いてみたらどうだろうか。

```:whitelist
^https*://([^/][^/]*\.)*qiita\.com/
```

これではダメだった。
証明書をとるためだろうか、最初に `qiita.com:443` というのに接続しにいっている。

```:squid_log
 TCP_DENIED/407 4054 CONNECT qiita.com:443 - HIER_NONE/- text/html
 TCP_DENIED/407 4424 CONNECT qiita.com:443 - HIER_NONE/- text/html
 TCP_DENIED/200 0 CONNECT qiita.com:443 PROSPER2\\USERNAME HIER_NONE/- -
```

先ほどのルールに、プロトコルとポート番号を考慮してみよう。どうせだからHTTPなら:80と入れても通信させてあげるようにしよう。
文字列の先頭は、プロトコル表記があってもなくてもマッチするようにし、FQDNの最後はポート番号があってもなくてもマッチするようにした。

```:whitelist
^(https*://)*([^/][^/]*\.)*qiita\.com(:443|:80)*/
```

まだダメだった。
さっきと変わってない。ポート番号で終わっているから、最後のスラッシュが邪魔してマッチしないんだろう。

```:squid_log
 TCP_DENIED/407 4054 CONNECT qiita.com:443 - HIER_NONE/- text/html
 TCP_DENIED/407 4424 CONNECT qiita.com:443 - HIER_NONE/- text/html
 TCP_DENIED/200 0 CONNECT qiita.com:443 PROSPER2\\USERNAME HIER_NONE/- -
```

先ほどのルールに追加して、スラッシュがある、もしくは、スラッシュが無くポート番号もしくはFQDNで文字列の末尾になる。とした。

```:whitelist
^(https*://)*([^/][^/]*\.)*qiita\.com(:443|:80)*(/.*)*$
```

ルートのサイトは、 `https://qiita.com/` サブドメインのサイトは `https://zine.qiita.com/` の両方で通信確認できた。
たぶんこれでOKだと思う。


## 例：slack.comの場合

同じようにslackのサイトも許可しておこう。

```:whitelist
^(https*://)*([^/][^/]*\.)*slack\.com(:443|:80)*(/.*)*$
```

ブラウザでみてみると、なんか中途半端だ。
[![Screenshot from Gyazo](https://gyazo.com/5d4c4f8d70e62f06940435f4f1efa172/raw)](https://gyazo.com/5d4c4f8d70e62f06940435f4f1efa172)

ログをみてみたところ、slack-edge.comっていうとこに通信しに行ってるな。

```:squid_log
 TCP_DENIED/407 4082 CONNECT a.slack-edge.com:443 - HIER_NONE/- text/html
 TCP_DENIED/407 4452 CONNECT a.slack-edge.com:443 - HIER_NONE/- text/html
 TCP_DENIED/407 4082 CONNECT a.slack-edge.com:443 - HIER_NONE/- text/html
 TCP_DENIED/200 0 CONNECT a.slack-edge.com:443 PROSPER2\\USERNAME HIER_NONE/- -
```

ということは、 slack という文字列のあとに、  -edge という文字列が **ある** もしくは **ない** とすればよさそうだ。

```:whitelist
^(https*://)*([^/][^/]*\.)*slack(-edge)*\.com(:443|:80)*(/.*)*$
```

もういちどブラウザでみてみよう。
[![Screenshot from Gyazo](https://gyazo.com/81083f812317f2773e8d45d470fb86bb/raw)](https://gyazo.com/81083f812317f2773e8d45d470fb86bb)
うん、これで大丈夫そう。



# さいごに
**ホワイトリストやブラックリストには dstdomain を使ったほうが断然楽です**
が、正規表現の勉強も兼ねて、ってことで試行錯誤してみました。