198
195

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

サイト攻撃されてたけど、対策しててよかった話

Last updated at Posted at 2021-07-23

今朝起きたらブラックリスト追加通知がきてた

(-ω-).。スヤァ

Σ(oωo) {ピロンッ}

(-ω-) { なんや・・・普段なることがないラインに通知がきとる・・・ )

(’ω’)!! { 「ブラックリストにIP:XXX.XXX.XX.XXが追加されました」やと!? )

急いでアクセスログテーブルを確認すると・・・

スクリーンショット 2021-07-23 14.45.44.png
スクリーンショット 2021-07-23 14.46.41.png

(-ω-) {これは・・・たぶん管理画面のログイン画面のURLを探してるんやろなぁ・・・)

スクリーンショット 2021-07-23 15.07.40.png

(^ω^) {しっかりとブラックリストに登録されてる!!対策しててよかったで!)

攻撃されたサイトについて

・公開して1ヶ月ほど
・Lightsailのlinux2にDjango・nginxのっけたブログみたいなサイト
・google検索では到達できないほど、少ないなコンテンツ量
→どっからきたんや?(ドメイン名がメジャーなワードで構成してるから、ドメインからランダムに?)

対策内容

・MIDDLEWAREの最初で、直近60秒以内に35回アクセスで404ページ。45回アクセスでブラックリスト。
※但し、googlebotはホワイトリストに登録する
・ブラックリスト、ホワイトリスト登録で、ライン通知する

・ライントークンはここで発行
https://notify-bot.line.me/ja/

settings.py
# 一番最初になるように設定。
MIDDLEWARE = [
    'base.middle.middle.AppMiddle',
    'django.middleware.security.SecurityMiddleware',
    ....

# ライントークン
LINE_NOTIFY_TOKEN = 'XXXXXXXXXX'

今回メインとなる処理
※ブラックリスト期間7日じゃ短いので365日に修正してます(7日じゃ許せねぇよなぁ?)

base.middle.middle.py
import subprocess
import time

from django.conf import settings
from django.core.cache import cache
from django.http import Http404
from django.utils.deprecation import MiddlewareMixin

from base.service.common.commonService import AccessLogService
from base.utils import lineUtils
from base.utils.requestUtil import RequestUtil

WHITE_IP_LIST = 'white_ip_list'
BLACK_IP_LIST = 'black_ip_list'
CONTROL_IP_LIST = 'control_ip_list'
CONTROL_IP_LIST_DEFAULT = {
    WHITE_IP_LIST: [],
    BLACK_IP_LIST: []
}

class AppMiddle(MiddlewareMixin):

    @staticmethod
    def process_request(request):

        # アクセスログ登録
        if not settings.DEBUG: AccessLogService.insert_access_log(request)
        else: return

        request_util = RequestUtil(request)
        ip = request_util.get_ip()
        control_ip_list = cache.get(CONTROL_IP_LIST, CONTROL_IP_LIST_DEFAULT)
        # ホワイトリスト
        if ip in control_ip_list[WHITE_IP_LIST]: return
        # ブラックリスト
        if ip in control_ip_list[BLACK_IP_LIST]:
            # ブラックリスト対象のIPで期限を確認
            if cache.get('black_ip_' + ip) is None:
                # 期限切れならブラックリストから除外
                control_ip_list[BLACK_IP_LIST].remove(ip)
                cache.set(CONTROL_IP_LIST, control_ip_list)
            else:
                raise Http404("not found")

        ip_time_list = cache.get(ip, [])
        time_temp = time.time()
        # 60秒前の更新記録を削除
        while ip_time_list and (time_temp - ip_time_list[-1]) > 60:
            ip_time_list.pop()
        ip_time_list.insert(0, time_temp)
        cache.set(ip, ip_time_list, timeout=60)
        if len(ip_time_list) > 45:
            control_ip_list[BLACK_IP_LIST].append(ip)
            # 該当IPで365日使用不可とする
            cache.set(CONTROL_IP_LIST, control_ip_list, timeout=60 * 60 * 24 * 365)
            cache.set('black_ip_' + ip, '', timeout=60 * 60 * 24 * 365)
            lineUtils.send_line_notify(f'ブラックリストに登録しました IP:{ip}')
        if len(ip_time_list) > 35:
            if is_google_bot(ip):
                # googlebotのIPをホワイトリストに登録する
                control_ip_list[WHITE_IP_LIST].append(ip)
                cache.set(CONTROL_IP_LIST, control_ip_list, timeout=60 * 60 * 24 * 365)
                lineUtils.send_line_notify(f'ホワイトリストに登録しました IP:{ip}')
            else:
                raise Http404("not found")

# googlebotか判定する
def is_google_bot(ip):
    # googlebotか判定
    try:
        host = subprocess.run(['host', ip], stdout=subprocess.PIPE).stdout.decode().replace('\n', '')
        return host.endswith(('googlebot.com', 'google.com'))
    except:
        return False

下記は個人で作ったutilとかserviceとか

base.service.common.commonService.py
"""
    共通サービス
"""
from base.models import ErrLog, AccessLog
from base.utils.requestUtil import RequestUtil

# アクセスログ登録
class AccessLogService:

    @staticmethod
    def insert_access_log(request):

        request_util = RequestUtil(request)

        # アクセスログ登録
        AccessLog.objects.create(
            csrf_token=request_util.get_csrf_cookie(),
            request_url=request_util.get_request_url(),
            request_host_url=request_util.get_request_host_url(),
            time_zone=request_util.get_time_zone(),
            user_agent=request_util.get_user_agent(),
            ip=request_util.get_ip(),
        )

base.utils.requestUtil
# HTTP request操作Util
class RequestUtil:

    # request
    request = None

    def __init__(self, request):
        self.request = request

    # CSRF COOKIE取得
    def get_csrf_cookie(self):
        return self.request.META.get('CSRF_COOKIE')

    # リクエストURL取得
    def get_request_url(self):
        return self.request.path

    # リクエストホストURL(送信元)取得
    def get_request_host_url(self):
        return self.request.META.get('HTTP_REFERER')

    # タイムゾーン取得
    def get_time_zone(self):
        return self.request.META.get('TZ')

    # ユーザーエージェント取得
    def get_user_agent(self):
        return self.request.META.get('HTTP_USER_AGENT')

    # アクセスIP取得
    def get_ip(self):
        # 'HTTP_X_FORWARDED_FOR'ヘッダを参照して転送経路のIPアドレスを取得する。
        forwarded_addresses = self.request.META.get('HTTP_X_FORWARDED_FOR')
        if forwarded_addresses:
            # 'HTTP_X_FORWARDED_FOR'ヘッダがある場合: 転送経路の先頭要素を取得する。
            client_addr = forwarded_addresses.split(',')[0]
        else:
            # 'HTTP_X_FORWARDED_FOR'ヘッダがない場合: 直接接続なので'REMOTE_ADDR'ヘッダを参照する。
            client_addr = self.request.META.get('REMOTE_ADDR')

        # 動作確認のため、取得したアドレスをそのまま返す。
        return client_addr

base.utils.lineUtils.py
import requests

from django.conf import settings


def send_line_notify(notification_message):
    """
    LINEに通知する
    """
    line_notify_token = settings.LINE_NOTIFY_TOKEN
    line_notify_api = 'https://notify-api.line.me/api/notify'
    headers = {'Authorization': f'Bearer {line_notify_token}'}
    data = {'message': f'message: {notification_message}'}
    requests.post(line_notify_api, headers=headers, data=data)

まとめ

公開して間もないサイトでもサイト攻撃される可能性あるので
対策は十分にしないとやで〜〜〜!

参考にしたもの

https://qiita.com/lxk/items/f56a08bc5ec74c7e3883
https://qiita.com/akeome/items/e1e0fecf2e754436afc8

198
195
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
198
195

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?