늘모자란, 개발 :: [Security] MySQL error.log monitoring

늘모자란, 개발

MySQL 포트는 아주 공개적으로 열려있다. 3306이며 포트를 바꿔도 공격에 자연스럽게 노출되게 된다. 오픈소스의 숙명이라고 할 수 있겠다.

서버 세팅한지 얼마 되지도 않았는데 어찌나 많은 불나방들이 달려드는지 골머리를 앓고 있던차에,
이녀석들을 제거하는 일을 자동화를 해야겠다고 결심했다.

그래서 fail2ban을 깔아서 처리해보려고 했으나 이게 왠일, fail2ban은 정말 SSH(22)만 검사하는 프로그램이었던것이다.
찾아보니 그냥 검사나 제때하고 포트바꿔라 이런소리나 하고 있고...
간단하게 코딩해보기로 했다. 크게 어려울것 같지 않았다. (부작용은 아직 모르겠다)

mysql.log를 남기는것은 성능에 마이너스이므로 에러로그와 슬로우쿼리만 남기고 있다.
두개 로그는 파일 크기가 그렇게 크지 않기때문에 로드하는것에도 부하가 없을 것이라고 생각(근거 없는 믿음)한다

#!/usr/bin/env python
# -*- coding: utf8 -*-

import re
from subprocess import call

path = "/var/log/mysql/"
log = "error.log"

logContents = ""

excludeText = "etc ips............................"

with open("{}{}".format(path,log)) as f:
    logContents = f.read()

extractedIP = {}
for ip in re.findall( r'\'?\'@\'[0-9]+(?:\.[0-9]+){3}\'', logContents):
    ip = ip.replace('@','').replace('\'','')
    try:
        if type(extractedIP[ip]):
            extractedIP[ip] = extractedIP[ip] + 1
    except:
        extractedIP[ip] = 1

for index in extractedIP:
    if extractedIP[index] > 2 and index not in excludeText:
        call("iptables -A INPUT -s {} -j DROP".format(index), shell=True)

f = open("{}{}".format(path,log),"w")
f.write('')
f.close()

print "Done"


내가 로그를 살펴보아하니 공격은 거의 5분안에 이뤄지더라. [아래 로그 참조]
2016-02-07T18:46:47.070457Z 519468 [Note] Access denied for user 'root'@'180.97.215.141' (using password: YES)
2016-02-07T18:46:47.330309Z 519469 [Note] Access denied for user 'root'@'180.97.215.141' (using password: YES)
2016-02-07T18:46:47.521742Z 519470 [Note] Access denied for user 'root'@'180.97.215.141' (using password: YES)
2016-02-07T18:46:47.670816Z 519471 [Note] Access denied for user 'root'@'180.97.215.141' (using password: YES)
2016-02-07T18:46:47.796906Z 519472 [Note] Access denied for user 'root'@'180.97.215.141' (using password: YES)
2016-02-07T18:46:47.915819Z 519473 [Note] Access denied for user 'root'@'180.97.215.141' (using password: YES)
2016-02-07T18:46:48.037179Z 519475 [Note] Access denied for user 'root'@'180.97.215.141' (using password: YES)
2016-02-07T18:46:48.146458Z 519476 [Note] Access denied for user 'root'@'180.97.215.141' (using password: YES)
2016-02-07T18:46:48.253486Z 519477 [Note] Access denied for user 'root'@'180.97.215.141' (using password: YES)
2016-02-07T18:46:48.355799Z 519478 [Note] Access denied for user 'root'@'180.97.215.141' (using password: YES)
2016-02-07T18:46:48.470777Z 519480 [Note] Access denied for user 'root'@'180.97.215.141' (using password: YES)
2016-02-07T18:46:48.670311Z 519481 [Note] Access denied for user 'root'@'180.97.215.141' (using password: YES)
2016-02-07T18:46:48.891320Z 519482 [Note] Access denied for user 'root'@'180.97.215.141' (using password: YES)
2016-02-07T18:46:49.034734Z 519483 [Note] Access denied for user 'root'@'180.97.215.141' (using password: YES)
2016-02-07T18:46:49.167179Z 519486 [Note] Access denied for user 'root'@'180.97.215.141' (using password: YES)
2016-02-07T18:46:49.361079Z 519487 [Note] Access denied for user 'root'@'180.97.215.141' (using password: YES)
2016-02-07T18:46:49.555965Z 519489 [Note] Access denied for user 'root'@'180.97.215.141' (using password: YES)
2016-02-07T18:46:49.800100Z 519490 [Note] Access denied for user 'root'@'180.97.215.141' (using password: YES)


1분에 약 적게는 3건 많게는 5건으로 시도하기때문에 3분마다 cron을 돌게 하고,
거절 된 아이피가 3건이상일 경우 해킹이라고 생각해 iptables를 이용해 블럭 하도록 처리했다.

단점이라면, 3분안에 공격이 연속되지 않으면 로그를 초기화하기때문에 잡아낼 수 없다는 단점이 있다.
즉시 처리 하기 위해 3분이라는 짧은 텀을 주었으나 10분정도를 줘도 무방할 것 같다.

심플한 코드인데 벌써 한 50개정도의 아이피를 블럭한것같다.
이 코드는 gist에서 버전 관리 될 예정이다.
2016/02/10 11:37 2016/02/10 11:37