akkietech’s diary

セキュリティ関連メインの自分用メモ書き。twitter: @akkietech

1/30 FlaskをSqlite3と連携させる

めっっっっちゃくちゃ苦戦

とりあえずflaskでの自作ページのログイン機能として
Register処理とLogin処理をSQLite3と連携させることを考えていた

dbファイルへのアクセスとしては
Registerが「書き込み」
Loginが「読み込み」
にあたる

Apacheの本番環境で動作させると
どちらの処理もdbファイルへのアクセスに問題があった

■背景
デバッグモードではDBへの連携はできていた
なのでApacheで動かしているときの動作に問題があるのだと気づいた

そしてログを確認
自分の場合は
tail -f /var/log/httpd/error_log

例えばRegisterページで登録しようとするとこのエラーが出ていた

sqlite3.OperationalError: unable to open database file

んーファイルがそもそも開けていないっぽい
開発環境でflask runでは処理できていたのに...

普通にdbファイルの権限の問題だと思って
chmodとかchownとか触りまくってたけど
そんな甘い世界ではなかった

そしてググりまくった結果判明した原因は3つ

原因1
dbファイルのパーミッション

原因2
__init__.pyでのdbファイルパスの渡し方

原因3
SELinuxによるアクセス制限


■原因1 dbファイルのパーミッション
これはとりあえずそう
ずっとrootでやってたこともありdbファイルを置くフォルダも全てrootでやっていた
だからapacheに変更

# chown -R apache:apache [dbファイルがあるフォルダ名]

まずこれが1つ

■原因2 __init__.pyでのdbファイルパスの渡し方
これはエラーログとかをコピペしてググりまくって
同じ境遇の人が記事書いているのを発見。

どうやらパスの渡し方が問題だったらしい

以下__init__.pyを一部抜粋

変更前

import os
from flask import Flask

app = Flask(__name__)
app.config.from_mapping(
		SECRET_KEY='dev',
		DATABASE=os.path.join(app.instance_path, 'FlaskApp.sqlite'),
	)

変更後

import os
from flask import Flask

app = Flask(__name__)

app.config.from_mapping(
		SECRET_KEY='dev',
		DATABASE=os.path.join('/var/www/FlaskApp/instance', 'FlaskApp.sqlite'),
	)

変更前のは公式のやつをそのまま持ってきてた
os.pathとapp.instance_pathを組み合わせてdbファイルのパスを取得しようとしている

そして変更後はdbファイルのパスを直接渡してみることにした

これでLoginは成功した、つまりdbファイルの「読み込み」はできるようになった
しかし、「書き込み」はできていなかった


■原因3 SELinuxによるアクセス制限
LoginはできてもRegisterはできなかった
つまり書き込み
何回やってもInternal Server Errorが返る

再度ログを確認してみる

sqlite3.OperationalError: attempt to write a readonly database

さっきとは微妙に違う
今回は明らかに権限が原因だと思ったので
またchmodとchownで色々してみたけどどれでもなかった

すると画面右上にあるエラーメッセージが上がっていることに気づいた

「AVC拒否」
SELinux は問題を検出しました」

うそだろ...?
ここにきてSELinuxによる制限どうこうが入ってくるのか?
たしかにCent7を使い始めたばかりだが

SELinuxのメッセージの詳細を確認したところ
やはり結局httpdがdbファイルへのアクセスを許可されていなかった

後々知ることになるが、SELinuxでの今回のエラーログはこんな感じで見れる
cat /var/log/audit/audit.log | grep "type=AVC"

type=AVC msg=audit(1548864798.247:345): avc: denied { write } for pid=8108 comm="httpd" name="FlaskApp.sqlite" dev="dm-0" ino=10397195 scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:httpd_sys_content_t:s0 tclass=file


画面右上のメッセージをクリックして
さらに表示されている解決策となるコマンドを入力

# semanage fcontext -a -t httpd_sys_rw_content_t /var/www/FlaskApp/instance/FlaskApp.sqlite
# restorecon -v /var/www/FlaskApp/instance/FlaskApp.sqlite

#setsebool -P httpd_unified 1

#ausearch -c 'httpd' --raw | audit2allow -M my-httpd
#semodule -i my-httpd.pp

改行ごとのまとまりでそれぞれ解決策が異なるコマンドらしいが、
もうどっちでもいいので全てを入力した

そしてApacheを再起動

apachectl restart

きてる...

きてる!!!!!!
Registerがきちんと処理してくれた!!!!

ここでまさかのSELinixuが初対面でここまでしてくれていたとは...


■まとめ
学んだこととしては
・tail -f /var/log/error_logでエラーを確認することはとても大切
 そしてエラーログを元にググりまくるのもとても大切

パーミッションがいつもやっているようなchmodとかだけではなくて
 SELiuxのアクセス制御によっても行われている

・CentOS7に来てSELinuxと戦う必要が今後もあるかもしれない


これでDBとの連携はとりあえずは完了
あとは。。。なんだ

BBS作りか

■ちなみに
前回記事で書いたWifiアダプタ
注文したやつが届いたのやってみたが
そんなに変わらない印象

結局NEHの感度が悪いわけではなさそうだった。。。
まぁこれも勉強か