web接口的安全

web接口的安全,第1张

概述Http接口由于很容易篡改和捕获,所有要对其作加密和签名处理。一个常见的系统架构图如下: 其中,加密和验签都在网关层实现。 RSA加密算法是一种非对称加密算法,可以通过RSA生成一对公钥和私钥,可以用这对公钥和私钥实现加解密和签名。 加密 假如A是客户端,B是服务器,B使用RSA生成一对公钥和私钥,将公钥发给A,A使用公钥对内容加密,传输给B,B使用私钥将内容解密。 验签 假如A是客户端,B是服务

http接口由于很容易篡改和捕获,所有要对其作加密和签名处理。一个常见的系统架构图如下:


其中,加密和验签都在网关层实现。

RSA加密算法是一种非对称加密算法,可以通过RSA生成一对公钥和私钥,可以用这对公钥和私钥实现加解密和签名。

加密

假如A是客户端,B是服务器,B使用RSA生成一对公钥和私钥,将公钥发给A,A使用公钥对内容加密,传输给B,B使用私钥将内容解密。

验签

假如A是客户端,B是服务器,A使用RSA生成一对公钥和私钥,将公钥发给B,A使用私钥制造签名,将签名和内容一起发给B,B使用公钥可以判断签名的真伪,然后决定是否处理。

例子 制造一对RSA 公钥/私钥
public class ClIEnt(){  main(String... args ){        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");        keyPairGen.initialize(512);//最少为512        KeyPair keyPair = keyPairGen.generateKeyPair();//生成一对公/私钥        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();//获取私钥        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();//获取公钥        HashMap keyMap = new HashMap<String,Object>(2);        keyMap.put(PUBliC_KEY,publicKey);        keyMap.put(PRIVATE_KEY,privateKey);        //RSAPublicKey使用Base64编码,转成String串,方便打印可见        String publicKeyString=(new BASE64Encoder()).encodeBuffer(publicKey.getEncoded());        String privateKeyString=(new BASE64Encoder()).encodeBuffer(privateKey.getEncoded());        System.out.println(publicKeyString);        System.out.println(privateKeyString);        //将公钥String串通过Base64解码,转变为类        byte[] keyBytes;        keyBytes = (new BASE64Decoder()).decodeBuffer(publicKeyString);        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);        PublicKey publicKey = keyFactory.generatePublic(keySpec);//转成了类        //将私钥String串通过Base64解码,转变为类        byte[] keyBytes;        keyBytes = (new BASE64Decoder()).decodeBuffer(key);        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);        return privateKey;//转成了类         }}
公钥加密/私钥解密

上面是获取公私钥的办法,注意在String转公私钥类的时候,使用的编码类不一样。下面是加密和解密

//公钥加密    public static byte[] encrypt(byte[] plainText,String publicKeyStr,RSAPublicKey rsaPublicKey) throws Exception {        PublicKey publicKey = getPublicKey(publicKeyStr);//        PublicKey publicKey = rsaPublicKey;        Cipher cipher = Cipher.getInstance("RSA");        cipher.init(Cipher.ENCRYPT_MODE,publicKey);        int inputLen = plainText.length;        ByteArrayOutputStream out = new ByteArrayOutputStream();        int offSet = 0;        int i = 0;        byte[] cache;        while (inputLen - offSet > 0) {            if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {                cache = cipher.doFinal(plainText,offSet,MAX_ENCRYPT_BLOCK);            } else {                cache = cipher.doFinal(plainText,inputLen - offSet);            }            out.write(cache,cache.length);            i++;            offSet = i * MAX_ENCRYPT_BLOCK;        }        byte[] encryptText = out.toByteArray();        out.close();        return encryptText;    }//私钥解密    public static byte[] decrypt(byte[] encryptText,String privateKeyStr,RSAPrivateKey rsaPrivateKey) throws Exception {        PrivateKey privateKey = getPrivateKey(privateKeyStr);//        PrivateKey privateKey = rsaPrivateKey;        Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);        cipher.init(Cipher.DECRYPT_MODE,privateKey);        int inputLen = encryptText.length;        ByteArrayOutputStream out = new ByteArrayOutputStream();        int offSet = 0;        byte[] cache;        int i = 0;        // 对数据分段解密        while (inputLen - offSet > 0) {            if (inputLen - offSet > MAX_DECRYPT_BLOCK) {                cache = cipher.doFinal(encryptText,MAX_DECRYPT_BLOCK);            } else {                cache = cipher.doFinal(encryptText,cache.length);            i++;            offSet = i * MAX_DECRYPT_BLOCK;        }        byte[] plainText = out.toByteArray();        out.close();        return plainText;    }
私钥加签/公钥验签

下面是签名以及验证签名

//私钥加签名    public static byte[] sign(byte[] data,String privateKeyStr) throws Exception {        PrivateKey priK = getPrivateKey(privateKeyStr);        Signature sig = Signature.getInstance(SIGNATURE_ALGORITHM);        sig.initSign(priK);        sig.update(data);        return sig.sign();    }//公钥验证    public static boolean verify(byte[] data,byte[] sign,String publicKeyStr) throws Exception {        PublicKey pubK = getPublicKey(publicKeyStr);        Signature sig = Signature.getInstance(SIGNATURE_ALGORITHM);        sig.initVerify(pubK);        sig.update(data);        return sig.verify(sign);    }
实际的应用

上面的例子验证了加密/解密,加签/验签的可行性,在实际的应用过程中,要实现上面的,需要准备两套签名,公钥都是公开的。
客户端需要持有客户端私钥,服务端公钥,服务端需要持有服务端私钥,客户端公钥。
这样,在A向B传参的过程中,A首先将使用B的公钥将参数加密,然后加上自己的私钥制造的签名。B接收到请求后,首先使用A的公钥验证签名的真伪,然后使用B的私钥解密参数。  
回调的时候也一样,B首先使用A的公钥加密,然后使用B的私钥加签名,然后A收到后,先验签名,没有问题后用A的私钥进行解密。

在上面的过程中,A,B均向对方发送了公钥,都保留自己的私钥,所以是安全的,但是关于A和B是什么时候向对方传递的公钥,有几次握手,还是要再看看资料的。

token、签名、加密

token主要是存储用户信息,工作流程如下:

用户登录,请求发送到认证服务器进行认证 认证服务器验证通过,返回一个token。 用户拿着token访问其他的API 其他服务器获取token去认证服务器认证,检查访问有效性 如果token合法,那么通过,不合法则要求重新登录

签名主要是防止篡改请求,工作流程如下:

客户端先列出需要发出请求参数 将请求参数和用户的secret按照一定的规则进行排列,然后用哈希散列算法将其变为一个签名串 将所有参数发送到服务器,服务器接收请求后,用同样的规律进行组装,也用同样的hash算法组装,比较签名串的异同,如果不一样,返回异常

加密主要是对不方便公开的信息进行处理,有堆成加密和非对称加密两种。对称加密有很多种算法,效率很高,因为只有一个密钥,在网络环境中,对称加密的一大缺点是密钥的管理与分配,换句话说,如何把密钥发送到需要解密你的消息的人的手里是一个问题。
非对称加密采用一个公钥和一个私钥,用公钥进行加密,用私钥进行解密。

常见的加密类型 md5:散列算法,将字符串散列成16进制的32位字符串 SHA:散列算法 DES\3DES\AES:对称加密算法 RSA\DSA\ECC:非对称加密算法 HMAC_md5\HMAC_SHA:散列算法,包含一个密钥和正文 Base64:一种编码形式,将非ASCII码的二进制转换成ASCII码的格式。虽然是可逆的,但是它的编码方式是公开的,无所谓加密,适合网络传输。 关于JWT

JWT(Json web token)
这是一个标准协议,JWT提供了一种用于发布接入令牌(Access Token),并对发布的签名接入令牌进行验证的方法。流程一般如下:

服务器设置一个私钥 用户登录成功后,服务器颁发一个令牌(token),里面包含了用户的信息。 用户拿到令牌后,带着令牌访问API

在上面的过程中,令牌由三部分组成,头文件(规定了哈希散列的方式),中间内容文件,包含了返给用户的信息,签名文件,由服务器产生的secret值和前面两个文件一起生成的哈希散列值。当用户带着token访问API的时候,可以解析出中间的内容。而且中间的内容一旦被伪造,那么签名的验证肯定无法通过,所有具有防篡改的功能。
在具体实施JWT的过程中,需要注意的问题由:token的作废问题,续签问题 。特别是续签问题,由于exp修改了,整个签名串就变了,jwt 的特性天然不支持续签!

public class JWTHelper {    private static final String SECRET = "X******XXXxxx**X*Xxx*";    public static String signJWT() throws IOException {        JWTSigner jwtSigner=new JWTSigner(SECRET);         Map<String,Object> claims = new HashMap<String,Object>();        ObjectMapper mapper = new ObjectMapper();        String JsonString = mapper.writeValueAsstring(new User(1000L,"zhangSan"));        claims.put("user",JsonString);        return jwtSigner.sign(claims);    }    public static<T> T unSignJWT(String  s,Class<T> tClass) throws SignatureException,NoSuchAlgorithmException,JWTVerifyException,InvalIDKeyException,IOException {        JWTVerifIEr verifIEr = new JWTVerifIEr(SECRET);        Map<String,Object> claims= verifIEr.verify(s);        String Json = (String)claims.get("user");        System.out.println(Json);        ObjectMapper objectMapper = new ObjectMapper();        return objectMapper.readValue(Json,tClass);    }}
总结

以上是内存溢出为你收集整理的web接口的安全全部内容,希望文章能够帮你解决web接口的安全所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1079673.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-27
下一篇 2022-05-27

发表评论

登录后才能评论

评论列表(0条)

保存