Token Authentication (Private Access Token) の実装方法
先日とある方からAmazon CloudFrontの[署名付きCookie]と近しい仕組みをCloudflareで実装することは可能か?という話がありました。
署名付きCookieをCloudflareはNativeでサポートしていませんが、代わりにToken Authenticationという機能があり、生成したトークンをURLパラメータに埋め込むことでその代替策の実装が可能です。
この機能はProプラン以上で利用が可能です。
やってみる
いつも通りDNS ProxyモードでアクセスできるWebサイトを作ります。
マネージメントコンソール左のSecurity
からCreate firewall rule
をクリックします。
適当な名前を入力します。
ルールに以下の文字列を入力します。以下のルールはtest.harunobukameda.labrat.online
にアクセスしてきたユーザーに対して、10800秒有効なトークンが含まれているかどうか?(トークンが作成されたから10800秒経過していないか?)を判別しています。ユーザーからのアクセスはURLの後ろに?verify=xxxxxx
としてトークンを付与させることを想定しているので、Separatorとして8
を指定しています。(?verify=
が8文字なので。)
(http.host eq "test.harunobukameda.labrat.online" and not is_timed_hmac_valid_v0("mysecrettoken", http.request.uri,10800, http.request.timestamp.sec,8))
mysecrettoken
がShared Secretとして機能することになります。
上記のルールではタイムスタンプが有効じゃなければ?という設定ですので、挙動はBlock
を指定します。
Save
を押してルールをDeployするとトークン無しでアクセスを行った場合以下のエラーとなります。
では次にトークンを作成してみます。
Python 3.8 用サンプルScriptは以下です。
import time
from hashlib import sha256
message = "/"
secret = "mysecrettoken"
separator = "?verify="
timestamp = str(int(time.time()))
digest = hmac.new((secret).encode('utf8'), "{}{}".format(message,timestamp).encode('utf8'), sha256)
token = urllib.parse.quote_plus(base64.b64encode(digest.digest()))
print("{}{}{}-{}".format(message, separator, timestamp, token))
実行すると以下の文字列が出てきます。
/?verify=1687334255-Omd3LUqHoXBAK115H53w7v3kakXCd%2BYR1zTjvDFfuPc%3D
https://test.harunobukameda.labrat.online/?verify=1687334255-Omd3LUqHoXBAK115H53w7v3kakXCd%2BYR1zTjvDFfuPc%3D
にアクセスすると無事内容が表示されます。
例えばsecret = "mysecrettoken2"
のようにShared Secretを書き換えるとFirewall Ruleと値がずれるため、アクセスを行うとエラーとなります。
マネージメントコンソールでは以下のようにアクセス履歴が出てきます。
セキュリティについて
署名付きCookieもそうですが、この方式はセキュリティ的に万全とはいいがたいことに注意してください。Shared Secretが漏洩してしまえば、トークンを作成すること可能です。署名付きCookieの場合は、漏洩も気にする必要があります。強固なセキュリティを求める場合はmTLSなどを検討すべきです。
Discussion