Translate

domingo, 30 de septiembre de 2018

Ataques web y cómo gestionarlos

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.