セキュリティのCSRF(クロスサイトリクエストフォージェリ)の動きと対策を確認します。
確認環境 ・Python 3.8.5 ・Windows 10 |
目次
サンプル | CSRF(クロスサイトリクエストフォージェリ)とは |
サンプルイメージ |
CSRF(クロスサイトリクエストフォージェリ)とは
- CSRFは、以下のような手順です。
1.あるサイトAにログインしてセッションを保持している状態とします。
2.悪意のあるURLをクリックし、そのURLのサーバーのプログラムからサイトAにアクセスしにいきます。
3.そのサイトAがCSRF対策をしていない場合、セッションはあるのでアクセスを受け付けて動作してしまいます。 - CSRF対策としてサイトAは、そのアクセスがどこから来たのか確認する必要があります。
- 画面表示時にアクセストークンやワンタイムパスワード等を発行してクライアント側に送信し、再度のサイトへのアクセス時はサーバー側の値と照合して確かめるようにします。
サンプルイメージ
PythonのBottleフレームワークでCSRF対策をしたサンプルイメージです。
# coding: utf-8
from bottle import route,run,get,request,app
from beaker.middleware import SessionMiddleware
import secrets
session_opts = {
'session.type': 'file',
'session.cookie_expires': 300,
'session.data_dir': './data',
'session.auto': True
}
app1 = SessionMiddleware(app(), session_opts)
token = ''
# 初期表示
@route("/test1", method="GET")
def init():
global token
session1 = request.environ.get('beaker.session')
session1['logged_in'] = True
session1.save()
rec = "first"
token = secrets.token_urlsafe(32)
html = '<form action="/display1" method="POST">'
html += '<p>session:' + rec + '</p>'
html += '<input name="token" type="hidden" value="' + token + '"/>'
html += '<input value="登録" type="submit" /></form>'
return html
@route("/display1", method="POST")
def display1():
session1 = request.environ.get('beaker.session')
if session1.get('logged_in'):
if checkToken():
rec = "OK"
else:
rec = "トークンが異なる"
else:
rec = "セッションなし"
html = '<p>session:' + rec + '</p>'
return html
def checkToken():
return (secrets.compare_digest(token, request.forms.get("token")))
run(app=app1,host="127.0.0.1",port='8765')
初期表示時は、16行目から実行されます。
20行目は、セッションの'logged_in'にTrueをセットしています。
23行目は、secrets.token_urlsafeで文字列のトークンを出力しています。
トークンの文字列は、以下のようなイメージです。
CqUfJLENmVlaobL33T7kEV_YhDjr4qcio7x2ThbtAxU
26行目は、出力したトークンをhiddenのvalue値にセットしています。
27行目の登録ボタンを押すと30行目から実行されます。
33行目は、セッションのlogged_in'を判定しています。
CSRF対策の箇所
34行目で44行目が実行されます。
サーバーにあるトークン値と取得した画面から送信されたトークン値が同じ場合trueになり、異なる場合はfalseとして処理を分けます。
関連の記事