美文网首页
防刷验证

防刷验证

作者: yuanzicheng | 来源:发表于2018-09-07 00:10 被阅读52次

1.“问题-答案”模式的图片验证

常见的图片验证有字母数字组合简单算术题简单选择题等等,这种类型的验证码的可行性在于人类能够轻松识别、判断,而机器比较难区分,但随着人工智能和机器学习的不断发展,这类验证码越来越容易破解了,不过生成图片的时候做一定程度的干扰(比如字符重叠、增加干扰线条、使用非纯色背景、甚至采用gif)可以加大破解成本。

1.1 工作流程(以登录验证为例,其它业务场景同样适用)

1.进入登录页,客户端向服务端发送预登录请求;

2.服务端生成随机字符串verify_code(通常为字母+数字组合),并以字符串为内容生成图片verify_image,同时创建一个唯一的verify_key与字符串绑定在服务端存储(可以设置有效期),将verify_imageverify_key一并作为预登录的响应结果返回客户端;

3.用户登录,客户端向服务端发送登录请求,以用户输入的账号、密码、验证码input_code以及预登录请求得到verify_key作为请求参数;

4.服务端接收登录请求后检查参数是否完整,若参数完整,则根据verify_key获取存储的verify_codeinput_code进行比较(无论是否一致均删除此条记录,保证一个验证码只能验证一次),完全一致则继续执行账号、密码验证,否则直接登录失败。

1.2 代码实现

VerifyCode.kt (服务端生成图片)

import java.awt.BasicStroke
import java.awt.Color
import java.awt.Font
import java.awt.Graphics2D
import java.awt.image.BufferedImage
import java.io.File
import java.io.IOException
import java.io.OutputStream
import java.util.Random

import javax.imageio.ImageIO
import javax.imageio.stream.FileImageOutputStream

/**
 * 验证码工具类
 * 代码来自 https://blog.csdn.net/yangxuwang888/article/details/81431705
 */
class VerifyCode {
    private val w = 70
    private val h = 35
    private val r = Random()
    // {"宋体", "华文楷体", "黑体", "华文新魏", "华文隶书", "微软雅黑", "楷体_GB2312"}
    private val fontNames = arrayOf("宋体", "华文楷体", "黑体", "微软雅黑", "楷体_GB2312")
    private val codes = "23456789abcdefghjkmnopqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ"
    private val bgColor = Color(255, 255, 255)

    // 向图片中画4个字符
    /**
     * 首字符的基线位于用户空间的 (x, h-5) 位置处
     * 原点在左上角,X轴递增的方向是从左向右;Y轴是从上到下
     * 在提供的坐标位于基线上最左边字符的情况下,可以从右到左呈现字形
     * h-5表示y轴方向,向上偏移了5
     */
    val image: BufferedImage
        get() {
            val image = createImage()
            val g2 = image.graphics as Graphics2D
            val sb = StringBuilder()
            for (i in 0..3) {
                val s = randomChar() + ""
                sb.append(s)
                val x = i.toFloat() * 1.0f * w.toFloat() / 4
                g2.font = randomFont()
                g2.color = randomColor()
                g2.drawString(s, x, (h - 5).toFloat())
            }
            text = sb.toString()
            drawLine(image)
            return image
        }

    private fun randomColor(): Color {
        val red = r.nextInt(150)
        val green = r.nextInt(150)
        val blue = r.nextInt(150)
        return Color(red, green, blue)
    }

    private fun randomFont(): Font {
        val index = r.nextInt(fontNames.size)
        val fontName = fontNames[index]
        val style = r.nextInt(4)
        val size = r.nextInt(5) + 24
        return Font(fontName, style, size)//指定字体名称、样式和点大小,创建一个新 Font。
    }

    //画干扰的线条
    private fun drawLine(image: BufferedImage) {
        val num = 3//画三条
        val g2 = image.graphics as Graphics2D
        for (i in 0 until num) {
            val x1 = r.nextInt(w)
            val y1 = r.nextInt(h)
            val x2 = r.nextInt(w)
            val y2 = r.nextInt(h)
            g2.stroke = BasicStroke(1.5f)
            g2.color = Color.BLUE
            g2.drawLine(x1, y1, x2, y2)
        }
    }

    private fun randomChar(): Char {
        val index = r.nextInt(codes.length)
        return codes[index]
    }

    private fun createImage(): BufferedImage {
        val image = BufferedImage(w, h, BufferedImage.TYPE_INT_RGB)
        val g2 = image.graphics as Graphics2D
        g2.color = this.bgColor
        g2.fillRect(0, 0, w, h)
        return image
    }

    companion object {
        var text: String? = null

        @Throws(IOException::class)
        fun output(image: BufferedImage, out: OutputStream) {
            ImageIO.write(image, "JPEG", out)
        }
    }
}

/*
fun main(args: Array<String>) {
    for (i in 1..10) {
        val code = VerifyCode()
        val image = code.image
        //获取图片
        ImageIO.write(image, "jpg", FileImageOutputStream(File("/tmp/$i.jpg")))
        //获取图片中的文字
        println(VerifyCode.text)
    }
}
*/

TestController.kt (基于SpringMVC实现的用于测试的API)

import org.springframework.beans.factory.annotation.Autowired
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RestController
import javax.imageio.ImageIO
import javax.servlet.http.HttpServletResponse
import sun.misc.BASE64Encoder
import java.io.ByteArrayOutputStream


@RestController
class TestController {

    @Autowired
    private lateinit var response: HttpServletResponse

    /**
     * 直接返回图片
     */
    @GetMapping("/test")
    fun test() {
        val code = VerifyCode()
        val image = code.image
        //获取图片
        ImageIO.write(image, "jpg", response.outputStream)
        //获取图片中的文字
        println(VerifyCode.text)
    }

    /**
     * 将图片base64编码返回
     */
    @GetMapping("/test2")
    fun test2(): String {
        val code = VerifyCode()
        val image = code.image
        val byteArrayOutputStream = ByteArrayOutputStream()//io流
        ImageIO.write(image, "jpg", byteArrayOutputStream)//写入流中
        val bytes = byteArrayOutputStream.toByteArray()//转换成字节
        val encoder = BASE64Encoder()
        var base64 = encoder.encodeBuffer(bytes).trim()//转换成base64串
        base64 = base64.replace("\n".toRegex(), "").replace("\r".toRegex(), "")//删除 \r\n
        return base64
    }
}

test.html (显示验证码的测试页面)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<img id="img" src="https://cdn2.jianshu.io/assets/web/nav-logo-4c7bbafe27adc892f3046e6978459bac.png"
     alt="" width="70" height="35"/>
</body>
<script>
    setTimeout(function () {
        document.getElementById("img").src = "data:image/jpg;base64,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"
    },2000)
</script>
</html>

其它逻辑按部就班实现起来没有什么花头,不再一一赘述。

2.利用验证行为的特征区分人机差异的行为验证

典型案例:极验验证码

「行为验证」不单纯基于“问题-答案”的模式来区别人机,而是基于完成验证过程中的行为模式和行为特征,通过深度学习对行为数据进行高维分析,构建人机边界。
摘自 https://docs.geetest.com/install/overview/prodes/

具体实现原理和交互逻辑可以查看极验官网。当然,极验行为验证的核心技术在于机器学习,这部分内容的实现在极验的后台,对使用者而言是不可见的。

3.其它验证

  • 淘宝使用过的选择你曾经购买过的商品图片...
  • 12306使用过的小朋友认图片(体验很差,被喷成狗屎)
  • ......

相关文章

  • 防刷验证

    1.“问题-答案”模式的图片验证 常见的图片验证有字母数字组合、简单算术题、简单选择题等等,这种类型的验证码的可行...

  • 短信验证码防刷

    常规手段 前端加一分钟倒计时(光加这个解决不了问题,可以抓包直接绕过去) 校验码(人机互动) 后端加时间,一分钟内...

  • python2.7搬运--->TensorFlow - 深

    谷歌的开源深度学习工具 --py 简介 验证码主要用于防刷,传统的验证码识别算法一般需要把验证码分割为单个字符,然...

  • 美洽新功能对话防刷

    对话防刷强势登陆 通过自定义规则和新对话开启验证,限制访客发起对话,帮助企业解决恶意刷对话的问题。 企业在正常推广...

  • 【VUE】vue+Verify实现防刷验证码验证

    因为公司要做防刷,所以要验证码功能,于是又在网上找,看了一圈都是需要收费的,最后同事找了一个纯前端的开源,免费的验...

  • 如何设计短信验证码防刷机制

    最近遇到一个关于防止短信验证码被刷的产品设计问题,后来在面试一个前来应聘JAVA开发的程序员的时候,他也提到了他以...

  • 金融风控中的账号安全

    标签: 反欺诈技术 账号风控主要包括以下几个方面 区分人机:识别垃圾注册 防刷:防刷评论,防刷下载,防刷人气 反黄...

  • 高并发架构设计要点(秒杀)

    页面请求静态化(CND) 较少对服务器请求压力 服务端防刷设计 弹出验证码,防止机器脚本请求; IP 过滤; 通过...

  • [刷题防痴呆] 0125 - 验证回文串 (Valid Pali

    题目地址 https://leetcode.com/problems/valid-palindrome/descr...

  • [刷题防痴呆] 0591 - 标签验证器 (Tag Valida

    题目地址 https://leetcode.com/problems/tag-validator/[https:/...

网友评论

      本文标题:防刷验证

      本文链接:https://www.haomeiwen.com/subject/iygfgftx.html