Android端如何简单的防黑产

简介: apk的混淆加固,相关密钥的安全存储,以及接口的加密,都是我们加深App安全的操作,也是进一步加深黑产用户的破解难度,对于数据的流失,防黑产,一般都是和接口挂钩,大部分也都是服务端需要考虑的,毕竟交互的最终结果都是传到服务端,无非前端做一些配合服务端的事情。

如何防止薅羊毛,一直是App头疼且需要注意的问题,前端能做到真正的防黑产吗?答案是否定的,也就是说,通过前台,我们是无法知道当前用户是否是真实用户的,毕竟Android是不安全的,可以模拟用户的一系列操作手势,也可以通过抓取相应的接口,模拟相应的请求,一个黑产想要达到他想要的目的,无论程序再安全,也无非是破解难度的问题。


apk的混淆加固,相关密钥的安全存储,以及接口的加密,都是我们加深App安全的操作,也是进一步加深黑产用户的破解难度,对于数据的流失,防黑产,一般都是和接口挂钩,大部分也都是服务端需要考虑的,毕竟交互的最终结果都是传到服务端,无非前端做一些配合服务端的事情。


那么除了以上的相关处理,前端是否还有其他的简单逻辑,告知服务端,当前用户是否是真实用户呢?当然是可以的,说好了,只能是简单,纯粹的简单,不参杂一丁点的复杂思想。实现思路,其实就是针对项目中的用户最常用行为轨迹,进行埋点统计,告知服务端,这种方式只能简单的进行统计,主观意识上认为它是真实用户,并不能做到百分百,但也能起到一定的作用,比如可以定位那些暴力的刷接口行为,通过这种方式,我们就可以避免这种行为。


一个项目中的功能有很多,比如电商中的购物,及时通讯中的聊天等等,针对不同的App,肯定有用户最常用的功能,这就是大概率的用户习惯,针对这些用户习惯,我们可以设计相对应的路径,也就是用户,通过哪些事件后,进入到了最后的功能,比如购物,用户触发了商品列表,点击了商品后进入到商品详情,然后点击购买,最后发起了支付,这就是一个路径,我们可以成为是一个事件链。


事件的统计方式:


一个事件链,从开始到结束,可能有很多事件,但每一个事件链是唯一的,如下图的事件链ABC,记录好定义的事件链,就可以针对当前事件链,进行逐个事件统计,如下图中的123,到end结束,end为当前事件链结束的标识,得到结束的标识后,就得到了一个用户的执行流程,就可以上报到服务端。


image.png


举例(登录操作),定义事件链为login:


打开应用-->点击我的-->立即加入-->输入手机号-->输入验证码-->点击登录-->登录成功

以上是登录从开始到结束的整个事件链流程,针对每一个事件进行存储,除最后一个事件是end标识,前边的都为存储类型,当执行到end类型后就可以上报此事件链。

事件链的上传结果,包含用户的id,各个事件的触发标识。


具体实现:


基本的逻辑就是如上,代码也不复杂,总共可以分为三个方面,第一个是事件的统计,其实和埋点的思路一致,第二个是,针对事件链或者事件的存储,第三个就是事件的上传。


classBlackProductionUtils {
privatevalmPreferences="vipBlack"privatevalmSpEvent="spEvent"privatevarmSp: SharedPreferences?=nullprivatevarmOnce: Boolean=false//全局单次上传,所有事件链只上报一次companionobject {
@JvmStaticprivatevarinstance: BlackProductionUtils?=nullget() {
if (field==null) {
field=BlackProductionUtils()
                }
returnfield            }
@JvmStaticfunget(): BlackProductionUtils {
returninstance!!        }
    }
/*** AUTHOR:AbnerMing* INTRODUCE:once:是否一个事件链只执行一次*/funinit(context: Context, once: Boolean=false) {
mOnce=oncemSp=context.getSharedPreferences(mPreferences, 0)
    }
/*** AUTHOR:AbnerMing* INTRODUCE:添加事件,key为事件链标识,position为事件索引,* start是事件开始,end是结束事件的标识*/funaddEvent(
key: String, position: Int,
start: Boolean=false,
end: Boolean=false    ) {
try {
//首先判断是否单次上报,如果是,取出标识,存在就中断执行if (mOnce&&getString(mSpEvent).contains(key)) {
return            }
if (start) {
//进行清空事件,从新开始put(key, "")
            }
//首先获取vareventData=getString(key)
if (!TextUtils.isEmpty(eventData)) {
//证明存在数据eventData+=containsPosition(eventData, position)
            } else {
//证明不存在eventData=position.toString()
            }
if (end) {
//结束,进行上报此事件uploadEvent(key, eventData)
            } else {
//无结束put(key, eventData)
            }
        } catch (e: Exception) {
e.printStackTrace()
        }
    }
/*** AUTHOR:AbnerMing* INTRODUCE:是否包含*/privatefuncontainsPosition(eventData: String, position: Int): String {
valp=position.toString()
returnif (!eventData.contains(p)) {
p        } else {
""        }
    }
/*** AUTHOR:AbnerMing* INTRODUCE:上报事件,key:事件链标识,eventData:一个事件链的所有事件*/privatefunuploadEvent(key: String, eventData: String) {
valspEvent=getString(mSpEvent)
if (mOnce) {
if (!spEvent.contains(key)) {
addSpKey(key)
//单次进行上传reportEvent(key, eventData)
            }
        } else {
//每次进行上传reportEvent(key, eventData)
        }
    }
/*** AUTHOR:AbnerMing* INTRODUCE:走接口,统一上报*/privatefunreportEvent(key: String, eventData: String) {
    }
/*** AUTHOR:AbnerMing* INTRODUCE:保存事件链Key*/privatefunaddSpKey(key: String) {
//记录每一个事件链标识varspKey=getString(mSpEvent)
spKey+=keyput(mSpEvent, spKey)
    }
privatefunput(key: String, value: String) {
try {
mSp!!.edit().putString(key, value).commit()
        } catch (e: Exception) {
e.printStackTrace()
        }
    }
privatefungetString(key: String, defaultVal: String=""): String {
varmValue=""mSp?.let {
mValue=it.getString(key, defaultVal)!!        }
returnmValue    }
/*** AUTHOR:AbnerMing* INTRODUCE:清除所有的事件*/funclearEvent() {
mSp?.let {
it.edit().clear().commit()
        }
    }
}


调用


1、初始化

默认每次事件链执行完都上传


BlackProductionUtils.get().init(this)


一个事件链只上传一次


BlackProductionUtils.get().init(this,true)


2、添加事件


默认false,不清除原有事件,true为每次事件开始时,都会从新记录事件,具体情况,比如当前事件链有10个事件,用户触发了前5个,后面不走了,隔了一段时间又从事件1开始了,之前存储的事件,清除还是保存,就是这个意思。


事件开始


BlackProductionUtils.get().addEvent("main", 0, true)


正常的事件存储,实际会有多个


BlackProductionUtils.get().addEvent("main", 1)


事件结束


BlackProductionUtils.get().addEvent("main", 3, end=true)


告知服务端只需在reportEvent方法里写请求逻辑即可。


相关的逻辑就是如上代码,可以根据自己项目的存储方式,或者其他逻辑进行更改。大家可以简单的认为就是埋点,然后进行上报服务端,服务端会根据每个用户上报的事件链,来进行统计分析。


防黑产,以上的方式,开头已经陈述,并不能做到百分百,通过多个事件链,但也能够有效的过滤一些非真实用户,当然了,具体情况具体分析,你说它有意义,它就存在意义,若没意义,其实也没任何意义。

相关文章
|
Web App开发 小程序 iOS开发
Fiddler - 抓包手机App、微信小程序等网络请求
Fiddler - 抓包手机App、微信小程序等网络请求
1046 0
Fiddler - 抓包手机App、微信小程序等网络请求
|
2月前
|
XML API 网络安全
【安卓】在安卓中使用HTTP协议的最佳实践
【安卓】在安卓中使用HTTP协议的最佳实践
53 4
|
3月前
|
XML JSON Java
Android App开发即时通信中通过SocketIO在客户端与服务端间传输文本和图片的讲解及实战(超详细 附源码)
Android App开发即时通信中通过SocketIO在客户端与服务端间传输文本和图片的讲解及实战(超详细 附源码)
233 0
|
3月前
|
XML Java 定位技术
Android Studio App开发之网络通信中使用GET方式调用HTTP接口的讲解及实战(附源码 超详细必看)
Android Studio App开发之网络通信中使用GET方式调用HTTP接口的讲解及实战(附源码 超详细必看)
221 0
|
缓存 Android开发
【开发一个简单的音乐播放器+服务端】【二】
【开发一个简单的音乐播放器+服务端】【二】
82 0
|
JSON Java 数据库连接
【开发一个简单的音乐播放器+服务端】【一】
【开发一个简单的音乐播放器+服务端】【一】
126 0
|
Web App开发 API
chrome插件的通讯
chrome插件的通讯
|
Java Android开发 数据安全/隐私保护