当前位置 : 主页 > 编程语言 > java >

一种表单提交AES加密案例(仿某大学bbs加密逻辑)

来源:互联网 收集:自由互联 发布时间:2022-07-17
最近分析了一大学bbs登录时,加密的流程,在此自己用spring boot做了个类似的,在此记录下,感觉还是有点东西的。逻辑很简单: 登录页面: 输入用户名/密码后,这里是admin/admin 用F

最近分析了一大学bbs登录时,加密的流程,在此自己用spring boot做了个类似的,在此记录下,感觉还是有点东西的。逻辑很简单:

登录页面:

一种表单提交AES加密案例(仿某大学bbs加密逻辑)_java

输入用户名/密码后,这里是admin/admin

一种表单提交AES加密案例(仿某大学bbs加密逻辑)_java_02

用Fiddler抓包是这样的:

一种表单提交AES加密案例(仿某大学bbs加密逻辑)_java_03

这里的Password用了AES加密,这里前端从后端再加载页面的时候,就获取了aes的密钥和向量,当然这里可以用JS逆向,得到这个值(这里和某大学BBS一样)

对应的流程图是这样的:

一种表单提交AES加密案例(仿某大学bbs加密逻辑)_spring_04

程序结构如下:

一种表单提交AES加密案例(仿某大学bbs加密逻辑)_java_05

代码如下:

LoginController.java

package cn.it1995.MyController;

import cn.it1995.service.LoginService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Controller
public class LoginController {

@Autowired
LoginService loginService;

@GetMapping("/")
public String index(HttpServletResponse response,
Model model){



String cookie = loginService.generateCookie();
String salt = loginService.getSaltByCookie(cookie);
String offset = loginService.getOffsetByCookie(cookie);
response.addCookie(new Cookie("token", cookie));
model.addAttribute("saltStr", salt);
model.addAttribute("offsetStr", offset);

return "login.html";
}

@PostMapping
public String login(@RequestParam("userName") String userName,
@RequestParam("password"){

Cookie[] cookies = request.getCookies();
String cookie = "";
for(Integer i = 0; i < cookies.length; i++){

if(cookies[i].getName().equals("token")){

cookie = cookies[i].getValue();
}
}

if(cookie.equals("")){

return "redircet:/";
}

// String salt = loginService.getSaltByCookie(cookie);
try{

boolean passwordCorrect = loginService.isPasswordCorrect(cookie, password);
System.out.println("The passwordCorrect is " + passwordCorrect);
if(!passwordCorrect){

return "redirect:/";
}
}
catch (Exception e){

e.printStackTrace();
return "redirect:/";
}

// System.out.println(userName);
// System.out.println(password);
// System.out.println(salt);

return "success.html";
}
}

MySession.java

package cn.it1995.Object;

public class MySession {

public String cookie;
public String salt;
public String offset;

public MySession(String cookie, String salt, String offset){

this.cookie = cookie;
this.salt = salt;
this.offset = offset;
}
}

SessionRepository.java

package cn.it1995.repository;

import cn.it1995.Object.MySession;
import org.springframework.stereotype.Repository;

import java.util.ArrayList;

@Repository
public class SessionRepository {

private ArrayList<MySession> sessionList = new ArrayList<MySession>();

public void addSession(MySession session){

sessionList.add(session);
}

public String getSaltByCookie(String cookie){

for(MySession mySession : sessionList){

if(mySession.cookie.equals(cookie)){

return mySession.salt;
}
}

return null;
}

public String getOffsetByCookie(String cookie){

for(MySession mySession : sessionList){

if(mySession.cookie.equals(cookie)){

return mySession.offset;
}
}

return null;
}

public boolean isSessionExist(MySession session){

for(MySession mySession : sessionList){

if(mySession.cookie.equals(session.cookie)){

return true;
}
}

return false;
}

public void clearAllSession(){

sessionList.clear();
}

}

LoginServer.java

package cn.it1995.service;

import cn.it1995.Object.MySession;
import cn.it1995.repository.SessionRepository;
import cn.it1995.tool.AESUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Random;

@Service
public class LoginService {

@Autowired
SessionRepository sessionRepository;

public String generateCookie(){

String cookie = generateString(32);
String salt = generateString(16);
String offset = generateString(16);

MySession mySession = new MySession(cookie, salt, offset);
sessionRepository.addSession(mySession);
return cookie;
}


public String getSaltByCookie(String cookie){

return sessionRepository.getSaltByCookie(cookie);
}

public String getOffsetByCookie(String cookie){

return sessionRepository.getOffsetByCookie(cookie);
}

public boolean isUserExist(String userName){

if(userName.equals("admin")){

return true;
}

return false;
}

public boolean isPasswordCorrect(String cookie, String password) throws Exception {

String saltByCookie = sessionRepository.getSaltByCookie(cookie);
String vi = sessionRepository.getOffsetByCookie(cookie);
String decrypt = AESUtil.decrypt(password, saltByCookie, vi);
if(decrypt.equals("admin")){

return true;
}

return false;
}

public void removeAllSession(){

sessionRepository.clearAllSession();
}


protected String generateString(Integer length){

String str = "zxcvbnmlkjhgfdsaqwertyuiopQWERTYUIOPASDFGHJKLZXCVBNM1234567890";
Random random = new Random();

//cookie
StringBuffer cookieSb = new StringBuffer();
for(int i = 0; i < length; ++i){

//产生0-61的数字
int number = random.nextInt(62);

//将产生的数字通过length次承载到sb中
cookieSb.append(str.charAt(number));
}

return new String(cookieSb);
}
}

AESUtil.java

package cn.it1995.tool;


import org.apache.tomcat.util.codec.binary.Base64;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;

public class AESUtil {

public static String decrypt(String content, String key, String vi) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, UnsupportedEncodingException, UnsupportedEncodingException, InvalidAlgorithmParameterException {

Key k = toKey(key.getBytes());
byte[] encoded = k.getEncoded();
SecretKeySpec aes = new SecretKeySpec(encoded, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
IvParameterSpec iv = new IvParameterSpec(vi.getBytes());
cipher.init(Cipher.DECRYPT_MODE, aes, iv);

byte[] bytes = cipher.doFinal(Base64.decodeBase64(content));

return new String(bytes, "UTF-8");
}

public static String encrypt(String data, String key, String vi) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException {

//Key k = toKey(Base64.decodeBase64(key));
Key k = toKey(key.getBytes());
byte[] encoded = k.getEncoded();
SecretKeySpec aes = new SecretKeySpec(encoded, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
IvParameterSpec iv = new IvParameterSpec(vi.getBytes());
cipher.init(Cipher.ENCRYPT_MODE, aes, iv);
byte[] bytes = cipher.doFinal(data.getBytes("UTF-8"));
return Base64.encodeBase64String(bytes);
}

private static Key toKey(byte[] key){

SecretKeySpec aes = new SecretKeySpec(key, "AES");
return aes;
}

public static void main(String[] args) throws NoSuchPaddingException, BadPaddingException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IllegalBlockSizeException, UnsupportedEncodingException, InvalidKeyException {

String content = "7mv2MJPHj1o/rdar1I4i0Q==";
String key = "sN1DEJAVZNf3OdM3";
String vi = "GDHgt7hbKpsIR4b4";

System.out.println("原文 : root");

String e = AESUtil.encrypt("root", key, vi);
System.out.println("密文 : " + e);
String f = AESUtil.decrypt(e, key, vi);
System.out.println("解密 : " + f);
}

}

WebAppMain.java

package cn.it1995;

import org.apache.catalina.Context;
import org.apache.catalina.connector.Connector;
import org.apache.tomcat.util.descriptor.web.SecurityCollection;
import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class WebAppMain {

public static void main(String[] args){

SpringApplication.run(WebAppMain.class, args);
}

@Bean
public TomcatServletWebServerFactory servletContainer(){

TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {

@Override
protected void postProcessContext(Context context){

SecurityConstraint constraint = new SecurityConstraint();
constraint.setUserConstraint("CONFIDENTIAL");
SecurityCollection collection = new SecurityCollection();
collection.addPattern("/*");
constraint.addCollection(collection);
context.addConstraint(constraint);
}
};
tomcat.addAdditionalTomcatConnectors(httpConnector());
return tomcat;
}

@Bean
public Connector httpConnector(){

Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
connector.setScheme("http");
//Connector监听的http的端口号
connector.setPort(8081);
connector.setSecure(false);
//监听到http的端口号后转向到的https的端口号
connector.setRedirectPort(8443);
return connector;
}
}

login.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="https://www.thymeleaf.org"
xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<!-- Standard Meta -->
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">

<!-- Site Properties -->
<title>Login Example - Semantic</title>
<link rel="stylesheet" type="text/css" href="https://semantic-ui.com/dist/components/reset.css">
<link rel="stylesheet" type="text/css" href="https://semantic-ui.com/dist/components/site.css">

<link rel="stylesheet" type="text/css" href="https://semantic-ui.com/dist/components/container.css">
<link rel="stylesheet" type="text/css" href="https://semantic-ui.com/dist/components/grid.css">
<link rel="stylesheet" type="text/css" href="https://semantic-ui.com/dist/components/header.css">
<link rel="stylesheet" type="text/css" href="https://semantic-ui.com/dist/components/image.css">
<link rel="stylesheet" type="text/css" href="https://semantic-ui.com/dist/components/menu.css">

<link rel="stylesheet" type="text/css" href="https://semantic-ui.com/dist/components/divider.css">
<link rel="stylesheet" type="text/css" href="https://semantic-ui.com/dist/components/segment.css">
<link rel="stylesheet" type="text/css" href="https://semantic-ui.com/dist/components/form.css">
<link rel="stylesheet" type="text/css" href="https://semantic-ui.com/dist/components/input.css">
<link rel="stylesheet" type="text/css" href="https://semantic-ui.com/dist/components/button.css">
<link rel="stylesheet" type="text/css" href="https://semantic-ui.com/dist/components/list.css">
<link rel="stylesheet" type="text/css" href="https://semantic-ui.com/dist/components/message.css">
<link rel="stylesheet" type="text/css" href="https://semantic-ui.com/dist/components/icon.css">

<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://semantic-ui.com/dist/components/form.js"></script>
<script src="https://semantic-ui.com/dist/components/transition.js"></script>


<!-- 引入 CDN Crypto.js 开始 AES加密 注意引入顺序 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/core.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/enc-base64.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/md5.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/evpkdf.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/cipher-core.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/aes.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/pad-pkcs7.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/mode-ecb.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/enc-utf8.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/enc-hex.min.js"></script>
<!-- 引入 CDN Crypto.js 结束 -->



<style type="text/css">
body {
background-color: #DADADA;
}
body > .grid {
height: 100%;
}
.image {
margin-top: -100px;
}
.column {
max-width: 450px;
}
</style>
<script language="JavaScript">function login(){

var password = document.getElementById("password").value;
var offset = document.getElementById("offset").value;
var salt = document.getElementById("salt").value;

let key = CryptoJS.enc.Utf8.parse(salt);
let srcs = CryptoJS.enc.Utf8.parse(password);
let vi = CryptoJS.enc.Utf8.parse(offset);


var encrypted = CryptoJS.AES.encrypt(srcs, key, {
iv: vi,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});

console.log("原始数据 : ", password);
console.log("vi : ", offset);
console.log("salt : ", salt);

document.getElementById("password").value = encrypted.toString();
console.log("ase加密 : ", encrypted.toString());
console.log("解密");

let decrypted = CryptoJS.AES.decrypt(encrypted.toString(), key, {
iv: vi,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});

console.log("ase 解码 : " , CryptoJS.enc.Utf8.stringify(decrypted).toString());
}
</script>
</head>
<body>

<div class="ui middle aligned center aligned grid">
<div class="column">
<h2 class="ui teal image header">
<div class="content">
Log-in to your account
</div>
</h2>
<form action="login" method="post" class="ui large form" onsubmit="login()">
<div class="ui stacked segment">
<div class="field">
<div class="ui left icon input">
<i class="user icon"></i>
<input type="text" id="userName" name="userName" placeholder="userName">
</div>
</div>
<div class="field">
<div class="ui left icon input">
<i class="lock icon"></i>
<input type="password" id="password" name="password" placeholder="password">
</div>
</div>
<button class="ui fluid large teal button submit">Login</button>
</div>

<input name="salt" id="salt" type="hidden" th:value="${saltStr}">
<input name="offset" id="offset" type="hidden" th:value="${offsetStr}">

<div class="ui error message"></div>

</form>

</div>
</div>

</body>

</html>

success.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="https://www.thymeleaf.org"
xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<!-- Standard Meta -->
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">

<!-- Site Properties -->
<title>Success</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://semantic-ui.com/dist/components/reset.css">
<link rel="stylesheet" type="text/css" href="https://semantic-ui.com/dist/components/site.css">

<link rel="stylesheet" type="text/css" href="https://semantic-ui.com/dist/components/container.css">
<link rel="stylesheet" type="text/css" href="https://semantic-ui.com/dist/components/grid.css">
<link rel="stylesheet" type="text/css" href="https://semantic-ui.com/dist/components/header.css">
<link rel="stylesheet" type="text/css" href="https://semantic-ui.com/dist/components/image.css">
<link rel="stylesheet" type="text/css" href="https://semantic-ui.com/dist/components/menu.css">

<link rel="stylesheet" type="text/css" href="https://semantic-ui.com/dist/components/divider.css">
<link rel="stylesheet" type="text/css" href="https://semantic-ui.com/dist/components/segment.css">
<link rel="stylesheet" type="text/css" href="https://semantic-ui.com/dist/components/form.css">
<link rel="stylesheet" type="text/css" href="https://semantic-ui.com/dist/components/input.css">
<link rel="stylesheet" type="text/css" href="https://semantic-ui.com/dist/components/button.css">
<link rel="stylesheet" type="text/css" href="https://semantic-ui.com/dist/components/list.css">
<link rel="stylesheet" type="text/css" href="https://semantic-ui.com/dist/components/message.css">
<link rel="stylesheet" type="text/css" href="https://semantic-ui.com/dist/components/icon.css">

<script src="https://semantic-ui.com/dist/components/form.js"></script>
<script src="https://semantic-ui.com/dist/components/transition.js"></script>

<style type="text/css">
body {
background-color: #DADADA;
}
body > .grid {
height: 100%;
}
.image {
margin-top: -100px;
}
.column {
max-width: 450px;
}
</style>
</head>
<body>

<div class="ui middle aligned center aligned grid">
<div class="column">
<h1>Success</h1>
</div>
</div>

</body>

</html>

application.properties

#Thymeleaf配置
spring.thymeleaf.cache=false
spring.thymeleaf.encoding=utf-8
spring.thymeleaf.mode=HTML5
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html


server.port=8443
server.ssl.key-alias=selfsigned_localhost_sslserver
server.ssl.key-password=it1995
server.ssl.key-store=classpath:ssl-server.jks
server.ssl.key-store-provider=SUN
server.ssl.key-store-type=JKS

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>org.example</groupId>
<artifactId>LoginAuthority</artifactId>
<version>1.0-SNAPSHOT</version>

<dependencies>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.10.RELEASE</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>2.3.12.RELEASE</version>
</dependency>

<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-ext-jdk16</artifactId>
<version>1.45</version>
</dependency>

</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.1.10.RELEASE</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

</project>
网友评论