不正アクセスログ集計ツール⑥

最近たまに書くというとこればかりの話になっているが、その割には一向に進まない・・・

djangoへの実装だが、今回はデータベースを使用するわけでもないテストページなので新たにアプリケーションを追加することなく、ポータルのトップページにコッソリぶら下げることとする。(とりあえずログインユーザーのみのアクセス制限は掛ける予定として)

まずはurls.pyへのページ追加

app_name = 'top'

urlpatterns = [
    path('', views.IndexView.as_view(), name='index'),
    path('iplog/', views.BadIPView.as_view(), name='badip'),
    path('ipsum/', views.IpSumView.as_view(), name='iplog'),
]

indexは通常のポータルページで、今回 iplogとbadipという名前のページを追加する。iplogが不正アクセスの疑いのある(何回もログイン失敗を繰り返す輩)のIPアドレスとアクセス回数のリスト、badipがそのIPアドレスのアクセス履歴を表示するページ。

どちらのクラスもデータベースを使用せず、サーバー側のデータをリスト化して参照するので、まずはIpSumViewクラスから。

class IpSumView(generic.ListView):
    template_name = 'top/ipsumlist.html'
    context_object_name = 'ipaddress_records'
    queryset = None
    paginate_by_default = 20
    form1 = None
    form_initial = {}

template_nameは使用するテンプレートのパス名、context_object_nameはテンプレートで使用するリスト。querysetは通常であればデータベースの問い合わせとして、モデルオブジェクトとの接続を行なうが、ここではNoneとしてメソッドのget_queryset()をオーバーライドして先のアクセス解析関数からの戻り値のリストとして返す

    def get_queryset(self):
        """URL引数を取り出すサンプルとデータベースの代わりに動的にリストを作成する
        """
        days = int(self.request.GET.get('days', 1))
        max = int(self.request.GET.get('count', 1))
        srt = self.request.GET.get('srt', 'count')
        src = self.request.GET.get('src', 'bt')
        return get_login_report(get_datetime_hours_ago(days * 24), get_datetime_hours_ago(0), max, src, srt)

実際はフォームのためのパラメータセットなどがあるが省略。
リクエストGETでパラメータを設定するが、パラメータがない場合の初期値を取るため上記のような書き方となっている。get_login_reportがアクセス集計関数

def get_login_report(st, ed, max = 1, src = 'bt', srt = 'count'):
    iplist = {}
    #hists = get_login_history(st, ed)
    list1 = get_django_loginfails(None, st, ed) if src != 'wp' else []
    list2 = get_wp_loginfails(st, ed) if src != 'dj' else []
    hists = list1 + list2
    blist = get_blocklist()
    for adr in map(lambda x: x['address'], hists):
        iplist[adr] = iplist[adr] + 1 if adr in iplist.keys() else 1
    retv = [{'address':adr, 'count': cnt} for adr, cnt in iplist.items() if cnt >= max and adr not in blist]
    if srt == 'count':
        retv.sort(key = lambda x: x['count'], reverse=True)
    else:
        retv.sort(key = lambda x: hash(x['address']), reverse=True)
    return retv

wordpressのログイン履歴データベースからのリストと、djangoポータルページへの履歴を合せて、アクセス回数ごとのリストに変換。指定回数以上アクセスした対象を返す関数となっている。

左がとりあえずの完成形となる。BootstrapのNavibar以外は装飾無しの素のHTMLなので飾りっ気一切無し。この辺の見栄え関連は次回以降勉強していくことにする。

めっちゃくちゃ端折った感じで完成してますが、所詮覚え書きなので、ここまでの作り込みに関して気が付いたときに勘所とかを追記していこうと思います。