表单提交时,前端用js加密,后端用Java(struts2)解密

2 篇文章 0 订阅
2 篇文章 0 订阅

表单提交时,前端用js加密,后端用Java(struts2)解密

前一篇博文提到,对称密钥系统双方使用相同的密码加密和解密,相对而言比较快,但是,如果双方之前没有约定,仅仅靠对称密钥系统无法进行加密和解密。RSA公开密钥加密系统采用公钥加密,私钥解密,能够安全传输需要加密的文本。但是,由于其需要进行大量的指数运算,速度慢,成本高,常用于加密少量的文本。

这里,我们对于表单提交时的密码采用公开密钥系统进行加密和解密。前端用JS进行公钥加密,后端用struts2(Java)私钥解密。

前端jsp表单提交的代码

<form action="login" id="loginForm" method="post">
    <table>
        <tr>
            <td>用户名</td>
            <td><input type="text" name="username" /></td>
        </tr>
        <tr>
            <td>密码</td>
            <td><input type="password" name="password" id="password" /></td>
        </tr>

        <tr>
<!--这里加上验证码是因为我们在密码框失去焦点时采用异步的方式从后端得到公钥。如果没有输入验证码的时间来等待查询,可能在提交之前得到不加密。另一种方式,在页面加载时如果发现表单项,则请求;或者用户框得到焦点时,就请求,则有足够的时间了。-->
<!--验证码这里直接是数字,不是动态的-->
            <td>验证码</td>
            <td><input type="text" name="verify" id="verify" /></td>
            <td><p>这是验证码 <i>520520</i></p></td>
        </tr>
        <tr>
            <td><input type="submit" value="提交"/></td>
            <td><input type="reset" value="重置"/></td>
        </tr>
    </table>
</form>

JS代码

添加两个事件处理程序。第一个,密码框失去焦点时,触发获取公钥的函数。第二个,提交时,触发加密的操作并提交。

<script type="text/javascript">
    //获取public key
    var publicKey = null;
    function getPublicKey() {   
        //新建一个XHR对象,只支持IE7以上的浏览器,或者其他浏览器,我用的是谷歌浏览器
        var xhr = new XMLHttpRequest();

        //需要访问的链接
        var urlString = "/Encryption/passwordEncrypt.action";
        xhr.open("post", urlString, true);
        xhr.send(null);

        //检查响应的状态   
        xhr.onreadystatechange = function() {
            if(xhr.readyState == 4) {
                if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
                    if(xhr.responseText != null) {          
                        publicKey = xhr.responseText;
                    } 
                }
            }   
        };

    }
    function encryptPassword(event) {       
        //对密码进行加密
        var encrypt = new JSEncrypt();

        encrypt.setPublicKey(publicKey);
        var password = document.getElementById("password").value;
        document.getElementById("password").value = encrypt.encrypt(password);

        //提交之前,检查是否已经加密。假设用户的密码不超过20位,加密后的密码不小于20位
        var password = document.getElementById("password").value;
        if(password.length < 20) {
            //实际提示,可以换一种说法
            alert("encryption failed");
            //若没有加密,阻止提交
            event.preventDefault();
        }
    }
    var password = document.getElementById("password");
    //添加事件处理程序:密码框失去焦点时,请求publicKey
    password.addEventListener("blur", getPublicKey, false);
    var loginForm = document.getElementById("loginForm");
    //提交时,进行加密
    loginForm.addEventListener("submit", encryptPassword, false);
</script>

用于提供加密和解密功能的工具类

这里除了struts2自身的JAR包以外,还需要依赖bcprov和commons-codec这两个JAR包。bcprov提供用于加密和解密的provider,它实现了算法和密钥的生成等。codec大致提供了编码解码功能。这个工具类很大程度上参考了链接,自己加了注释。

package com.chris.encryption;

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.interfaces.RSAPublicKey;

import javax.crypto.Cipher;

import org.apache.commons.codec.binary.Base64;



public class RSAUtils {
    //KeyPair is a simple holder for a key pair.
    private static final KeyPair keyPair = initKey();
    /**
     * 初始化方法,产生key pair,提供provider和random
     * @return KeyPair instance
     */
    private static KeyPair initKey() {

        try {
            //添加provider
            Provider provider = new org.bouncycastle.jce.provider.BouncyCastleProvider();
            Security.addProvider(provider);
            //产生用于安全加密的随机数
            SecureRandom random = new SecureRandom();

            //KeyPairGenerator is used to generate pairs of public and private keys,
            //which is constructed using the getInstance() factory methods.
            KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", provider);
            generator.initialize(1024, random); 
            return generator.generateKeyPair();
        } catch(Exception e) {
            throw new RuntimeException(e);
        }
    }
    /**
     * 产生public key
     * @return public key字符串
     */
    public static String generateBase64PublicKey() {
        PublicKey publicKey = (RSAPublicKey)keyPair.getPublic();

        //encodeBase64(): Encodes binary data using the base64 
        //algorithm but does not chunk the output.
        //getEncoded():返回key的原始编码形式
        return new String(Base64.encodeBase64(publicKey.getEncoded()));
    }
    /**
     * 解密数据
     * @param string 需要解密的字符串
     * @return  破解之后的字符串
     */
    public static String decryptBase64(String string) {
        //decodeBase64():将Base64数据解码为"八位字节”数据
        return new String(decrypt(Base64.decodeBase64(string.getBytes())));
    }

    private static byte[] decrypt(byte[] byteArray) {
        try {
            Provider provider = new org.bouncycastle.jce.provider.BouncyCastleProvider();
            Security.addProvider(provider);
            //Cipher: 提供加密和解密功能的实例
            //transformation: "algorithm/mode/padding"
            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", provider);
            PrivateKey privateKey = keyPair.getPrivate();
            //初始化
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            //doFinal(): 加密或者解密数据
            byte[] plainText = cipher.doFinal(byteArray);
            return plainText;
        } catch(Exception e) {
            throw new RuntimeException(e);
        }
    }


}

产生公钥的action类

package com.chris.encryption;

import java.io.PrintWriter;

import javax.servlet.ServletResponse;

import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionSupport;

public class PasswordEncrypt extends ActionSupport {
    @Override
    public String execute() throws Exception {      
        ServletResponse response = ServletActionContext.getResponse();
        PrintWriter writer = response.getWriter();
        String publicKey = RSAUtils.generateBase64PublicKey();
        writer.write(publicKey);        
        System.out.println(publicKey);  
        //由于我们这里不需要返回页面,故这里直接返回null
        return null;
    }
}

处理登陆请求的action

package com.chris.encryption;

import com.opensymphony.xwork2.ActionSupport;

public class Login extends ActionSupport {
    private String username;
    private String password;
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    @Override
    public String execute() throws Exception {
        System.out.println(username);
        System.out.println(password);

        String decipher = RSAUtils.decryptBase64(password);
        System.out.println(decipher);
        return null;
    }

}

struts.xml配置action

<?xml version="1.0" encoding="gb2312" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
    "http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
    <constant name="struts.i18n.encoding" value="gb2312"/>
    <package name="chris" extends="struts-default">

        <!-- 配置login -->
        <action name="passwordEncrypt" 
            class="com.chris.encryption.PasswordEncrypt">
        </action>
        <action name="login"
            class="com.chris.encryption.Login">
        </action>
    </package>
</struts>

参考链接:

[1]http://blog.csdn.net/sinat_29508201/article/details/51648572

有错误还请指出,共同进步。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在前端使用 HTML 实现选择一张数据表的字段进行填充,需要使用后端Java 代码来实现与数据库的交互。一般来说,可以使用 JavaJSP 或者 Servlet 技术来实现数据的传输和交互。 以下是一个简单的示例,展示了如何在前端使用 HTML 和 JavaScript 实现选择一张数据表的字段进行填充,同使用后端Java 代码来实现与数据库的交互。 首先,我们需要在 HTML 中创建一个输入表单,并为其指定一个唯一的标识符,例如: ```html <form id="myForm"> <label for="input1">输入框1:</label> <input type="text" id="input1" name="input1"><br> <label for="input2">输入框2:</label> <input type="text" id="input2" name="input2"><br> <label for="field">选择字段:</label> <select id="field" name="field"> <option value="">请选择字段</option> <option value="field1">字段1</option> <option value="field2">字段2</option> <option value="field3">字段3</option> <!-- 其他选项 --> </select> <input type="button" value="填充" onclick="fillInput()"> </form> ``` 上述代码中,我们创建了一个输入表单,并为其指定了一个唯一的标识符`myForm`。在表单中,我们创建了两个输入框`input1`和`input2`,以及一个下拉选项`field`,用于选择数据表的字段。同,我们创建了一个按钮,用于触发填充操作。 接下来,我们可以使用 JavaScript 代码来实现在选择数据表字段,自动填充所选字段对应的值的功能。例如: ```javascript // 获取表单元素 var form = document.getElementById("myForm"); // 获取选择字段的下拉选项 var field = form.elements["field"]; // 填充输入框的方法 function fillInput() { // 获取选中的字段名 var fieldName = field.value; // 发送请求,获取字段值 var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { if (xhr.readyState == 4 && xhr.status == 200) { // 解析响应数据,获取字段值 var fieldValue = xhr.responseText; // 将字段值填充到相应的输入框中 if (fieldName == "field1") { form.elements["input1"].value = fieldValue; } else if (fieldName == "field2") { form.elements["input2"].value = fieldValue; } // 其他字段对应的输入框 } }; xhr.open("GET", "/getData?field=" + fieldName, true); xhr.send(); } ``` 在上述代码中,我们首先获取了表单元素,并使用`form.elements`属性获取了选择字段的下拉选项。然后,我们使用`XMLHttpRequest`对象发送了一个 GET 请求,请求的 URL 中携带了选择的字段名`fieldName`。 在请求响应中,我们解析了响应数据,获取了字段值。然后,我们将字段值填充到相应的输入框中,使用了`form.elements`属性来获取输入框元素,并使用`value`属性来设置输入框的值。 在后端Java 代码中,我们需要根据选择的字段名来查询数据库,获取对应的字段值。以下是一个简单的 Servlet 的示例代码,用于处理前端发来的 GET 请求,并返回对应的字段值。 ```java @WebServlet("/getData") public class GetDataServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 获取选择的字段名 String fieldName = request.getParameter("field"); // 查询数据库,获取字段值 String fieldValue = queryFieldValue(fieldName); // 返回响应数据 response.setContentType("text/plain"); response.setCharacterEncoding("UTF-8"); response.getWriter().write(fieldValue); } // 查询字段值的方法 private String queryFieldValue(String fieldName) { // 根据字段名查询字段对应的值,例如从数据库中查询,或者使用一些预定义的映射关系等等。 // 这里只是一个示例,返回一个固定的字符串。 return "字段" + fieldName.substr(5) + "的值"; } } ``` 在上述代码中,我们使用`@WebServlet`注解将 Servlet 映射到 URL`/getData`上。在`doGet`方法中,我们获取了请求参数中的选择字段名`fieldName`,然后调用了`queryFieldValue`方法来查询数据库,获取对应的字段值。最后,我们使用`response.getWriter().write`方法将字段值作为响应数据返回给前端
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值