关于Java对接网络验证+实践小例子,简单易懂

一个简单的网络验证小例子,各位大佬勿喷

        突发奇想,如果一位A友找你拿一份 Working Fruits,但是你不想这位A友把你辛苦劳作、熬夜加点写出的代码分享他或她的另外一位朋友B友,也许并不是很有价值的一个小作业而已,但是就像我一样,多多少少有着私心的幼稚心理。这种想法就像你下载一个收费软件一样,所属权是你,需要授权码或者特定的方式得到你的允许,才能够运行整体代码。当然,不要破环人与人之间的关系或情感,学习为本(说笑了),教程只提供参考。 


目录

一. 预备知识点

二. 常见的网络验证   

三. 微验验证原理

四. 代码实现

五. 缺陷与优化


一. 预备知识点

        我们需要了解MD5和RC4加密原理。MD5是一种常用的哈希算法,它可以将任意长度的数据转换为固定长度的哈希值。通过对比哈希值,我们可以验证数据的完整性和一致性。而RC4是一种流密码算法,它可以根据密钥生成伪随机流,用于对数据进行加密和解密。通过使用MD5和RC4加密算法,我们可以确保在网络传输过程中的数据安全性。

        其次,我们需要了解Java反射。Java反射是一种强大的机制,它允许我们在运行时动态地获取类的信息并操作类的成员。在网络验证中,我们可以利用Java反射机制来动态加载和调用验证相关的类和方法(写好了就包装成一个JAR吧),从而实现灵活的验证逻辑。

        当然,网络验证的实现涉及到更多的知识和技术,比如数据库的构建和管理,有自己的服务器自己管理数据,自主随时管理数据,但是表数据的增删改查操作会产生更多的工作量。这些都是我们在实际开发中需要考虑的问题,需要具备相应的知识储备和技能因此,我们不如简单点,用别人写好的验证系统,直接拿来用不就是了,代码越简单越好对吧

        在实际的网络验证中,我们可以借助已有的对接API来实现本地的验证。这意味着我们可以选择市面上已有的验证服务或库,并通过网络接口进行数据传输和验证。通过使用这些对接API,我们可以简化验证的实现过程,提高开发效率。      

二. 常见的网络验证   

        在网络验证领域中,可以找到一些常见的验证案例,如T3、BS、易游、微验、大纸片等验证系统。这些系统各有特点,其中T3验证系统相对容易被破解,易游验证系统在外观上更加简单,但内部却更为复杂。考虑到教程的讲解需要,我们选择使用微验验证管理系统来进行讲解。

        微验验证管理系统以其独特的特点和功能而备受易语言开发者关注。它提供了一种简单而高效的验证解决方案,适用于各种场景和需求。通过微验验证管理系统,确保验证的安全性和可靠性。

        相比于其他验证系统,微验验证管理系统在设计上更加注重用户体验和易用性。它采用了简化的外观设计,使用户能够快速上手并进行验证操作。同时,微验验证管理系统内部的复杂性也为用户提供了更多的灵活性和定制化选项。

        本教程将重点介绍如何使用微验验证管理系统进行验证操作。通过详细的讲解和示例,本教程将帮助自身了解验证的基本原理和操作步骤。读者可以学习如何配置和管理微验验证系统,以及如何应用验证功能到项目中。

三. 微验验证原理

        先不管加密如何加密,解密如何解密,搞清楚这个验证流程,话不多说,看图。

四. 代码实现

        官方提供的Java对接例子只有不能就地运行、同时客户端不具有安卓特定的imei码,否则验证无法过签名,需要实际开发打包成APP才可使用,因此,我二改了官方提供的代码,可以就地运行。

        微验官方已经写好的rc4加密解密方法,可直接使用

        需要具体看懂吗,不需要,只需要明白每个方法的作用,具体怎么实现的不重要,我还是更喜欢面向对象

        RC4加密算法工具类详解

  1. encryRC4String方法:将给定的字符串数据使用RC4算法进行加密,并返回加密后的十六进制字符串形式。参数包括待加密的数据、密钥和字符集。

  2. encryRC4Byte方法:将给定的字符串数据使用RC4算法进行加密,并返回加密后的字节数组形式。参数包括待加密的数据、密钥和字符集。

  3. decryRC4方法:将给定的十六进制字符串数据使用RC4算法进行解密,并返回解密后的字符串形式。参数包括待解密的数据、密钥和字符集。

  4. initKey方法:根据给定的密钥生成RC4算法所需的初始密钥。返回一个字节数组。

  5. bytesToHex方法:将字节数组转换为十六进制字符串形式。返回转换后的字符串。

  6. hexToByte方法:将十六进制字符串转换为字节数组形式。返回转换后的字节数组。

  7. RC4Base方法:根据给定的输入数据和密钥使用RC4算法进行加密或解密操作。返回加密或解密后的字节数组。

     属性KEK 特定的密钥,不同的密钥产生不同的结果,不可更改

        RC4工具类 

import java.io.UnsupportedEncodingException;

public class RC4Util {
    public static final String KEY = "PZ8KBd4TbE7mjEb";

    public RC4Util() {
    }

    public static String encryRC4String(String data, String key, String chartSet) throws UnsupportedEncodingException {
        return data != null && key != null ? bytesToHex(encryRC4Byte(data, key, chartSet)) : null;
    }

    public static byte[] encryRC4Byte(String data, String key, String chartSet) throws UnsupportedEncodingException {
        if (data != null && key != null) {
            byte[] bData;
            if (chartSet != null && !chartSet.isEmpty()) {
                bData = data.getBytes(chartSet);
                return RC4Base(bData, key);
            } else {
                bData = data.getBytes();
                return RC4Base(bData, key);
            }
        } else {
            return null;
        }
    }

    public static String decryRC4(String data, String key, String chartSet) throws UnsupportedEncodingException {
        return data != null && key != null ? new String(RC4Base(hexToByte(data), key), chartSet) : null;
    }

    private static byte[] initKey(String aKey) {
        byte[] bkey = aKey.getBytes();
        byte[] state = new byte[256];

        int index1;
        for(index1 = 0; index1 < 256; ++index1) {
            state[index1] = (byte)index1;
        }

        index1 = 0;
        int index2 = 0;
        if (bkey.length == 0) {
            return null;
        } else {
            for(int i = 0; i < 256; ++i) {
                index2 = (bkey[index1] & 255) + (state[i] & 255) + index2 & 255;
                byte tmp = state[i];
                state[i] = state[index2];
                state[index2] = tmp;
                index1 = (index1 + 1) % bkey.length;
            }

            return state;
        }
    }

    public static String bytesToHex(byte[] bytes) {
        StringBuffer sb = new StringBuffer();

        for(int i = 0; i < bytes.length; ++i) {
            String hex = Integer.toHexString(bytes[i] & 255);
            if (hex.length() < 2) {
                sb.append(0);
            }

            sb.append(hex);
        }

        return sb.toString();
    }

    public static byte[] hexToByte(String inHex) {
        int hexlen = inHex.length();
        byte[] result;
        if (hexlen % 2 == 1) {
            ++hexlen;
            result = new byte[hexlen / 2];
            inHex = "0" + inHex;
        } else {
            result = new byte[hexlen / 2];
        }

        int j = 0;

        for(int i = 0; i < hexlen; i += 2) {
            result[j] = (byte)Integer.parseInt(inHex.substring(i, i + 2), 16);
            ++j;
        }

        return result;
    }

    private static byte[] RC4Base(byte[] input, String mKkey) {
        int x = 0;
        int y = 0;
        byte[] key = initKey(mKkey);
        byte[] result = new byte[input.length];

        for(int i = 0; i < input.length; ++i) {
            x = x + 1 & 255;
            y = (key[x] & 255) + y & 255;
            byte tmp = key[x];
            key[x] = key[y];
            key[y] = tmp;
            int xorIndex = (key[x] & 255) + (key[y] & 255) & 255;
            result[i] = (byte)(input[i] ^ key[xorIndex]);
        }

        return result;
    }
}

        接下来是通过官方提供的加密工具类自主写的对接例子类,可以通过上文中的验证流程图共同参考。

        WeiYan对接类

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.URL;
import java.net.URLConnection;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Enumeration;
import java.util.Random;

//TODO:Benmao

public class WeiYan {
    String kami;//卡密
    public String markcode;//设备码
    public long time;//时间戳//Long time = System.currentTimeMillis()
    public String appKey="57012";//不可更改
    //"kami="+卡密+"&markcode="+设备码+"&t="+时间戳+"&"+sss.APPKEY
    public String data;
    public String SIGN;//通过md5加密
    public int random;//随机数,范围[1000, 9999]

    public String url="https://wy.llua.cn/api/?id=kmlogon"+"&app="+this.appKey+"&data=";

    //加密字段MD5
    public void Gm(String kami){
        this.kami=kami;
        this.time=System.currentTimeMillis()/1000;//Long.parseLong(String.valueOf(System.currentTimeMillis()).substring(0 ,10))

        this.markcode=getDeviceID();//getDeviceID();
        //需要加密的字段
        String str="kami="+this.kami+"&markcode="+this.markcode+"&t="+this.time+"&"+this.appKey;
        this.SIGN = stringToMD5(str);//encodeMD5(str);
    }

    //Rce4字段加密
    public void GD(){
        //随机数
        this.random=new Random().nextInt(99999)+1000;//范围1000~9999
        //需要加密的字段
        String str="kami="+this.kami+"&markcode="+this.markcode+"&t="+this.time+"&sign="+this.SIGN+"&value"+this.time+this.random;
        try {
            this.data=RC4Util.encryRC4String(str, RC4Util.KEY, "UTF-8");
            url+=this.data;
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }

    //返回数据解密
    public String deRec4(String anUrl){
        //String anUrl = "https://wy.llua.cn/api/?id=kmlogon&app=57012&data=4a5311e1cf22abb6c079de314f7f7ca9670658e0d306b87a9ab62f560e75ec31cdb0598abc2df00063003484e229ee81d0e07daf64b6d8a4cd190835bdf0c8bbd329b901888296a9a376c9bd73e62f56bce31982e072a38f8fb1fc261d43ce7231edf7c7a883bfec92c47475f0a07e3045161fcc10e5";
        URL url = null;
        String res ="";//最终结果
        try {
            url = new URL(anUrl);
            URLConnection conn = url.openConnection();
            BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String inputLine;
            StringBuilder result = new StringBuilder();
            while ((inputLine = in.readLine()) != null) {
                result.append(inputLine);
            }
            //System.out.println(result);//加密前的字段
            res=result.toString();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        //解码
        try {
            String json = RC4Util.decryRC4(res, RC4Util.KEY, "UTF-8");
            return json;
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }


    //MD5加密
    public static String encodeMD5(String str)
    {
        try
        {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            md5.update(str.getBytes("UTF-8"));
            byte messageDigest[] = md5.digest();
            StringBuilder hexString = new StringBuilder();
            for (byte b : messageDigest)
            {
                hexString.append(String.format("%02X", b));
            }
            return hexString.toString().toLowerCase();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return "";
    }

    //iApp Md5加密
    public static String stringToMD5(String plainText)
    {
        byte[] secretBytes = new byte[0];
        try {
            secretBytes = MessageDigest.getInstance("md5").digest(plainText.getBytes());
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
        String md5code = new BigInteger(1, secretBytes).toString(16);
        for(int i = 0; i < 32 - md5code.length(); i++)
        {
            md5code = "0" + md5code;
        }
        return md5code;
    }

    //获取独立设备码
    public static String getDeviceID() {
        try {
            Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
            while (networkInterfaces.hasMoreElements()) {
                NetworkInterface networkInterface = networkInterfaces.nextElement();
                byte[] mac = networkInterface.getHardwareAddress();
                if (mac != null) {
                    StringBuilder sb = new StringBuilder();
                    for (byte b : mac) {
                        sb.append(String.format("%02X", b));
                    }
                    return sb.toString().toLowerCase();
                }
            }
        } catch (SocketException e) {
            e.printStackTrace();
        }
        return null;
    }
}

RC4加密算法工具类详解 

  1. Gm方法:对卡密进行加密处理,生成设备码和时间戳,并计算签名。参数为卡密。

  2. GD方法:对需要加密的字段进行RC4加密,并生成随机数。参数为卡密。

  3. deRec4方法:对返回的数据进行解密处理。参数为需要解密的URL。

  4. encodeMD5方法:对字符串进行MD5加密处理。参数为待加密的字符串。

  5. stringToMD5方法:对字符串进行MD5加密处理,并返回加密后的结果。参数为待加密的字符串。

  6. getDeviceID方法:获取设备的唯一标识码。

  7. kami(卡密)、markcode(设备码)、time(时间戳)、appKey(应用密钥)、data(加密后的数据)、SIGN(签名)、random(随机数)和url(请求的URL)。

    public String getKami() {
        return kami;
    }

    public void setKami(String kami) {
        this.kami = kami;
    }

    public String getMarkcode() {
        return markcode;
    }

    public void setMarkcode(String markcode) {
        this.markcode = markcode;
    }

    public long getTime() {
        return time;
    }

    public void setTime(long time) {
        this.time = time;
    }

    public String getAppKey() {
        return appKey;
    }

    public void setAppKey(String appKey) {
        this.appKey = appKey;
    }

    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }

    public String getSIGN() {
        return SIGN;
    }

    public void setSIGN(String SIGN) {
        this.SIGN = SIGN;
    }

    public int getRandom() {
        return random;
    }

    public void setRandom(int random) {
        this.random = random;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

        接下来就是写一个验证例子。上述代码编译成一个jar包,然后使用反射调用其内部方法

         Main类

/**
 * @作者:笨猫
 * @create: 2024-03-16 14:52
 **/
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class main {
    public static void main(String[] args) {
        String kami = "Benmao2127FC";//这个就是卡密

        try {
            // 反射调用 WeiYan()构造方法,输出this.url
            Class<?> weiYanClass = Class.forName("top.benmao.rc4.WeiYan");
            Constructor<?> weiYanConstructor = weiYanClass.getConstructor();
            Object weiYanObject = weiYanConstructor.newInstance();
            Method getUrlMethod = weiYanClass.getDeclaredMethod("getUrl");
            getUrlMethod.setAccessible(true);
            String url = (String) getUrlMethod.invoke(weiYanObject);
            System.out.println("this.url: " + url);

            // 反射调用Gm方法,并输出属性this.SIGN
            Method gmMethod = weiYanClass.getDeclaredMethod("Gm", String.class);
            gmMethod.setAccessible(true);
            gmMethod.invoke(weiYanObject, kami);
            String sign = (String) weiYanClass.getField("SIGN").get(weiYanObject);
            System.out.println("this.SIGN: " + sign);

            // 反射调用GD方法,再次输出this.url
            Method gdMethod = weiYanClass.getDeclaredMethod("GD");
            gdMethod.setAccessible(true);
            gdMethod.invoke(weiYanObject);
            url = (String) getUrlMethod.invoke(weiYanObject);
            System.out.println("this.url: " + url);

            // 反射调用deRec4()方法,获取返回值并输出
            Method deRec4Method = weiYanClass.getDeclaredMethod("deRec4", String.class);
            deRec4Method.setAccessible(true);
            String result = (String) deRec4Method.invoke(weiYanObject, url);
            System.out.println("Result: " + result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

        运行结果

        只需要把获取的结果JSON后进入校验即可,剩下的就看自己怎么运用吧。

五. 缺陷与优化

        想说的是,比起官方提供的代码,就地运行只需要懂一点点Java语言,有可能解密就只是一个变量的事情,如果需要更加安全、高效、易处理的工作方式,可以继续尝试包装成一个apk并选择各大官方的加固平台进行加固,如360加固。

        本次教程结束了,感兴趣的可以关注我,如有与本博客持有不同的看法或评判,请随时留意吧。

  • 30
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论
1.安装 上传源码到网站目录,设置网站目录为源码二级目录public,很多虚拟主机不支持此设置 伪静态,源码默认包含了apache的伪静态规则,但很多情况下还需要自己设置,请百度对应对应的设置方法,例如Nginx thinkphp5伪静态设置,如果您使用的宝塔,那么在网站伪静态里面设置一下即可。如果伪静态没有设置好,会出现资源文件找不到,图片脚本等都404等情况。 2.配置 由于前期准备给自己用的,偷懒了很多情况,一些配置直接在\application\config.php中,所有请打开文件修改配置 3.邮箱服务器配置,注册,找回密码,购卡等操作需要用到邮箱发信 请在配置文件中找到mail节点设置smtp服务器账号和密码 如 'mail' => [ 'server'=>'smtp.qq.com', 'acount' => 'q214783030@qq.com', 'password' => '' 密码不是qq密码 ] 4.此版本更新安全,有用到openssl的rsa加密。需要配置openssl.cnf的路径,请在配置文件中修改 如:'opensslConf'=> 'D:\BtSoft\WebSoft\apache\conf\openssl.cnf' 此文件一般在你的apache配置文件夹中 5.支付,如果您想使用验证的自动发卡功能,官方默认支持两种对接方式 1.微信原生支付,需要签约商户,微信支付配置文件vendor/wxpay/WxPay.Config.php 绑定支付的APPIDGet AppId() 商户号 GetMerchantId()商户支付密钥 GetKey() 2.码支付,默认qq和支付宝使用码支付对接,需要挂监听软件,码支付官网https://codepay.fateqq.com/ 6.开启Workerman,这是一个socket库,这次的版本添加了websocket心跳方式,开启的好处是即时心跳,比如秒t下线,即时消息,群发消息,另外带个定时器,每个6分钟自动执行一次清理异常掉线未发退出登录通知服务器的用户,如果不开启,会出现很多麻烦,使用方法,双击打开源码目录下的start_for_win.bat,并保持cmd窗口打开,此功能仅在windows下测试过,linux大同小异主要执行php start_register.php start_gateway.php start_businessworker.php 如果正常运行您可以看到3个工作ok yzGateway Register yzBusinessWorker,可能出现的问题,找不到php命令,把php.exe加入到环境变量即可,如果使用websocket心跳的话,单机最大可能只有1000左右连接 7.必须开启openssl扩展 安装可能出现的问题 1.数据库连接不上,如果您确认数据库账号密码是正确的却连接不上,可以手动导入sql文件,文件路径/public/install/test.sql,导入成功后需要在application/database.php中配置您的库信息 2.安装时候环境监测有可能有点问题,不想整了,自己确定就行 遇到其它问题加群 365011408 提问即可 遇到返回数据未解密,用模块源码取调试 调用例子群文件获取,官网对接看这里 必须要开启Workerman 心跳处理,2种心跳方式,一种web定时心跳,一种socket主动发送

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Benmao⁢

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值