当前位置: 首页 > news >正文

[Spring Boot]登录密码三种加密方式

简述

介绍其三种密码加密方法
1.SM2加密与验签
2.随机密码盐加密
3.MD5加密
推荐使用方法1,其次使用方法2,最不推荐的是方法3。方法3极其容易被密码字典破解,如果项目进行安全测试,通常是不允许的加密方式。

SM2加密与验签

引入bcprov,以使用SM2加密。

        <dependency><groupId>org.bouncycastle</groupId><artifactId>bcprov-jdk15to18</artifactId><version>1.69</version></dependency>

工具类与测试方法

加密的主要工具类如下,其中带有测试的main方法。

import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.asn1.gm.GMObjectIdentifiers;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECParameterSpec;import java.security.*;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.Map;/*** sm2算法与签名的使用** @author fir* @date 2024/7/23 14:22*/
@Slf4j
public class Sm2SignatureUtils {static {Security.addProvider(new BouncyCastleProvider());}public static final String PUBLIC_KEY = "publicKey";public static final String PRIVATE_KEY = "privateKey";/*** 生成国密公私钥对*/public static Map<String, String> generateSmKey() throws Exception {KeyPairGenerator keyPairGenerator;SecureRandom secureRandom = new SecureRandom();ECGenParameterSpec sm2Spec = new ECGenParameterSpec("sm2p256v1");keyPairGenerator = KeyPairGenerator.getInstance("EC", new BouncyCastleProvider());keyPairGenerator.initialize(sm2Spec);keyPairGenerator.initialize(sm2Spec, secureRandom);KeyPair keyPair = keyPairGenerator.generateKeyPair();PrivateKey privateKey = keyPair.getPrivate();PublicKey publicKey = keyPair.getPublic();String publicKeyStr = new String(Base64.getEncoder().encode(publicKey.getEncoded()));String privateKeyStr = new String(Base64.getEncoder().encode(privateKey.getEncoded()));return Map.of(PUBLIC_KEY, publicKeyStr, PRIVATE_KEY, privateKeyStr);}/*** 将Base64转码的公钥串,转化为公钥对象*/public static PublicKey createPublicKey(String publicKey) {PublicKey publickey = null;try {X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(publicKey));KeyFactory keyFactory = KeyFactory.getInstance("EC", new BouncyCastleProvider());publickey = keyFactory.generatePublic(publicKeySpec);} catch (Exception e) {log.error("将Base64转码的公钥串,转化为公钥对象异常:{}", e.getMessage(), e);}return publickey;}/*** 将Base64转码的私钥串,转化为私钥对象*/public static PrivateKey createPrivateKey(String privateKey) {PrivateKey publickey = null;try {PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey));KeyFactory keyFactory = KeyFactory.getInstance("EC", new BouncyCastleProvider());publickey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);} catch (Exception e) {log.error("将Base64转码的私钥串,转化为私钥对象异常:{}", e.getMessage(), e);}return publickey;}/*** 根据publicKey对原始数据data,使用SM2加密*/public static String encrypt(byte[] data, String publicKeyBase64) {PublicKey publicKey = createPublicKey(publicKeyBase64);ECPublicKeyParameters localEcPublicKeyParameters = getEcPublicKeyParameters(publicKey);SM2Engine localSm2Engine = new SM2Engine();localSm2Engine.init(true, new ParametersWithRandom(localEcPublicKeyParameters, new SecureRandom()));byte[] arrayOfByte2;try {arrayOfByte2 = localSm2Engine.processBlock(data, 0, data.length);return Base64.getEncoder().encodeToString(arrayOfByte2);} catch (InvalidCipherTextException e) {log.error("SM2加密失败:{}", e.getMessage(), e);return null;}}private static ECPublicKeyParameters getEcPublicKeyParameters(PublicKey publicKey) {ECPublicKeyParameters localEcPublicKeyParameters = null;if (publicKey instanceof BCECPublicKey localEcPublicKey) {ECParameterSpec localEcParameterSpec = localEcPublicKey.getParameters();ECDomainParameters localEcDomainParameters = new ECDomainParameters(localEcParameterSpec.getCurve(),localEcParameterSpec.getG(), localEcParameterSpec.getN());localEcPublicKeyParameters = new ECPublicKeyParameters(localEcPublicKey.getQ(), localEcDomainParameters);}return localEcPublicKeyParameters;}/*** 根据privateKey对加密数据encode data,使用SM2解密*/public static String decrypt(String encodeBase64, String privateKeyBase64) {SM2Engine localSm2Engine = new SM2Engine();PrivateKey privateKey = createPrivateKey(privateKeyBase64);BCECPrivateKey sm2PriK = (BCECPrivateKey) privateKey;byte[] encodeData = Base64.getDecoder().decode(encodeBase64);ECParameterSpec localEcParameterSpec = sm2PriK.getParameters();ECDomainParameters localEcDomainParameters = new ECDomainParameters(localEcParameterSpec.getCurve(),localEcParameterSpec.getG(), localEcParameterSpec.getN());ECPrivateKeyParameters localEcPrivateKeyParameters = new ECPrivateKeyParameters(sm2PriK.getD(),localEcDomainParameters);localSm2Engine.init(false, localEcPrivateKeyParameters);try {byte[] result = localSm2Engine.processBlock(encodeData, 0, encodeData.length);return new String(result);} catch (InvalidCipherTextException e) {log.error("SM2解密失败:{}", e.getMessage(), e);return null;}}/*** 私钥,数据,生成签名*/public static String signByPrivateKey(String dataStr, String privateKeyBase64) throws Exception {PrivateKey privateKey = createPrivateKey(privateKeyBase64);byte[] data = Base64.getDecoder().decode(dataStr);Signature sig = Signature.getInstance(GMObjectIdentifiers.sm2sign_with_sm3.toString(), BouncyCastleProvider.PROVIDER_NAME);sig.initSign(privateKey);sig.update(data);byte[] sign = sig.sign();return Base64.getEncoder().encodeToString(sign);}/*** 公钥与签名验证数据合法性*/public static boolean verifyByPublicKey(String dataStr, String publicKeyBase64, String signatureBase64) throws Exception {PublicKey publicKey = createPublicKey(publicKeyBase64);byte[] signature = Base64.getDecoder().decode(signatureBase64);byte[] data = Base64.getDecoder().decode(dataStr);Signature sig = Signature.getInstance(GMObjectIdentifiers.sm2sign_with_sm3.toString(), BouncyCastleProvider.PROVIDER_NAME);sig.initVerify(publicKey);sig.update(data);return sig.verify(signature);}public static void test() throws Exception {// 生成公私钥对Map<String, String> keys = generateSmKey();String publicKey = keys.get(PUBLIC_KEY);String privateKey = keys.get(PRIVATE_KEY);String testStr = "123456";System.out.println("原始字符串:" + testStr);System.out.println("公钥:" + keys.get(PUBLIC_KEY));System.out.println("私钥:" + keys.get(PRIVATE_KEY));System.out.println();// 公钥加密String encrypt = encrypt(testStr.getBytes(), publicKey);System.out.println("加密数据:" + encrypt);// 私钥签名,后续根据数据与公钥验签String sign = signByPrivateKey(encrypt, privateKey);System.out.println("数据签名:" + sign);// 公钥验签,验证通过后再进行数据解密boolean b = verifyByPublicKey(encrypt, publicKey, sign);System.out.println("数据验签:" + b);//私钥解密String decrypt = decrypt(encrypt, privateKey);System.out.println("解密数据:" + decrypt);}public static void uesCase() throws Exception {//生成公私钥对String publicKey = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEsrdE0XrAO2S7Ize0tm0r3diH9cPH23t0J9yVDtiVux6g71msH5YGTWW6/ogQSCVJ4iaofgCS/ly5+wkXa+/IGg==";String privateKey = "MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgNxb+Jcu1vhGt9UEbeFUYeCC+RWL7+sfUL1vnhBp2KtKgCgYIKoEcz1UBgi2hRANCAASyt0TResA7ZLsjN7S2bSvd2If1w8fbe3Qn3JUO2JW7HqDvWawflgZNZbr+iBBIJUniJqh+AJL+XLn7CRdr78ga";String testStr = "123456";System.out.println("原始字符串:" + testStr);System.out.println("公钥:" + publicKey);System.out.println("私钥:" + privateKey);System.out.println();//公钥加密String encrypt = encrypt(testStr.getBytes(), publicKey);System.out.println("加密数据:" + encrypt);// 私钥签名,后续根据数据与公钥验签String sign = signByPrivateKey(encrypt, privateKey);System.out.println("数据签名:" + sign);//公钥验签,验证通过后再进行数据解密boolean b = verifyByPublicKey(encrypt, publicKey, sign);System.out.println("数据验签:" + b);//私钥解密String decrypt = decrypt(encrypt, privateKey);System.out.println("解密数据:" + decrypt);}public static void main(String[] args) {try {test();
//            uesCase();} catch (Exception e) {throw new RuntimeException(e);}}
}

使用案例

验证密码

接受到用户输入的用户与密码之后,在数据库中查询出旧的密码,并进行旧密码进行验签、解密。解密后判断用户输入的密码与数据库存储的密码是否相同。

        // 验证密码是否正确String password = "123456";String passwordOld = user.getPassword();String signature = user.getSignature();String decryptPasswordOld = null;try {// 公钥验签,查看数据与签名是否有效boolean b = Sm2SignatureUtils.verifyByPublicKey(passwordOld, public, signature);if(!b){throw new CommonException("数据损坏");}decryptPasswordOld = Sm2SignatureUtils.decrypt(passwordOld, private);}catch (Exception e){throw new CommonException("数据损坏");}if (decryptPasswordOld == null || !decryptPasswordOld.equals(password)) {throw new CommonException("用户密码错误");}
修改密码

接收到用户的密码后,根据公私要生成加密数据串与私钥签名。并存储到数据库,用于之后的密码验证。

            // 公钥加密String password = "123456";String encrypt = Sm2SignatureUtils.encrypt(password.getBytes(), public);// 根据数据与私钥,生成私钥签名String sign = Sm2SignatureUtils.signByPrivateKey(encrypt, private);user.setPassword(encrypt);user.setSignature(sign);

随机密码盐加密

工具类与测试方法

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;/*** @author fir* @date 2024/7/25 12:22*/
public class SaltUtils {/*** 生成随机安全盐** @return 盐*/public static String generateSalt() {// 使用SecureRandom生成安全的随机盐SecureRandom random = new SecureRandom();byte[] salt = new byte[16];random.nextBytes(salt);return Base64.getEncoder().encodeToString(salt);}/*** 生成加盐密码** @return 盐*/public static String hashPassword(String password, String salt){// 将密码和盐结合String saltedPassword = password + salt;// 使用SHA-256进行哈希MessageDigest md;try {md = MessageDigest.getInstance("SHA-256");}catch (NoSuchAlgorithmException e){throw new RuntimeException("加密盐处理失败");}byte[] hashedBytes = md.digest(saltedPassword.getBytes());// 将哈希值转换为字符串return Base64.getEncoder().encodeToString(hashedBytes);}public static void main(String[] args){String salt = generateSalt();String password = "123456";String hashPassword = hashPassword(password, salt);System.out.println("盐:" + salt);System.out.println("密码:" + password);System.out.println("加密密码:" + hashPassword);}}

使用案例

验证密码

查询出用户的密码,将用户输入的密码盐加密,并判断与数据库的加密密码是否一致。

        String password = "123456";String salt = user.getSalt();String passwordOld = user.getPassword();String mPassword = SaltUtils.hashPassword(password, salt);if (!mPassword.equals(passwordOld)) {throw new CommonException("密码错误");}
修改密码

将用户输入的密码md5加密之后,存在数据库中,用于之后的密码验证

        String password = "123456";String salt = SaltUtils.generateSalt();String hashPassword = SaltUtils.hashPassword(password, salt);user.setPassword(hashPassword);

MD5加密

引入hutool包,以使用md5加密。

        <dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.19</version></dependency>

测试方法

import cn.hutool.crypto.digest.MD5;/*** @author fir* @date 2024/7/22 10:07*/
public class Md5Utils {public static void main(String[] args){// MD5取值String mPassword = MD5.create().digestHex("123456");System.out.println(mPassword);}
}

使用案例

验证密码

查询出用户的密码,将用户输入的密码MD5加密,并判断与数据库的加密密码是否一致。

        String password = "123456";String mPassword = MD5.create().digestHex(password);String passwordOld = user.getPassword();if (!mPassword.equals(passwordOld)) {throw new CommonException("密码错误");}
修改密码

将用户输入的密码md5加密之后,存在数据库中,用于之后的密码验证

        String password = "123456";String passwordMd5 = MD5.create().digestHex(password);user.setPassword(passwordMd5);

相关文章:

[Spring Boot]登录密码三种加密方式

简述 介绍其三种密码加密方法 1.SM2加密与验签 2.随机密码盐加密 3.MD5加密 推荐使用方法1&#xff0c;其次使用方法2&#xff0c;最不推荐的是方法3。方法3极其容易被密码字典破解&#xff0c;如果项目进行安全测试&#xff0c;通常是不允许的加密方式。 SM2加密与验签 引入…...

前端面试项目细节重难点分享(十三)

面试题提问&#xff1a;分享你最近做的这个项目&#xff0c;并讲讲该项目的重难点&#xff1f; 答&#xff1a;最近这个项目是一个二次迭代开发项目&#xff0c;迭代周期一年&#xff0c;在做这些任务需求时&#xff0c;确实有很多值得分享的印象深刻的点&#xff0c;我讲讲下面…...

每天五分钟深度学习:向量化方式完成逻辑回归m个样本的前向传播

本文重点 我们已经知道了向量化可以明显的加速程序的运行速度,本节课程将使用向量化来完成逻辑回归的前向传播,不使用一个for循环。 逻辑回归的前向传播 我们先来回忆一下逻辑回归的前向传播,如果我们有m个训练样本,首先对第一个样本进行预测,我们需要计算z,然后计算预…...

以线程完成并发的UDP服务端

网络(九)并发的UDP服务端 以线程完成功能 客户端 // todo UDP发送端 #include <stdio.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/types.h> #include <stdlib.h> #include <string.h…...

linux c 特殊字符分割

/* * brief: 根据split_symbol分割字符串 * param: str为要分割的字符串&#xff0c;split_symbol是分隔符 * return&#xff1a;返回garray的指针数组&#xff0c;如果返回非空需要自己处理释放 */ GPtrArray_autoptr char_sz_spilt(pchar* str, pchar split_symbol) {if (NUL…...

搭建本地私有知识问答系统:MaxKB + Ollama + Llama3 (wsl网络代理配置、MaxKB-API访问配置)

目录 搭建本地私有知识问答系统:MaxKB、Ollama 和 Llama3 实现指南引言MaxKB+Ollama+Llama 3 Start buildingMaxKB 简介:1.1、docker部署 MaxKB(方法一)1.1.1、启用wls或是开启Hyper使用 WSL 2 的优势1.1.2、安装docker1.1.3、docker部署 MaxKB (Max Knowledge Base)MaxKB …...

谷粒商城实战笔记-65-商品服务-API-品牌管理-表单校验自定义校验器

文章目录 1&#xff0c;el-form品牌logo图片自定义显示2&#xff0c;重新导入和注册element-ui组件3&#xff0c;修改brand-add-or-update.vue控件的表单校验规则firstLetter 校验规则sort 校验规则 1&#xff0c;el-form品牌logo图片自定义显示 为了在品牌列表中自定义显示品…...

学好C++之——命名空间

c开始学习之时&#xff0c;你不可避免会遇到一个新朋友&#xff0c;那就是——namespace&#xff08;命名空间&#xff09;。 那么这篇文章就来为你解决这个小麻烦喽~ 目录 1.namespace存在的意义 2.namespace的定义 3.namespace的使用 1.namespace存在的意义 在C中&#…...

pytorch lightning报错all tensors to be on the same device

RuntimeError: Expected all tensors to be on the same device, but found at least two devices, cuda:0 and cpu! 修改指定为gpu trainer pl.Trainer(max_epochstrain_params.iterations, loggertb_logger,acceleratorgpu, devices1)...

Redis中的哨兵(Sentinel)

上篇文章我们讲述了Redis中的主从复制&#xff08;Redis分布式系统中的主从复制-CSDN博客&#xff09;&#xff0c;本篇文章针对主从复制中的问题引出Redis中的哨兵&#xff0c;希望本篇文章会对你有所帮助。 文章目录 一、引入哨兵机制 二、基本概念 三、主从复制的问题 四、哨…...

产业创新研究杂志产业创新研究杂志社产业创新研究编辑部2024年第12期目录

高质量发展 如何在新一轮产业链变革中平稳应对挑战 王宏利; 1-3《产业创新研究》投稿&#xff1a;cnqikantg126.com 基于ERGM的城市间绿色低碳技术专利转让网络结构及演化研究 吕彦朋;姜军;张宁; 4-6 数字基础设施建设对城市FDI的影响——基于“宽带中国”试点政策…...

网闸(Network Gatekeeper或Security Gateway)

本心、输入输出、结果 文章目录 网闸(Network Gatekeeper或Security Gateway)前言网闸主要功能网闸工作原理网闸使用场景网闸网闸(Network Gatekeeper或Security Gateway) 编辑 | 简简单单 Online zuozuo 地址 | https://blog.csdn.net/qq_15071263 如果觉得本文对你有帮助…...

C#中的字符串

String 在实例方法中string虽然传入的是引用类型 但是修改string 并不是修改原来堆里面的值 而是又重新创建一个堆值 用来然后用方法内的变量指向新的堆值 C# 中的字符串&#xff08;string 类型&#xff09;提供了许多有用的方法来处理字符串数据。以下是一些常用的字符…...

docker安装部署elasticsearch7.15.2

docker安装部署elasticsearch7.15.2 1.拉取es镜像 docker pull docker.elastic.co/elasticsearch/elasticsearch:7.15.2如果不想下载或者镜像拉去太慢可以直接下载文章上面的镜像压缩包 使用镜像解压命令 docker load -i elasticsearch-7-15-2.tar如下图所示就表示镜像解压成…...

Symfony 入门指南:快速安装与基础配置

Symfony 入门指南&#xff1a;快速安装与基础配置 Symfony 是一个强大而灵活的 PHP 框架&#xff0c;广泛应用于构建现代 Web 应用程序。本指南将带您一步一步地了解如何快速安装 Symfony&#xff0c;并完成基本配置&#xff0c;以便您能够开始使用这个强大的框架。 目录 引…...

3.3V升压至5V的AH6922芯片:高效能的SOP8封装解决方案

# 3.3V升压至5V的AH6922芯片&#xff1a;高效能的SOP8封装解决方案 在当今快速发展的电子设备领域&#xff0c;对于电源管理的需求日益增长。特别是对于便携式产品和手持设备&#xff0c;一个高效、稳定且体积小巧的升压解决方案变得至关重要。本文将介绍一款专为这些需求设计…...

赋能未来教育,3DCAT助力深圳鹏程技师学院打造5G+XR实训室

随着国家对教育行业的重视&#xff0c;实训室建设已成为推动教育现代化的关键。《教育信息化2.0行动计划》、《职业教育示范性虚拟仿真实训基地建设指南》等政策文件&#xff0c;明确指出了加强虚拟仿真实训教学环境建设的重要性。 在这一大背景下&#xff0c;教育行业对于实训…...

力扣141环形链表问题|快慢指针算法详细推理,判断链表是否有环|龟兔赛跑算法

做题链接 目录 前言&#xff1a; 一、算法推导&#xff1a; 1.假设有环并且一定会相遇&#xff0c;那么一定是在环内相遇&#xff0c;且是快指针追上慢指针。 2.有环就一定会相遇吗&#xff1f;快指针是每次跳两步&#xff0c;有没有可能把慢指针跳过去&#xff1f; 3.那一定…...

React 常见的报错及解决方法

1、Warning: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons&#xff08;无效的钩子调用。钩子只能在函数组件的内部调用。这可能是由于以下原因之一&#xff09; 原因&#x…...

更新服务器nginx 1.26.1版本

今天在官网下载了nginx1的1.26.1版本&#xff0c;使用gpt的脚本想直接覆盖安装&#xff0c;脚本如下 #!/bin/bash# 设置变量 NGINX_VERSION"1.26.1" TAR_FILE"nginx-$NGINX_VERSION.tar.gz" SRC_DIR"nginx-$NGINX_VERSION"# 检查是否存在tar包 …...

基于算法竞赛的c++编程(28)结构体的进阶应用

结构体的嵌套与复杂数据组织 在C中&#xff0c;结构体可以嵌套使用&#xff0c;形成更复杂的数据结构。例如&#xff0c;可以通过嵌套结构体描述多层级数据关系&#xff1a; struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...

[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?

&#x1f9e0; 智能合约中的数据是如何在区块链中保持一致的&#xff1f; 为什么所有区块链节点都能得出相同结果&#xff1f;合约调用这么复杂&#xff0c;状态真能保持一致吗&#xff1f;本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里&#xf…...

pam_env.so模块配置解析

在PAM&#xff08;Pluggable Authentication Modules&#xff09;配置中&#xff0c; /etc/pam.d/su 文件相关配置含义如下&#xff1a; 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块&#xff0c;负责验证用户身份&am…...

生成 Git SSH 证书

&#x1f511; 1. ​​生成 SSH 密钥对​​ 在终端&#xff08;Windows 使用 Git Bash&#xff0c;Mac/Linux 使用 Terminal&#xff09;执行命令&#xff1a; ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" ​​参数说明​​&#xff1a; -t rsa&#x…...

高危文件识别的常用算法:原理、应用与企业场景

高危文件识别的常用算法&#xff1a;原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件&#xff0c;如包含恶意代码、敏感数据或欺诈内容的文档&#xff0c;在企业协同办公环境中&#xff08;如Teams、Google Workspace&#xff09;尤为重要。结合大模型技术&…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案

随着新能源汽车的快速普及&#xff0c;充电桩作为核心配套设施&#xff0c;其安全性与可靠性备受关注。然而&#xff0c;在高温、高负荷运行环境下&#xff0c;充电桩的散热问题与消防安全隐患日益凸显&#xff0c;成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

聊一聊接口测试的意义有哪些?

目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开&#xff0c;首…...

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!

简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求&#xff0c;并检查收到的响应。它以以下模式之一…...

【LeetCode】3309. 连接二进制表示可形成的最大数值(递归|回溯|位运算)

LeetCode 3309. 连接二进制表示可形成的最大数值&#xff08;中等&#xff09; 题目描述解题思路Java代码 题目描述 题目链接&#xff1a;LeetCode 3309. 连接二进制表示可形成的最大数值&#xff08;中等&#xff09; 给你一个长度为 3 的整数数组 nums。 现以某种顺序 连接…...

0x-3-Oracle 23 ai-sqlcl 25.1 集成安装-配置和优化

是不是受够了安装了oracle database之后sqlplus的简陋&#xff0c;无法删除无法上下翻页的苦恼。 可以安装readline和rlwrap插件的话&#xff0c;配置.bahs_profile后也能解决上下翻页这些&#xff0c;但是很多生产环境无法安装rpm包。 oracle提供了sqlcl免费许可&#xff0c…...