• 一种简单的登录加密方案


    该方案使用RSA加密和解密。

      每次登录前,客户端从服务器端获取公钥和随机值。

      公钥用于加密明文;

      随机值可以加强每一次操作的安全性,随机值也加入明文中一并加密,服务端对随机值进行校验,校验后从缓存中销毁,这样就算被别人拿到加密后的密文再次发起请求,由于随机值已失效,请求也是无效的。

    下面以js客户端为例,演示一下流程:

    1、假设客户的密码以SHA256加密后存在数据库中

    2.、客户输入用户名和密码点击 “登录”后,客户端发起请求,从服务器端获取公钥和随机值。

    {
        "rand": "SAXpJg",
        "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCK+oqElHP94+1BhhiTKX0pzziepN+C5Ff/qgmind2XvD35eWlCqzypGIXBoki526ZbsqrssbxTy5imhthe4eUTenLGUKkUgYUmDWrus8NmJm6IlXuqbGHaEY1zocsnlqVezOMj0AIUq5L65Y6e5XnEf1ludSzTF73MtFTjW8TRyQIDAQAB"
    }

    3、客户端将用户输入的密码使用SHA256加密

    <!--下载地址:https://github.com/Caligatio/jsSHA -->
             <script type="text/javascript" src="sha.js"></script>
             <!--下载地址:https://github.com/travist/jsencrypt-->
              <script type="text/javascript" src="jsencrypt.js"></script>
              <script>
                      
                    //用户输入的密码
                    var password1 = '123456';
                    
                    //从服务端获得的公钥
                    var publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCK+oqElHP94+1BhhiTKX0pzziepN+C5Ff/qgmind2XvD35eWlCqzypGIXBoki526ZbsqrssbxTy5imhthe4eUTenLGUKkUgYUmDWrus8NmJm6IlXuqbGHaEY1zocsnlqVezOMj0AIUq5L65Y6e5XnEf1ludSzTF73MtFTjW8TRyQIDAQAB";
        
                    
                    //从服务端获得的随机值
                    var rand = 'SAXpJg';
                    
                    //SHA-256加密
                    var shaObj = new jsSHA("SHA-256", "TEXT");
                    shaObj.update(password1);
                    var hash = shaObj.getHash("HEX");
            
                    //组装明文:由加密后的密码和随机值组成
                    var text = hash + '|' + rand;
                    console.log("待加密的文本: " + text);
                    
                    //使用RSA公钥加密
                    var encrypt = new JSEncrypt();
                      encrypt.setPublicKey(publicKey);
                    
                    // password就可以发送到服务端进行解密校验了
                    var password = encrypt.encrypt(text);
                    
                    console.log("加密后的密文:" + password);
        
              </script>

      控制台打印出来的结果:

    待加密的明文:8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92|SAXpJg
    加密后的密文:dgUBkZPZgL76+zMbKckAxb3C072I8b4nqAZlWUD/24Hp7UpAgiKx4P90xgs1UhWM2qputsjgpsgXLCNUg2vtO9MxpQk6zWUbyh4cxL08UcmMv3KIMO5rnbFxKEmuIbQ2G/3UZT8c+w899ERLCpDVyHrKSijdpvVoKrB6PzyjP+w=

      然后将加密后的密文传到服务器端即可。

    4、服务器端代码

      RSAUtils.java

    import java.security.KeyPair;
    import java.security.KeyPairGenerator;
    import java.security.SecureRandom;
    import java.security.Security;
    import java.security.interfaces.RSAPrivateKey;
    import java.security.interfaces.RSAPublicKey;
    
    import javax.crypto.Cipher;
    
    import org.apache.commons.codec.binary.Base64;
    import org.bouncycastle.jce.provider.BouncyCastleProvider;
    
    
    /**
     * RSA 工具
     * @author Luxh
     *
     */
    public class RSAUtils {
        
        
        
        private static final String ALGORITHM = "RSA";
        
        private static final String PROVIDER = "BC";
        
        private static final String TRANSFORMATION = "RSA/None/PKCS1Padding";
        
        private static final int KEY_SIZE = 1024;
        
        private static KeyPair keyPair = null;
        
        
        /**
         * 初始化密钥对
         */
        static {
            try{
                 Security.addProvider(new BouncyCastleProvider());
                 SecureRandom secureRandom = new SecureRandom();
                 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM, PROVIDER);
                 keyPairGenerator.initialize(KEY_SIZE, secureRandom);
                 keyPair = keyPairGenerator.generateKeyPair();
            }catch(Exception e) {
                e.printStackTrace();
            }
        }
        
        
        /**
         * 获取公钥
         * @return
         */
        public static RSAPublicKey getRSAPublicKey() {
             return (RSAPublicKey)keyPair.getPublic();
        } 
        
        /**
         * 获取Base64编码的公钥
         * @return
         */
        public static String getBase64PublicKey() {
            RSAPublicKey publicKey = getRSAPublicKey();
            //return new String(Base64.encodeBase64(publicKey.getEncoded()));
            return Base64.encodeBase64String(publicKey.getEncoded());
        } 
        
        
        /**
         * 使用公钥加密
         * @param data
         * @return
         */
        public static String encrypt(byte[] data) {
            String ciphertext = "";
            try {
                Cipher cipher = Cipher.getInstance(keyPair.getPublic().getAlgorithm());
                cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic());
                ciphertext = Base64.encodeBase64String(cipher.doFinal(data));
            } catch (Exception e) {
                e.printStackTrace();
            }
            return ciphertext;
        }
        
        
        
        /**
         * 使用私钥解密
         * @param ciphertext
         * @return
         */
        public static String decrypt(String ciphertext) {
            String plaintext = "";
            try {
                Security.addProvider(new BouncyCastleProvider());
                Cipher cipher = Cipher.getInstance(TRANSFORMATION, PROVIDER);
                RSAPrivateKey pbk = (RSAPrivateKey)keyPair.getPrivate();
                cipher.init(Cipher.DECRYPT_MODE, pbk);
                byte[] data = cipher.doFinal(Base64.decodeBase64(ciphertext));
                plaintext = new String(data);
            }catch (Exception e) {
                e.printStackTrace();
            }
            return plaintext;
        }
        
    }
    View Code

      DemoController.java

    import java.util.Map;
    
    import javax.servlet.http.HttpServletRequest;
    
    import org.apache.commons.lang3.RandomStringUtils;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;
    
    import com.google.common.collect.Maps;
    
    import io.caimi.util.RSAUtils;
    
    @RestController
    public class DemoController {
        
        
        /**
         * 获取公钥和随机值
         * 
         */
        @RequestMapping("/secret")
        public Map<String, Object> secret(HttpServletRequest request) {
            
            Map<String, Object> resultMap = Maps.newHashMap();
            
            // 获取公钥
            String publicKey = RSAUtils.getBase64PublicKey();
            resultMap.put("publicKey", publicKey);
            
            // 生成随机值
            String rand =  RandomStringUtils.randomAlphabetic(6);
            resultMap.put("rand", rand);
            
            // 将生成的随机值存到session中,实际使用可以存到第三方缓存中,并设置失效时间
            request.getSession().setAttribute("rand", rand);
            
            return resultMap;
            
        }
        
        
        /**
         * 校验
         * 
         */
        @RequestMapping(value="/check", method=RequestMethod.POST)
        public String check(HttpServletRequest request) {
            // 取得密文
            String password = request.getParameter("password");
            
            // 解密
            String plaintext = RSAUtils.decrypt(password);
            
            String[] arr = plaintext.split("\|");
            
            // 校验随机值
            String rand = arr[1];
            String randInSession = (String) request.getSession().getAttribute("rand");
            //随机值失效
            request.getSession().removeAttribute("rand");
            
            if(!rand.equals(randInSession)) {
                return "非法的请求";
            }
            
            // 校验密码
            String passwd = arr[0];
            
            // 实际中根据用户名从数据库中查询出密码
            String realPasswd = "8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92"; 
            
            if(!realPasswd.equals(passwd)) {
                return "密码输入错误";
            }
            
            return "校验通过";
        }
        
    }
    View Code

      maven依赖的一些jar

    <dependency>
                <groupId>commons-codec</groupId>
                <artifactId>commons-codec</artifactId>
                <version>1.10</version>
            </dependency>
            <dependency>
                <groupId>org.bouncycastle</groupId>
                <artifactId>bcprov-jdk15on</artifactId>
                <version>1.54</version>
            </dependency>
            
            <dependency>
                <groupId>com.google.guava</groupId>
                <artifactId>guava</artifactId>
                <version>18.0</version>
            </dependency>
            
            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-lang3</artifactId>
                <version>3.4</version>
            </dependency>
            
  • 相关阅读:
    Ubuntu安装后root 用户无法使用的解决方法
    struts2 上传 文件 注意问题
    WinSCP无法连接 ubuntu 的解决方法
    TOMCAT 6 中配置HTTPS
    Linux上安装ImageMagick和JMagick
    linux 下 Nginx 0.8.40的安装
    Displaying icons in a Flex List control
    Styling the Alert control’s message text
    Displaying icons in a Flex ComboBox control
    Styling the Alert control’s title bar
  • 原文地址:https://www.cnblogs.com/luxh/p/5414205.html
Copyright © 2020-2023  润新知