网络安全 管道符

1.Http接口安全概述:

       1.1、Http接口是互联网各系统之间对接的重要方式之一,使用http接口,开发和调用都很方便,也是被大量采用的方式,它可以让不同系统之间实现数据的交换和共享,但由于http接口开放在互联网上,那么我们就需要有一定的安全措施来保证不能是随随便便就可以调用;

       1.2、目前国内互联网公司主要采用两种做法实现接口的安全:

                一种是以支付宝等支付公司为代表的私钥公钥签名验证机制;

                一种是大量互联网企业都常采用的参数签名验证机制;

2. Http接口安全演进:

         2.1.完全开放的接口(完全开放)

         2.2.接口参数签名(基本安全)

         2.3.接口参数签名+时效性验证(更加安全)

         2.4.接口参数私钥签名公钥验签(固若金汤)

         2.5.接口参数签名+Https(金钟罩)

         2.6.口参数私钥签名公钥验签+Https(金钟罩)

         总之:安全是相对的,只有相对的安全,没有绝对的安全!

3.Http接口安全设计及应用

         3.1 接口参数私钥签名公钥验签

先来看看私钥+公钥的安全模式,这是一种更为安全的方式,它通过私钥和公钥实现接口的安全,目前互联网中主要是以支付宝

为代表的公司采用这种机制;(有很多开放平台也是采用这种机制) . 具体业务流所示:

网络安全 管道符_java

该签名是通过4个秘钥来实现的,分别是:

客户端应用私钥 , 客户端公钥 , 服务端应用私钥 , 服务端公钥.

私钥都是用来生成签名的,公钥都是用来解密的,客户端的公钥解密客户端的私钥生成的签名,服务端的公钥解密服务端的私钥生

成的签名,相信这样解释应该会比较好理解的.

        好了,下面就来看看是如何具体操作的,我的具体操作步骤:

        首先,4把密钥都是通过OpenSSL工具生成,你需要先获得这个工具:官方网站:https://www.openssl.org/

        介绍一下这个工具吧,OpenSSL 是一个开源的安全套接字层密码库,囊括主要的密码算法、常用的密钥和证书封装管理功能及SSL协议,并提供丰富的应用程序测试或其它目的使用;OpenSSL整个软件包大概可以分成三个主要的功能部分:SSL协议库、应用程序以及密码算法库;

        3.1.1确保Linux已经安装openssl  :  

               使用命令检查Linux是否已经安装openssl:yum list installed | grep openssl

               如果没有安装,则执行命令进行安装:yum install openssl openssl-devel -y

 3.1.2创建秘钥生成的目的地(文件夹):

ps : 我是在根目录中的soft文件夹下创建的

 mkdir server , mkdir client 先创建这两个文件,然后Linux会默认将生成的秘钥放入其中.

3.1.3 生成秘钥

  • 进入server文件,输入openssl  进入Openssl命令行;
  • 使用openssl生成私钥,执行如下命令:
  • genrsa -out rsa_private_key.pem 2048
  • 注意一点Java开发者需要将私钥转换成PKCS8格式,其他语言不用这一步操作,执行如下命令:
  • pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt -out rsa_private_key_pkcs8.pem
  • 使用openssl生成公钥,执行如下命令:
  • rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
  • 退出openssl命令行:exit
  • 经过以上步骤,我们可以在当前目录中(server)看到三个文件:
  •  rsa_private_key.pem(RSA私钥)
  •  rsa_private_key_pkcs8.pem(pkcs8格式RSA私钥)(我们java要使用的私钥是这一个)
  •  rsa_public_key.pem(对应RSA公钥)

         client端的秘钥与server端的秘钥生成一样,这里就不叙述了,想体验的朋友自己按照上一步操作再做一遍即可.

   

   3.2 Demo

      好了,现在就可以使用生成的秘钥来做一个简单的Demo来检验一下了.

      首先这里提供一个签名处理工具类:

      说明:该工具类依赖的包是java.security,该包JDK8才有,所以,如果使用下面这个Demo的话,建议检查自己的JDK是不是JDK8,如果是JDK8以下的版本,以下的Demo是用不了的.解决方法就是,使用第三方提供的依赖包,效果是相同的,依赖包如下:

<dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>RELEASE</version>
</dependency>

    以下是签名工具类:

    package com.kinglong.http.utils;
    
    import java.security.KeyFactory;
    import java.security.PublicKey;
    import java.security.Signature;
    import java.security.interfaces.RSAPrivateKey;
    import java.security.spec.PKCS8EncodedKeySpec;
    import java.security.spec.X509EncodedKeySpec;
    import java.util.Base64;
    
    /**
     * 签名处理工具类
     * 
     * @author haojinlong
     *
     */
    public class MyRSAUtils {
    	
    	public static final String CHARSET = "utf-8";
    
    	/**
    	 * RSA私钥签名
    	 * 
    	 * @param src 客户端传过来的原始参数
    	 * @param priKey  我们的客户端私钥
    	 * @return  
    	 * @throws Exception
    	 */
    	public static String sign (String src, String priKey) {
    		try {
    			KeyFactory fac = KeyFactory.getInstance("RSA");
    			byte[] pribyte = Base64.getDecoder().decode(priKey);
    			PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pribyte);
    			RSAPrivateKey privateKey = (RSAPrivateKey) fac.generatePrivate(keySpec);
    
    			Signature sigEng = Signature.getInstance("SHA1withRSA");
    			sigEng.initSign(privateKey);
    			sigEng.update(src.getBytes(MyRSAUtils.CHARSET));
    
    			byte[] signature = sigEng.sign();
    			return Base64.getEncoder().encodeToString(signature);
    
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		return null;
    	}
    
    	/**
    	 * RSA公钥验证签名
    	 * 
    	 * @param src  客户端穿过来的原始数据
    	 * @param sign  签名
    	 * @param publicKey 我们的客户端公钥
    	 * @return
    	 */
    	public static boolean signVerify (String sign, String src, String publicKey) {
    		try {
    			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    
    			//将公钥变为一个字节数组
    			byte[] encodedKey = Base64.getDecoder().decode(publicKey);
    			//使用秘钥工厂生成一个公钥对象pubKey
    			PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
    
    			//使用"SHA1WithRSA"算法,生成签名对象signature
    			Signature signature = Signature.getInstance("SHA1WithRSA");
    			signature.initVerify(pubKey);
    			signature.update(src.getBytes(MyRSAUtils.CHARSET));
    
    			boolean bverify = signature.verify(Base64.getDecoder().decode(sign));
    			return bverify;
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		return false;
    	}
    }

      下面是签名时需要的辅助工具类:

      package com.kinglong.http.HttpUtils;
      
      import java.util.Iterator;
      import java.util.Map;
      import java.util.Set;
      import java.util.TreeMap;
      /**
      *生成签名需要的辅助工具类
      */
      public class SignUtils {
      	/**
      	*将传进来的无序参数,转换为有序的字符串输出
      	*/
          public static String generateSortSign(Map<String,Object>paramMap){
      
              Map<String,Object> treeMap = new TreeMap<String, Object>(paramMap);
              Set<Map.Entry<String,Object>> entrySet = treeMap.entrySet();
              Iterator<Map.Entry<String,Object>> iterator = entrySet.iterator();
              StringBuffer stringBuffer = new StringBuffer();
      
              while (iterator.hasNext()){
      
                  Map.Entry<String,Object> entry=iterator.next();
                  String keys = entry.getKey();
                  String value = (String) entry.getValue();
                  stringBuffer.append(keys).append(value);
      
              }
              return  stringBuffer.toString();
      
          }
      
      }

        客户端代码:

        package com.kinglong.http.controller;
        
        import com.alibaba.fastjson.JSONObject;
        import com.kinglong.http.HttpUtils.HttpClientUtils;
        import com.kinglong.http.HttpUtils.SignUtils;
        import com.kinglong.http.constans.Constans;
        import com.kinglong.http.utils.MyRSAUtils;
        
        import java.util.Date;
        import java.util.Map;
        import java.util.concurrent.ConcurrentHashMap;
        
        public class HttpClient {
        
        
            public static void main(String[] args) {
        
                demo();
        
            }
        
            public static void demo(){
                String url ="http://localhost:8080/api/verifydemo";
        
        	//这里仅做演示使用,所以随手写了几个信息
                String realName = "我是验证信息";
                String phone = "17000000000";
                String idCard = "6403021992120511111";
                String bankCard = "5555555555555555555555";
        
                //封装参数
                Map<String,Object> paramMap = new ConcurrentHashMap<String, Object>();
                paramMap.put("realName",realName);
                paramMap.put("phone",phone);
                paramMap.put("idCard",idCard);
                paramMap.put("bankCard",bankCard);
        
        	//生成客户端签名,注意看,客户端这里生成签名的时候是使用的客户端私钥Constans.CLIENT_PRIVATE_KEY
                String sign = MyRSAUtils.sign(SignUtils.generateSortSign(paramMap),Constans.CLIENT_PRIVATE_KEY);
                paramMap.put("sign",sign);
        
        	//发送请求时注意:因为肯定会不可避免的要输出中文字符,所以记得在使用HttpClient通信的时候,设置编码格式为utf-8
        	//否则,我想你的签名验证成功的概率基本等于让两条平行线相交成功的概率
                String json = HttpClientUtils.doPostByEncode(url,paramMap,"utf-8");
        
                //解析json字符串
                JSONObject jsonObject = JSONObject.parseObject(json);
                String code = jsonObject.getString("code");
                String erroMessage = jsonObject.getString("erroMessage");
                JSONObject object = jsonObject.getJSONObject("object");
                String result = object.getString("result");
                String ret_sign = object.getString("ret_sign");//服务端发回的签名
                String resultDesc = object.getString("resultDesc");
        
                //封装参数准备进行验证该返回信息是否是由服务端发回的
        	//验证时的参数可以根据自己公司的规范去选择,我这里就选了这两个参数,因为偷懒没有生成新的map,所以这里需要clear一下.
                paramMap.clear();
                paramMap.put("result",result);
                paramMap.put("resultDesc",resultDesc);
        
              //调用签名验证工具类进行签名验证
              //重点!!!敲黑板啦!!注意看,这里使用的是服务端的公钥来解密服务端发送的签名的,很多人肯定使用了客户端公钥来解密,必然是失败的
              //同理,在服务端要是用客户端的公钥解密客户端发送的签名,这个前面的流程图我觉得已经说得很明确了
          boolean isTrue = MyRSAUtils.signVerify(ret_sign,SignUtils.generateSortSign(paramMap),Constans.SERVER_PUBLIC_KEY);
        
                if (isTrue){
                    System.out.println("返回正确信息,可以进行下一步操作");
                }else {
                    System.out.println("返回错误信息,不可以进行下一步操作");
                }
        
            }
        }

          下面是客户端使用的公共常量类:

          package com.kinglong.http.constans;
          
          public class Constans {
                  //客户端私钥
              public static final String CLIENT_PRIVATE_KEY="MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQClEAp0NDHtb9w5iJfyNOh6DeCRv0RjGFA1CIQ6ZxpfIc65h03hUGsDjcZtWQQZf7d30hiVCcQLylJYJidHQbPcDWULRhObgUxFIFQ37UW8c8DHDiHPNVRjH47ePi9sZIYbVuaWOJkS9NAoSDTRDA1vS7ewWosA9WyUSEuWSEm6eQQV02nlhf/cIsu3biDmq8Y9ffg9lLgEYbH4VQu6bRXgqpy90OxFh3Jh16nbAZXqAJMKCZyJYo5B9ZN4No8Q/EMZe98DNFybOod7WTuQmrS5FM0vCsjQpczBwn+dny5grWl4YgUYgAWOnvPr2iMXVXLqbQjcVEMFKwr/71K9yVehAgMBAAECggEBAJi6nvGm2gu41SznFrEmA3XsIT66m6yVcqGfn7nqbJxZy84fRBCXOG2xYUkMdJ6jbj+QRu6geqXuLwMhSnbEdIfIXRZxYPMiUFAl+cdF5KDa+iU1DlOMJOkS6j75iyfgW7YwUmvtMrY3j+O17CkB3ex9QxoKrVPVwwHxYv9LI+1FT0Fd3157gIbkBTdXnKUc4O4Z4/FTcvPYNR2h9O79xQbcx0clUbj61yQxkxVyN25plxxAVoUW7mKNleH6nFAkeb/gYxLdwlUHm53cYowSDtbzo4udB6qPWj/PvCVgu7UatnEhcyX9ZKCBmrX3+EvWTw9A9dTDSMu4D9CX2QsUq4ECgYEA2pTWhw6ulzWlORu12WcUxDzCVuKV7dGXCQ2MRnGELLm7HzAmRIjd0LubGWAKwUNa6NhWVNsupI8/hDh3hyjGAiTVn0gowDVQj4s/vIx5aYMsg6nxzUl3KrjBJyORHnY8+fFp5V1SHr0G6jOTynsqX0ONMpNZ/zyxiOQG5vGs7A8CgYEAwVHJAe0Eqz2jwLHA10Afsh3vS2Otcjj1cj9jxz1ZFoYIbD64Mc77bem+9x7xpI4w6/WezUOO4gZ8RaAh7PpyMWbTwzq0QHS7bSzKMfpRALyVf7HyIS/QuTUA0oLZXx9vk4wAe0rZBNFuuEtyU3XgHz8OSY/uHeTXJWYtJHTIkU8CgYAD6YgRcMTVNgOYCxPtKTgo7wF3dqTCVe8DHXf2Rs/b0RM1UrJMpbp6ovD6ukpW/TKiWkTpTeb+0QWNA0m4ZJVusmQUbsEz94BSoWZppIYDynJAhQkr6HW2kQn7/ln5lpouyxBfJ5VxsWZvSK8Lf7rZa6caUaLZu6dd0N8CwS6cJwKBgD74B9RTwtiQXF1wyNKUNX7MF1zkG+P/v5s2IKcOSY13nRi9GTxIIke8ApL2BlnGYxMIz3Am2EyxNhtrvIE3VqjWyJVn8ryoCUDXfQjocygdRUjxyl+a9o7NP/ZR3sIIOEzEJogCakwSd9EZ6iRbWeRzopC9jB86ogWxkXS1gXsrAoGAEOvVsv8lpY+TCs3Q78pnedwFIXXkrOknrXq2gb+WHmSSDCELOaqWsX73rdbW4IcmJ6kT2d5bn6hH+/2Zw/+Xpy6maBeLxxscXBfLHwT/85YG5z21LuyikB7ht/tZCNxQOjEfvo5MdCwNN6GhpPSVwNjLAvtiImJYnlDuGPaG+RU=";
          
          	//服务端公钥
              public static final String SERVER_PUBLIC_KEY="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqlG1v814kyQIEpLQnyxo/4RUku8PE+csGzH073XoW8xPdXAH8C7Y3isyDKSClTEGeS/SaqioYPFI+YlD0Eag1DEoVPkDcJeWsPv4FZr2ZO2wCenwqUrH5BM7ZapSBLenkgdhTF3SIUJMrTfJPaRJM1wb75SPawHO1zueM0cvcbeGNJOyCG69XPhour0Cei/HcflY3bXVx9kKH8vvAmbosAOrIwwdGSnV1YqSlApBmoobGYcaFPv5Clntghq+6P1ut2RSOrKinr0Q4wc4kIpnSY+j2oQ20OZ7rZXuLyGmMSsglvGwgTIoxHqkXpWP3qGFmYHSQgGCMFWxlT1t3e1AawIDAQAB";
          }

            ok,客户端就齐活了,下面是服务端:

            服务端使用的是springboot框架,以下是pom文件

            <?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>com.kinglong.http</groupId>
            	<artifactId>http-server</artifactId>
            	<version>0.0.1-SNAPSHOT</version>
            	<packaging>jar</packaging>
            
            	<name>http-server</name>
            	<description>Demo project for Spring Boot</description>
            
            	<parent>
            		<groupId>org.springframework.boot</groupId>
            		<artifactId>spring-boot-starter-parent</artifactId>
            		<version>1.5.10.RELEASE</version>
            		<relativePath/> <!-- lookup parent from repository -->
            	</parent>
            
            	<properties>
            		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
            		<java.version>1.8</java.version>
            	</properties>
            
            	<dependencies>
            		<dependency>
            			<groupId>org.springframework.boot</groupId>
            			<artifactId>spring-boot-starter-web</artifactId>
            		</dependency>
            
            		<dependency>
            			<groupId>org.springframework.boot</groupId>
            			<artifactId>spring-boot-starter-test</artifactId>
            			<scope>test</scope>
            		</dependency>
            
            		<dependency>
            			<groupId>commons-lang</groupId>
            			<artifactId>commons-lang</artifactId>
            			<version>RELEASE</version>
            		</dependency>
            
            
            		<dependency>
            			<groupId>commons-codec</groupId>
            			<artifactId>commons-codec</artifactId>
            			<version>RELEASE</version>
            		</dependency>
            
            
            		<dependency>
            			<groupId>com.alibaba</groupId>
            			<artifactId>fastjson</artifactId>
            			<version>1.2.45</version>
            		</dependency>
            
            	</dependencies>
            
            	<build>
            		<plugins>
            			<plugin>
            				<groupId>org.springframework.boot</groupId>
            				<artifactId>spring-boot-maven-plugin</artifactId>
            			</plugin>
            		</plugins>
            	</build>
            
            </project>

              说明:服务端的签名生成类,签名生成的辅助类都与客户端相同,所以,这里就不写了.

              服务端的公共常量类:

              package com.kinglong.http.constans;
              
              public class Constans {
              	//服务端私钥
                  public static final String SERVER_PRIVATE_KEY="MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCqUbW/zXiTJAgSktCfLGj/hFSS7w8T5ywbMfTvdehbzE91cAfwLtjeKzIMpIKVMQZ5L9JqqKhg8Uj5iUPQRqDUMShU+QNwl5aw+/gVmvZk7bAJ6fCpSsfkEztlqlIEt6eSB2FMXdIhQkytN8k9pEkzXBvvlI9rAc7XO54zRy9xt4Y0k7IIbr1c+Gi6vQJ6L8dx+VjdtdXH2Qofy+8CZuiwA6sjDB0ZKdXVipKUCkGaihsZhxoU+/kKWe2CGr7o/W63ZFI6sqKevRDjBziQimdJj6PahDbQ5nutle4vIaYxKyCW8bCBMijEeqRelY/eoYWZgdJCAYIwVbGVPW3d7UBrAgMBAAECggEBAJtfkxf4T4iblCmteVfb4aVHiQfJwc18VEYy2qkgvOoRhmMx4mv/sKNscGoMIXwMj0U6lQ/r8D8PnmzWBeEYrVslxQ9PYw3xm+y0z+qVxTTpiHBi08L8j0HHMaZbLBtVly6mQOKzrB/fJafXfmQXXRfXbTywH+2UZqb+oiFRTTzEnFMyku5HquA27Mp+K4KNFTVaKiCSadwz+XyFOf1cmUn4oRlYnhgbMKgn2JSyQLfJ5SSgYhnxat1Qbg1HDhOzo6L/NQwCkTzo3B52X56EQXZkk2p1pVRZiwaP/3FCHEenOv9jy+ZffdUFECRCv0Aw2isWqZ4zuVrgWCI801W/AVECgYEA0gwkMSHWlJaGtWhYifgWcOSr/v9l/SAiD0VN57j4THWIAq30WtOVE/ta4XhbSasxcHJIqNckq2inEm2b3jwcS7YKzlfKGl9xw8uL3yVM1YXtKwGrJr1xk8pcWOVBmFaAd8BaOHwsMkE8EhgiwZSctTbmRNeiOz6lIOj2aDu6fE0CgYEAz5SPKeNay00LIGk4Os+Zev1JPhwW4tfwTJxXV97TjvgYoRwUwV6XNjiXoxQD5iOXieK7Cy0GDMzJWxXpmEpI5BVv2X6GMkkH5iXz4rGtzsMNWZ5lF3d2PpRLvRIrSi3btevTohN7UkogyjEPhuEnV47Emsev36lB+bcJwgLBK5cCgYAuEaemdwt/T3yAMUCqEhWp8R2gMhgGapPN0Z+CoVkkO+r223xqp1ldJpYKOcGb6MZRKV+yWG2cgrmSGyRCm+CA4o6AL1UOb7yd+vjUmnO9qUAZXKZTOt28Unfqr22xoddPbIrdNK7k3tX0CgMlfhjYzg+3LaxRXi4Nh8rzlZYTSQKBgBahgq41bEun3aOt9QRsZ7ZB8P9FfrVCh59CmD8rOvNmVwERl62xS1kM+HM+FmK71KSixHOmd/djSDyW+f2xc5ryP1x979GBpsvPrXQ0nNdi6oyvuSPC0XBnKI63cWLH9yExUcRkzVgeXs7MZH33BBwGo6agSKtgv6Gi8/xj4n2HAoGBALD55ZzDDrB17ZOQSuEnn45R3FA62BGipCM8HFdZySeEOf9IPoOxy2xmzQtMc2VESRQeviw92E5gxNxrRgIHSQvPJryaHOjoMKI9+kDBejZvBEHWi23E4tobPUOUH/jBJJQ7Ue5aRB6IS/jlMzmVhan8vefnEXRDT5EnSfxV3Pa6";
              	//客户端公钥
                  public static final String CLIENT_PUBLIC_KEY="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApRAKdDQx7W/cOYiX8jToeg3gkb9EYxhQNQiEOmcaXyHOuYdN4VBrA43GbVkEGX+3d9IYlQnEC8pSWCYnR0Gz3A1lC0YTm4FMRSBUN+1FvHPAxw4hzzVUYx+O3j4vbGSGG1bmljiZEvTQKEg00QwNb0u3sFqLAPVslEhLlkhJunkEFdNp5YX/3CLLt24g5qvGPX34PZS4BGGx+FULum0V4KqcvdDsRYdyYdep2wGV6gCTCgmciWKOQfWTeDaPEPxDGXvfAzRcmzqHe1k7kJq0uRTNLwrI0KXMwcJ/nZ8uYK1peGIFGIAFjp7z69ojF1Vy6m0I3FRDBSsK/+9SvclXoQIDAQAB";
              
              }

                服务端接口:

                package com.kinglong.http.controller;
                
                import com.kinglong.http.constans.Constans;
                import com.kinglong.http.rto.ResponseObject;
                import com.kinglong.http.utils.MyRSAUtils;
                import com.kinglong.http.utils.SignUtils;
                import org.apache.commons.lang.StringUtils;
                import org.springframework.stereotype.Controller;
                import org.springframework.web.bind.annotation.RequestMapping;
                import org.springframework.web.bind.annotation.RequestParam;
                import org.springframework.web.bind.annotation.ResponseBody;
                
                import java.util.Date;
                import java.util.Map;
                import java.util.concurrent.ConcurrentHashMap;
                
                @Controller
                public class HttpController {
                
                    @RequestMapping("/api/verifydemo")
                    @ResponseBody
                    public Object demo(@RequestParam(value = "realName")String realName,
                                           @RequestParam(value = "phone")String phone,
                                           @RequestParam(value = "idCard")String idCard,
                                           @RequestParam(value = "bankCard")String bankCard,
                                           @RequestParam(value = "sign")String sign){
                
                        ResponseObject responseObject = new ResponseObject();
                        Map<String,Object> map = new ConcurrentHashMap<String,Object>();
                
                	//签名参数验证
                        if (StringUtils.isEmpty(realName)){
                
                            responseObject.setErroMessage("真实姓名不能为空");
                            responseObject.setCode("0000");
                
                        }else if (StringUtils.isEmpty(phone)){
                
                            responseObject.setErroMessage("手机号不能为空");
                            responseObject.setCode("0000");
                
                        }else if (StringUtils.isEmpty(idCard)){
                
                            responseObject.setErroMessage("身份证不能为空");
                            responseObject.setCode("0000");
                
                        }else if (StringUtils.isEmpty(bankCard)){
                
                            responseObject.setErroMessage("银行卡不能为空");
                            responseObject.setCode("0000");
                
                        }else if (StringUtils.isEmpty(sign)){
                
                            responseObject.setErroMessage("签名不能为空");
                            responseObject.setCode("0000");
                
                        }else {
                                //封装参数进行验证
                                map.put("realName",realName);
                                map.put("phone",phone);
                                map.put("idCard",idCard);
                                map.put("bankCard",bankCard);
                
                		//注意看,这里使用的就是客户端的公钥进行签名的解密
                               boolean isTrue = MyRSAUtils.signVerify(sign,SignUtils.generateSortSign(map),Constans.CLIENT_PUBLIC_KEY);
                
                                if (!isTrue){
                
                                    responseObject.setErroMessage("签名有误,请核查后再次尝试");
                                    responseObject.setCode("0000");
                            }
                        }
                
                        //0000是失败,1111是成功
                        String code = responseObject.getCode();
                        if(code!=null && code.equals("0000")){
                
                            map.clear();
                            map.put("result","0000");
                            map.put("resultDesc",responseObject.getErroMessage());
                	    
                	    //使用服务端私钥生成返回的签名
                            String ret_sign = MyRSAUtils.sign(SignUtils.generateSortSign(map),Constans.SERVER_PRIVATE_KEY);
                            map.put("ret_sign",ret_sign);
                            responseObject.setObject(map);
                
                        }else {
                
                            map.clear();
                            map.put("result","ok");
                            map.put("resultDesc","验证通过");
                
                	    //使用服务端私钥生成返回的签名
                            String ret_sign = MyRSAUtils.sign(SignUtils.generateSortSign(map),Constans.SERVER_PRIVATE_KEY);
                            map.put("ret_sign",ret_sign);
                            responseObject.setObject(map);
                            responseObject.setCode("1111");
                            responseObject.setErroMessage("验证成功");
                
                        }
                
                        return responseObject;
                    }
                
                }

                  over,以上就是使用私钥+公钥进行http接口安全设计的简单上手示例.

                  个人觉得,能把这个私钥公钥的搞明白了,其他的几个接口安全设计也就不在话下了,基本看一下流程图就能了然于心了.这里就放出参数安全设计的流程图,具体代码就不写了,有兴趣的可以尝试着做一下.

                  为了方便练习的盆友快速理解,那就顺带提几个需要注意的点吧.

                  1. 在做:"接口参数签名+时效性验证(更加安全)"时,注意服务端返回的签名就不需要再传时间戳了,理应是要传的,但是一般很少有人这么做.不过,要不要这么做,也得看公司的要求嘛.
                  2. 在拼装秘钥的时候,注意字符串首先得进行排序,不管是升序还是降序,亦或是其他的顺序(比如公司要求的顺序),如果不先按照一个约定的顺序进行排序,那么势必会造成客户端与服务端参数的字符串排列顺序不同,致使无法验证成功.这里就提供一个简便的排序工具,并且使用MD5进行16进制加密

                  网络安全 管道符_网络安全 管道符_02

                   

                  网络安全学习路线

                  对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。

                  同时每个成长路线对应的板块都有配套的视频提供:

                  需要网络安全学习路线和视频教程的可以在评论区留言哦~

                  最后
                  • 如果你确实想自学的话,我可以把我自己整理收藏的这些教程分享给你,里面不仅有web安全,还有渗透测试等等内容,包含电子书、面试题、pdf文档、视频以及相关的课件笔记,我都已经学过了,都可以免费分享给大家!

                  给小伙伴们的意见是想清楚,自学网络安全没有捷径,相比而言系统的网络安全是最节省成本的方式,因为能够帮你节省大量的时间和精力成本。坚持住,既然已经走到这条路上,虽然前途看似困难重重,只要咬牙坚持,最终会收到你想要的效果。

                  黑客工具&SRC技术文档&PDF书籍&web安全等(可分享)

                  结语

                  网络安全产业就像一个江湖,各色人等聚集。相对于欧美国家基础扎实(懂加密、会防护、能挖洞、擅工程)的众多名门正派,我国的人才更多的属于旁门左道(很多白帽子可能会不服气),因此在未来的人才培养和建设上,需要调整结构,鼓励更多的人去做“正向”的、结合“业务”与“数据”、“自动化”的“体系、建设”,才能解人才之渴,真正的为社会全面互联网化提供安全保障。

                  特别声明:
                  此教程为纯技术分享!本教程的目的决不是为那些怀有不良动机的人提供及技术支持!也不承担因为技术被滥用所产生的连带责任!本教程的目的在于最大限度地唤醒大家对网络安全的重视,并采取相应的安全措施,从而减少由网络安全而带来的经济损失

                  ### 小迪安全30天RCE漏洞概述 远程代码执行(Remote Code Execution, RCE)是一种高危漏洞,允许攻击者通过网络向目标系统发送恶意代码并被执行。这种漏洞通常源于应用程序未能正确验证用户输入的数据,导致恶意数据被当作可执行代码处理[^2]。 在Web开发环境中,无论是基于Linux还是Windows系统的应用,都可能因不当使用某些危险函数而引发RCE漏洞。这些危险函数包括但不限于`eval()`、`exec()`、`shell_exec()`等。如果开发者未对传入的参数进行严格校验,则可能导致任意代码或命令被执行的情况发生[^3]。 对于检测手段而言,可以采用多种方式来发现潜在存在的RCE风险点。其中较为常见的有白盒测试中的静态代码分析即代码审计;而在黑盒渗透过程中则更多依赖于自动化扫描工具如AWVS、XRay等辅助完成初步排查工作之外还需要结合人工经验针对特定业务逻辑深入挖掘隐藏更深的安全隐患。 至于防御措施方面除了常规建议像及时更新补丁版本外还需特别注意以下几点:一是尽可能避免调用那些已知存在较高安全隐患的功能模块;二是加强对外部可控变量值范围的有效限制并通过正则表达式等方式进一步增强过滤机制强度;三是考虑部署专业的防火墙类产品作为额外防护层以抵御来自外界未知威胁入侵尝试。 ### 管道的使用方法 管道(`|`) 是一种用于连接两个程序的标准输出与标准输入之间的特殊字,在Unix/Linux Shell编程中有广泛的应用场景之一就是构建复杂的命令链路实现单一指令难以达成的任务目的。例如当我们想要查找当前目录下所有扩展名为“.txt”的纯文本文件并将它们的内容按字母顺序排序最后保存到一个新的汇总文档当中去的时候就可以这样写: ```bash find . -name "*.txt" | xargs cat | sort > all.txt ``` 上述例子中第一个部分 `find . -name "*.txt"` 找到了合条件的目标列表交给第二个环节 `xargs cat` 去读取具体每一个匹配项的实际内容再传递给第三个阶段 `sort` 完成最终整理动作之后重定向存储起来形成完整的操作流程[^4]。 另外值得注意的是有时候为了绕过一些简单的字串替换型防护策略也可以巧妙运用反引号 `` 或者其他组合形式比如 `$()` 来达到相同的效果如下所示当直接书写 system('whoami') 被拦截时不妨试试下面这种方式或许就能奏效了呢? ```php <?php echo `whoami`; ?> ``` 或者是这样的PHP语句结构也能起到相应的作用: ```php $c='id'; echo shell_exec($c); ``` 以上两种情况均利用了不同语法特性规避掉了原始黑名单模式下的简单判断规则从而实现了预期功能需求[^5]。
                  评论
                  添加红包

                  请填写红包祝福语或标题

                  红包个数最小为10个

                  红包金额最低5元

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

                  抵扣说明:

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

                  余额充值