2015 年 11 月の記事一覧です(4 件)

Flaskアプリケーションに二段階認証機能を実装(通算2回目)

Flask製ブログツールをローカルではなく、パブリックなVM(Digitalocean)に立ててブログを書くことにしたので、念の為、二段階認証機能を実装しました。
実は、ブログに組み入れるのは2回目で、ちょうど2年前の11月に一度実装しています(その後面倒くさくなってやめた)。その時の学んだことは Shizuoka.py#3 で発表させて頂きました(なつかしい)。


当時は二段階認証の名前は聞いたことがあるけど実際にやったことがある人が少なく(Shizuoka.py#3の参加者でも使っている人が10人中1人(私)だった)、発表聴いてくれている方々が理解してくれているかどうか不安でした。それから2年経ち、多くのサービスで利用されるようになってきたので、今現在は実際に使うようになっている方も多いのではないかと思います。

pyotpを使う

pythonでtotpを扱うモジュールはいくつかありますが、私はpyotpを使用しています。シンプルなので気に入っています。 基本動作をIPyhtonで確認してみます

In [1]: import pyotp

In [2]: import time

In [3]: totp = pyotp.TOTP('JBSWY3DPEHPK3PXP')

In [4]: totp.now()
Out[4]: '211775'

In [5]: totp.verify(211775)
Out[5]: True

In [6]: time.sleep(30)

In [7]: totp.verify(211775)
Out[7]: False

因みに上記で記述されているシークレットキー(JBSWY3DPEHPK3PXP)はgoogle authenticatorのサンプルコードでも記述されていて、totpのサンプルで使われるのを時々見かけますが、これはBASE32文字列におけるHexspeak(deadbeef)になっています。その為、サンプルで使われているのかと思慮。

In [1]: import base64

In [2]: import binascii

In [3]: binascii.b2a_hex(base64.b32decode('JBSWY3DPEHPK3PXP'))
Out[3]: b'48656c6c6f21deadbeef'

Flaskアプリへ組み込む

Flaskアプリへ組み込む場合、べた書きしてもよいのですが、再利用できるように、pyotpを使用して受け取ったワンタイムパスワードが正しいかどうか判定するfunctionを作成します。こんな感じです。

from pyotp import TOTP
from datetime import datetime, timedelta

def tfa_auth(secret, otp):
    totp = TOTP(secret)
    now = datetime.now()
    past = now + timedelta(seconds=-30)
    try:
        return otp == totp.now() or otp == totp.at(past)
    except:
        return False

タイムギャップ処理(-30)は必ずつけるのですが、+30をどうするのか悩みます(最近のスマートフォンは必ず時刻同期されているだろうから必要ない?)。
そしてviews側のfunctionはこんなかんじです。この処理の前にユーザー認証処理があって、認証されたらこのfunctonに飛びます。

@app.route('/verify_tfa/', methods=['GET','POST'])
def verify_tfa():
    error = None
    if request.method == 'POST':
        if tfa_auth(app.config['TFA_SECRET'], str(request.form['token'])):
            session['logged_in'] = True
            flash(u'You were logged in', 'alert-success')
            return redirect(url_for('show_entries'))
        else:
            error = 'Invalid verification code'
    return render_template('verify_tfa.html', error = error)

二段階認証機能の実装は、QRコード生成等のステップが無ければ、結構単純なので一度やってみるのもいいと思います。


[Unix系]catやエディタを使わないでファイルの中身を見る

引き続き勉強です。今度はcatやエディタを使用しないでファイルの中身を確認する方法。

$ echo "hoge\nfuga\npiyo" > test.txt
$ cat test.txt
hoge
fuga
piyo
$ read -rd '' file<test.txt; echo "$file"
hoge
fuga
piyo

はじめてUNIXで仕事をする人が読む本
木本雅彦 松山直道 稲島大輔
KADOKAWA/アスキー・メディアワークス
売り上げランキング: 106,009

[Unix系] lsを使わないファイル一覧表示

lsが使用できない、もしくは存在しない時にファイルの一覧を表示する方法

$ echo *

この本で *nix のおさらいしてます

はじめてUNIXで仕事をする人が読む本
木本雅彦 松山直道 稲島大輔
KADOKAWA/アスキー・メディアワークス
売り上げランキング: 111,890

direnv を使って Vagrantfile にシークレットキーなどの情報をべた書きしないようにする

Vagrant + Digitalocean + Ansible でのサーバ構築も結構慣れてきたので、Vagrantfile や Ansible playbook を Github にプッシュしておこうと思ったのですが、Vagrantfile に digitalocean のAPIキーなど、公開してはいけない情報があったので direnv を使って隠すようにしました。

direnvは、ディレクトリに環境変数をセットして、そのディレクトリがカレントになった時だけ環境変数が有効になるというもので、使い方によってはかなり便利に使えるものだと思います。

direnvのインストールですが、OS Xの場合はHomebrewでインストール出来ます

$ brew install direnv

インストール後、zshrcに下記記述をして source ~/.zshrc します(他シェルの場合はドキュメントを確認下さい)

eval "$(direnv hook zsh)"

そして、direnv edit . とコマンドを打ち、立ち上がったエディターで

export SECRET_KEY=secretkey
のように記述し、保存します。保存すると、カレントディレクトリに .envrc というファイルが出来ます。

作成した環境変数をシェルで確認してみます。

$ echo $SECRET_KEY

今度はPythonで確認してみます。

>>> import os
>>> os.environ.get("SECRET_KEY")

肝心のVagrantfileへの記述する場合ですが、VagrantfileはRuby記法で書かれている為、Rubyで環境変数を取得するようにします。

ENV["SECRET_KEY"]
と書けばいいみたいです。

追記: .envrc は .gitignoreへ記述して公開リポジトリへアップしないようにしましょう!
追記その2:zshrc への記述を

if [ -x "$(which direnv)" ]; then
    eval "$(direnv hook zsh)"
fi
のようにするとdirenv有無にかかわらずzshrcを使い回せます。


PAGE TOP