En todos los ámbitos de nuestros desarrollos existe una acción, que habitualmente realiza un cliente, y posteriormente desencadenamos una reacción como resultado. En situaciones controladas no se incluyen protecciones ante ataques, pero en el mundo real, donde existe la cyberdelincuencia a nivel global, cualquier proyecto está en el objetivo de los hacker - a veces para practicar, otras para conseguir otros objetivos -.
Un aspecto muy importante en mis proyectos - PYMETRICK es uno de ellos - es la seguridad ante los cyberataques, y nunca está de más invertir tiempo y recursos en mantenerse actualizado - tus clientes te lo agradecerán - . Muchos de estos ataques están muy extendidos en webs desarrolladas sobre PHP (WORDPRESS, JOOMLA, ...) y algunos consisten en enviar como parámetros : /?cmd=echo(344444443%2b1); como es normal, el ataque tiene asociada una dirección IP que nos servirá para planificar nuestra reacción.
ABUSEIPDB https://www.abuseipdb.com es una base de datos online, que recolecta IPs denunciadas por prácticas abusivas categorizadas como :
4 DDoS Attack
5 FTP Brute-Force
6 Ping of Death
7 Phishing
8 Fraud VoIP
9 Open Proxy
10 Web Spam
11 Email Spam
12 Blog Spam
13 VPN IP
14 Port Scan
15 Hacking
16 SQL Injection
17 Spoofing
18 Brute-Force
19 Bad Web Bot
20 Exploited Host
21 Web App Attack
22 SSH
23 IoT Targeted
Para utilizar el API de este recurso deberá registrarse y obtener una API KEY que posteriormente nos será de mucha utilidad en la respuesta reactiva que debemos desencadenar si comprobamos que la IP cliente se encuentra en esta BB.DD.
Valentin Secades ha desarrollado un wrapper que podrás localizar en http://pipy o en https://github.com/vsecades/AbuseIpDb/ para PYTHON 2.7 y explica detalladamente su uso, para que de forma automática, puedas obtener los datos de cualquier IP que consultes.
En el caso de mis proyectos, todos han sido migrados a PYTHON 3 y sólo desarrollamos proyectos en esta versión, por lo que, una vez obtenido el código creado por Valentín Secades lo he adaptado para PYTHON 3 realizando muy pocos cambios (abuseipdb.py):
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
codeauthor:: Valentin Secades
check_ip
abuseipdb.check_ip(ip="[IP]",days="[DAYS]")
check_cidr
abuseipdb.check_cidr(cidr="[CIDR]",days="[DAYS]")
report_ip
abuseipdb.report_ip(categories="[CATEGORIES]", comment="[OPTIONAL COMMENT]", ip="[IP]")
Field Required Default Example Description
[IP] Y NA 8.8.8.8 IPv4 Address
[DAYS] N 30 30 Check for IP Reports in the last 30 days.
[CIDR] Y NA 207.126.144.0/20 IPv4 Address Block in CIDR notation
[CATEGORIES] Y NA 10,12,15 Comma delineated list of category IDs
[OPTIONAL COMMENT] N NA This is a comment. Describe the type of malicious activity
[API KEY] Y NA Tzmp1...quWvaiO Your API key.
"""
import requests
class Parameters():
configuration = {}
url_templates = {
"check_ip" : "https://www.abuseipdb.com/check/[IP]/json?key=[API_KEY]&days=[DAYS]",
"check_cidr" : "https://www.abuseipdb.com/check-block/json?key=[API_KEY]&network=[CIDR]&days=[DAYS]",
"report_ip" : "https://www.abuseipdb.com/report/json?key=[API_KEY]&category=[CATEGORIES]&comment=[COMMENT]&ip=[IP]",
}
defaults = {
"days" : "30"
}
@staticmethod
def get_config():
return Parameters.configuration
@staticmethod
def set_config(config):
Parameters.configuration = Parameters.dict_merge([Parameters.configuration, config])
@staticmethod
def merge_recursive(source, destination):
"""
:rtype: dict
"""
for key, value in source.items():
if isinstance(value, dict):
# get node or create one
node = destination.setdefault(key, {})
Parameters.merge_recursive(value, node)
else:
destination[key] = value
return destination
# taken from https://stackoverflow.com/questions/20656135/python-deep-merge-dictionary-data using recursion
@staticmethod
def dict_merge(list_dicts=[]):
# print("List received: ")
# pp = pprint.PrettyPrinter(indent=4)
# pp.pprint(list_dicts)
# Merge multiple dicts
target = {}
while len(list_dicts) > 0:
temp_dict = list_dicts.pop()
# pp.pprint(temp_dict)
target = Parameters.merge_recursive(target, temp_dict)
# pp.pprint(target)
return target
def configure_api_key(api_key):
#Check that api_key is not None OR that it has been set previously
if api_key is not None:
Parameters.set_config({"API_KEY": api_key})
else:
print("Api key cannot be blank")
def check_ip(ip=None,days=Parameters.defaults["days"]):
#used to check an IP for reports
if ip is not None:
request_url = Parameters.url_templates["check_ip"]
request_url = request_url.replace("[IP]",ip)
request_url = request_url.replace("[API_KEY]",Parameters.get_config()["API_KEY"])
request_url = request_url.replace("[DAYS]",days)
print(request_url)
response = requests.get(request_url)
# return raw for now, we will add decorators later on
return response.text
else:
print("ip is not defined")
return None
def check_cidr(cidr=None,days=Parameters.defaults["days"]):
# used to check an IP for reports
if cidr is not None:
request_url = Parameters.url_templates["check_cidr"]
request_url = request_url.replace("[CIDR]", cidr)
request_url = request_url.replace("[API_KEY]", Parameters.get_config()["API_KEY"])
request_url = request_url.replace("[DAYS]", days)
print(request_url)
response = requests.get(request_url)
# return raw for now, we will add decorators later on
return response.text
else:
print("CIDR is not defined")
return None
def report_ip(categories=None, comment="", ip=None):
# used to check an IP for reports
if ip is not None and categories is not None:
request_url = Parameters.url_templates["report_ip"]
request_url = request_url.replace("[IP]", ip)
request_url = request_url.replace("[API_KEY]", Parameters.get_config()["API_KEY"])
request_url = request_url.replace("[COMMENT]", comment)
request_url = request_url.replace("[CATEGORIES]", categories)
print(request_url)
response = requests.get(request_url)
# return raw for now, we will add decorators later on
return response.text
else:
print("ip is not defined")
return None
Ejemplo de cómo usar esta libreria :
import abuseipdb
import json
if __name__ == '__main__':
ip_addr = "77.95.35.23" # IP identificada en ataques
#ip_addr = "1.1.1.1" # IP NO identificada en ataques
abuseipdb.configure_api_key("API KEY")
rp =abuseipdb.check_ip(ip=ip_addr)
try:
print(type(rp).__name__)
json_rp = json.loads(rp)
if len(json_rp)>0:
if json_rp[0]['ip'] == ip_addr:
print(json_rp[0]['isWhitelisted'])
print(json_rp[0]['isoCode'])
print(rp)
except ValueError:
pass
Observa que el parámetro que nos indicará si es una IP identificada en procesos de faude o ataques nos los indicará el parámetro 'isWhitelisted' (False para IPs ATACANTES y True para IPs no registradas en ABUSEIPDB), el parámetro 'isoCode' solo nos servirá como referencia del país al que pertenece la IP. Integrar este proceso en su desarrollo web no será muy complicado y podrá redirigir la solicitud a una página de error o a un punto muerto donde no exista posibilidad de continuar con un ataque.
Todo el código y ejemplo están disponibles en https://github.com/JAVTAMVI/AbuseIpDb3
Fiel a nuestra política de publicar artículos prácticos y sencillos, espero que le ayude a enfrentarse a situaciones de ataque.