Cómo evitar que ddos maliciosos se rastreen en nginx
El sitio web que escribí, no sé por qué siempre hay muchas IP de acceso maliciosas, que no son usuarios normales. Antes de acceder, también pensé si podría ser el proxy del operador. IP de exportación del servidor, pero parece que no es así, no te preocupes por ahora, prohíbelo más tarde
Entonces, ¿cómo prohibir? Las reglas son relativamente simples, es decir, después de exceder un umbral, utilice el siguiente comando de iptables
iptables -I INPUT -s -j DROP
servicio de guardar iptables
servicio de reinicio de iptables
Cómo ¿Cuenta la IP de acceso de nginx? Actualmente, es relativamente sencillo leer el archivo nginx access.log y luego analizarlo. Si excede el umbral en un día, ejecutaremos el comando anterior y prohibiremos la IP.
Un problema es que lo que necesitamos es monitorear el archivo access.log todo el tiempo en lugar de leerlo una vez. Por supuesto, podemos bloquear la IP más tarde al final de cada día, pero esto no puede. Dale arrogancia al rastreador. Entonces
Creo que es mejor bloquearlo de inmediato.
He escrito una función similar a tail para leer un archivo antes. Al abrirlo, primero localiza el tamaño del archivo y luego comienza a leer las líneas en un bucle para procesarlo. es un poco diferente. Utilizo tail directamente para ubicar la secuencia de ese archivo en el sys.stdin de mi programa, para poder leer fácilmente todas las secuencias
tail /var/log/nginx/. access.log | python .py
Pero access.log de nginx se logrará una vez al día. ¿Cómo se hace? El método recomendado en el sitio web oficial de nginx
mv access.log. .log.0
kill -USR1 `cat master.nginx.pid`
dormir 1
gzip access.log.0 # hacer algo con el acceso. log.0 p>
Mi vps es procesado por logrotated, que se puede encontrar en /etc/logrotate.d/nginx
/var/log/nginx/*.log { p>
diario
faltaok
rotar 52
comprimir
retrasarcomprimir
notifempty
crear 640 nginx adm
scripts compartidos
postrotar
[ -f /var/run/nginx.pid ] && matar -USR1 `cat / var/run /nginx.pid`
endscript
}
La creación expresada aquí significa que el archivo se volverá a crear. De hecho, no hay datos nuevos en un archivo tan antiguo, pero debido a que se usa tail y no hay eof, al leer directamente, encontrará que la función file.readline () se atascará, lo que provocará que el programa se congele. para que el programa no pueda salir automáticamente. Luego elegí usar select para manejarlo y agregué un tiempo de espera de 10 segundos. A juzgar por el tráfico actual, básicamente hay muchas solicitudes por segundo. Si no hay datos durante 10 segundos, algo sucede. equivocado.
mientras sys.stdin en select.select([sys.stdin], [], [], 10)[0]:
Entonces, si no hay selección, significa Básicamente, el archivo de registro de nginx se rotó, por lo que cuando encontré tal situación, simplemente salí del programa y lo terminé.
¿Qué debo hacer si finalizo el programa? Originalmente quería reiniciar el programa, pero sentí que podría no ser apropiado, así que usé crontab para manejarlo y lo verifiqué cada 2 minutos. En varios inicios, utilicé Flock para evitar que el programa se reiniciara
*/2 * * * * Flock -xn /dev/shm/blocker.lock -c "sh /srv/www/beauty/daemon. /nginx_ip_blocker.sh"
Aquí se adjunta código
#coding=utf-8
importar sistema
importar re
importar sistema operativo
importar urllib
importar urllib2
importar fecha y hora
importar hora, sistema operativo
importar registro
importar json
importar selección
logging.basicConfig(level=logging.DEBUG, datefmt='%Y%m%d %H:% M:%S', format='[%( asctime)s] %(message)s')
"""
iptables -I INPUT -s -j DROP
servicio iptables guardar
servicio iptables reiniciar
Este script se utiliza principalmente para prohibir las direcciones IP que acceden maliciosamente a nginx
"""
MAX_IP=7000
def get_date():
return time.strftime("%Y%m%d")
def ban_one_ip(ip):
os.system("iptables -I INPUT -s %s -j DROP; servicio iptables guardar; servicio iptables reiniciar"%ip)
def find_ip_and_ban ():
para ip en ip_map:
if ip_map.get(ip)>MAX_IP:
imprime "prohibir ip, cuenta %s:%s "%(ip_map.get(ip), ip)
ip_map[ip] = 0
ban_one_ip(ip)
hoy = Ninguno
ip_map = {}
def process_log(lines):
ip_map global;
global hoy;
ahora = get_date ()
si ahora != hoy:
hoy = ahora
ip_map = {}
para línea en líneas: p>
ip = line.split (" ")[0]
recuento = ip_map.get(ip,0)
recuento += 1
ip_map[ip]=count;
find_ip_and_ban()
COUNT=50
def mai
n():
brk=False
while True:
tmp = 0;
líneas =[]
brk=False
mientras que sys.stdin en select.select([sys.stdin], [], [], 10)[0]:
línea = sys .stdin.readline()
si no es línea:
brk=True
imprime 'leer a eof'
descanso p>
líneas.append(línea)
tmp+=1
si tmp>CONTAR:
descanso
más:
brk=True
imprimir 'tiempo de espera de lectura'
pausa
proceso_log(líneas)
imprimir "leer líneas:%s"%len(líneas)
if brk:
break
if brk:
print "break fuera"
if __name__ == "__main__":
main()