解决 Button 组件的禁用属性被开发者工具手动删除后,从而造成点击事件被恶意触发的现象

对于 Button 按钮组件,BFUI 提供了一个 disabled 参数(布尔值)来定义该按钮是否被禁用。

当该参数为 true 时,会将 disabled 属性添加到原生 button 标签上,使该按钮点击时不执行绑定函数。

发现问题

但是,有一个很容易忽视的问题,我举例演示一下:

1
2
3
4
5
6
7
8
9
10
11
12
<template>
<bf-button @click="onClick" disabled>点击执行</bf-button>
</template>

<script setup lang="ts">\
import { BfButton } from '@bf-teams/bfui-vue';

// methods
const onClick = () => {
console.log('执行成功!')
}
</script>

打开控制台,由于该按钮是禁用状态,点击按钮是不执行该绑定函数的。

但是,现在我使用开发者工具将该 button 按钮元素节点的 disabled 属性手动删除,会发生什么?

你会发现,此时点击却能执行按钮上所绑定的点击事件,在控制台会打印出“执行成功!”这几个字。

这意味着什么不言而喻,这意味着如果浏览者会使用开发者工具操纵页面元素,那么该按钮组件的禁用属性形同虚设。按钮上绑定的点击事件也会有被恶意触发的风险。


分析问题

根据 Vue 官方文档 可知,click 监听器会被添加到 <bf-button> 的根元素,即那个原生的 <button> 元素之上。当原生的 <button> 被点击,会触发父组件的 onClick 方法。同样的,如果原生 button 元素自身也通过 v-on 绑定了一个事件监听器,则这个监听器和从父组件继承的监听器都会被触发。

因此,之所以会发上这种情况,是因为 Vue 在事件处理上进行了事件委托,事件监听放到了原生 button 本身。所以通过开发者工具删去元素的 disable 属性后,就会导致该按钮所绑定的监听事件重新变为可触发状态。

那么如何解决呢?


解决问题

1. 组件库使用者

我不知道其他组件库是否处理了这种情况,但是既然发现了这种隐患,那么在此我提醒所有前端开发的小伙伴,在使用组件库进行开发时,按钮所绑定的函数执行时一定要在前端或后端再次判断用户权限,确认无误后再执行对应的业务逻辑,防止被恶意造成无法逆转的损失。

2. 组件库开发者

我作为 BFUI 组件库的开发者,如果想从组件源码的角度优化这个“漏洞”,可以在 Button 组件源码的监听事件中加一层判断,当 props 中传入的 disabled 值不为 true 的时候,才使用 $emit() 抛出点击事件

  • 比如之前 Button 组件的相关源码为:

    1
    2
    3
    4
    5
    6
    7
    8
    // emit
    const emit = defineEmits(['click'])

    // methods
    const onClick = () => {
    // 抛出 click 事件
    emit('click')
    }
  • 现在修改为:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // emit
    const emit = defineEmits(['click'])

    // methods
    const onClick = () => {
    // 当按钮处于非禁用状态时,才抛出点击事件
    if (!props.disabled) {
    emit('click')
    }
    }

现在开头演示的那种情况就迎刃而解了,即便在浏览器开发者工具中删除了原生 button 节点的 disable 属性,也不会触发父组件绑定的点击事件,因为 <bf-button> 组件就没有抛出 click 事件。因此,当然使用组件时 <bf-button @click="onClick" disabled>点击执行</bf-button> 绑定的点击事件也就不会执行了。