今朝起きたらブラックリスト追加通知がきてた
(-ω-).。スヤァ
Σ(oωo) {ピロンッ}
(-ω-) { なんや・・・普段なることがないラインに通知がきとる・・・ )
(’ω’)!! { 「ブラックリストにIP:XXX.XXX.XX.XXが追加されました」やと!? )
急いでアクセスログテーブルを確認すると・・・
(-ω-) {これは・・・たぶん管理画面のログイン画面のURLを探してるんやろなぁ・・・)
(^ω^) {しっかりとブラックリストに登録されてる!!対策しててよかったで!)
攻撃されたサイトについて
・公開して1ヶ月ほど
・Lightsailのlinux2にDjango・nginxのっけたブログみたいなサイト
・google検索では到達できないほど、少ないなコンテンツ量
→どっからきたんや?(ドメイン名がメジャーなワードで構成してるから、ドメインからランダムに?)
対策内容
・MIDDLEWAREの最初で、直近60秒以内に35回アクセスで404ページ。45回アクセスでブラックリスト。
※但し、googlebotはホワイトリストに登録する
・ブラックリスト、ホワイトリスト登録で、ライン通知する
・ライントークンはここで発行
https://notify-bot.line.me/ja/
# 一番最初になるように設定。
MIDDLEWARE = [
'base.middle.middle.AppMiddle',
'django.middleware.security.SecurityMiddleware',
....
# ライントークン
LINE_NOTIFY_TOKEN = 'XXXXXXXXXX'
今回メインとなる処理
※ブラックリスト期間7日じゃ短いので365日に修正してます(7日じゃ許せねぇよなぁ?)
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とか
"""
共通サービス
"""
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(),
)
# 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
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