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

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

登录页面:

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

用Fiddler抓包是这样的:

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

对应的流程图是这样的:

程序结构如下:

代码如下:

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; @Controllerpublic 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; @Repositorypublic 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; @Servicepublic 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; @SpringBootApplicationpublic 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=falsespring.thymeleaf.encoding=utf-8spring.thymeleaf.mode=HTML5spring.thymeleaf.prefix=classpath:/templates/spring.thymeleaf.suffix=.html server.port=8443server.ssl.key-alias=selfsigned_localhost_sslserverserver.ssl.key-password=it1995server.ssl.key-store=classpath:ssl-server.jksserver.ssl.key-store-provider=SUNserver.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> 只要心中有希望存在,就有幸福存在。

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

相关文章:

你感兴趣的文章:

标签云: