设计一个安全对外的API接口,需要考虑哪些方面?

本文详细介绍了确保外网API接口安全的方法,包括使用签名防止数据篡改,信息加密(如单向散列MD5和SHA1,对称加密DES,非对称加密RSA)与密钥管理,以及实施OAuth2.0授权框架。这些策略旨在保证数据完整性和防止非法访问。
摘要由CSDN通过智能技术生成

如何保证外网开放接口的安全性。

  • 使用加签名方式,防止数据篡改

  • 信息加密与密钥管理

  • 搭建OAuth2.0认证授权

  • 使用令牌方式

  • 搭建网关实现黑名单和白名单

一、令牌方式搭建搭建API开放平台

图片

方案设计:

1.第三方机构申请一个appId,通过appId去获取accessToken,每次请求获取accessToken都要把老的accessToken删掉

2.第三方机构请求数据需要加上accessToken参数,每次业务处理中心执行业务前,先去dba持久层查看accessToken是否存在(可以把accessToken放到redis中,这样有个过期时间的效果),存在就说明这个机构是合法,无需要登录就可以请求业务数据。不存在说明这个机构是非法的,不返回业务数据。

3.好处:无状态设计,每次请求保证都是在我们持久层保存的机构的请求,如果有人盗用我们accessToken,可以重新申请一个新的taken.

二、基于OAuth2.0协议方式

原理

第三方授权,原理和1的令牌方式一样

1.假设我是服务提供者A,我有开发接口,外部机构B请求A的接口必须申请自己的appid(B机构id)

2.当B要调用A接口查某个用户信息的时候,需要对应用户授权,告诉A,我愿同意把我的信息告诉B,A生产一个授权token给B。

3.B使用token获取某个用户的信息。

联合微信登录总体处理流程

  1. 用户同意授权,获取code

  2. 通过code换取网页授权access_token

  3. 通过access_token获取用户openId

  4. 通过openId获取用户信息

三、信息加密与密钥管理

  • 单向散列加密

  • 对称加密

  • 非对称加密

  • 安全密钥管理

1.单向散列加密

散列是信息的提炼,通常其长度要比信息小得多,且为一个固定长度。加密性强的散列一定是不可逆的,这就意味着通过散列结果,无法推出任何部分的原始信息。任何输入信息的变化,哪怕仅一位,都将导致散列结果的明显变化,这称之为雪崩效应。

散列还应该是防冲突的,即找不出具有相同散列结果的两条信息。具有这些特性的散列结果就可以用于验证信息是否被修改。

单向散列函数一般用于产生消息摘要,密钥加密等,常见的有:

  • MD5(Message Digest Algorithm 5):是RSA数据安全公司开发的一种单向散列算法,非可逆,相同的明文产生相同的密文。

  • SHA(Secure Hash Algorithm):可以对任意长度的数据运算生成一个160位的数值;

SHA-1与MD5的比较

因为二者均由MD4导出,SHA-1和MD5彼此很相似。相应的,他们的强度和其他特性也是相似,但还有以下几点不同:

  • 对强行供给的安全性:最显著和最重要的区别是SHA-1摘要比MD5摘要长32 位。使用强行技术,产生任何一个报文使其摘要等于给定报摘要的难度对MD5是2128数量级的操作,而对SHA-1则是2160数量级的操作。这样,SHA-1对强行攻击有更大的强度。

  • 对密码分析的安全性:由于MD5的设计,易受密码分析的攻击,SHA-1显得不易受这样的攻击。

  • 速度:在相同的硬件上,SHA-1的运行速度比MD5慢。

1、特征:雪崩效应、定长输出和不可逆。

2、作用是:确保数据的完整性。

3、加密算法:md5(标准密钥长度128位)、sha1(标准密钥长度160位)、md4、CRC-32

4、加密工具:md5sum、sha1sum、openssl dgst。

5、计算某个文件的hash值,例如:md5sum/shalsum FileName,openssl dgst –md5/-sha

2.对称加密

秘钥:加密解密使用同一个密钥、数据的机密性双向保证、加密效率高、适合加密于大数据大文件、加密强度不高(相对于非对称加密)

对称加密优缺点

  • 优点:与公钥加密相比运算速度快。

  • 缺点:不能作为身份验证,密钥发放困难

图片

DES是一种对称加密算法,加密和解密过程中,密钥长度都必须是8的倍数

 
public class DES {
 public DES() {
 }
 
 // 测试
 public static void main(String args[]) throws Exception {
  // 待加密内容
  String str = "123456";
  // 密码,长度要是8的倍数 密钥随意定
  String password = "12345678";
  byte[] encrypt = encrypt(str.getBytes(), password);
  System.out.println("加密前:" +str);
  System.out.println("加密后:" + new String(encrypt));
  // 解密
  byte[] decrypt = decrypt(encrypt, password);
  System.out.println("解密后:" + new String(decrypt));
 }
 
 /**
  * 加密
  * 
  * @param datasource
  *            byte[]
  * @param password
  *            String
  * @return byte[]
  */
 public static byte[] encrypt(byte[] datasource, String password) {
  try {
   SecureRandom random = new SecureRandom();
   DESKeySpec desKey = new DESKeySpec(password.getBytes());
   // 创建一个密匙工厂,然后用它把DESKeySpec转换成
   SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
   SecretKey securekey = keyFactory.generateSecret(desKey);
   // Cipher对象实际完成加密操作
   Cipher cipher = Cipher.getInstance("DES");
   // 用密匙初始化Cipher对象,ENCRYPT_MODE用于将 Cipher 初始化为加密模式的常量
   cipher.init(Cipher.ENCRYPT_MODE, securekey, random);
   // 现在,获取数据并加密
   // 正式执行加密操作
   return cipher.doFinal(datasource); // 按单部分操作加密或解密数据,或者结束一个多部分操作
  } catch (Throwable e) {
   e.printStackTrace();
  }
  return null;
 }
 
 /**
  * 解密
  * 
  * @param src
  *            byte[]
  * @param password
  *            String
  * @return byte[]
  * @throws Exception
  */
 public static byte[] decrypt(byte[] src, String password) throws Exception {
  // DES算法要求有一个可信任的随机数源
  SecureRandom random = new SecureRandom();
  // 创建一个DESKeySpec对象
  DESKeySpec desKey = new DESKeySpec(password.getBytes());
  // 创建一个密匙工厂
  SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");// 返回实现指定转换的
                   // Cipher
                   // 对象
  // 将DESKeySpec对象转换成SecretKey对象
  SecretKey securekey = keyFactory.generateSecret(desKey);
  // Cipher对象实际完成解密操作
  Cipher cipher = Cipher.getInstance("DES");
  // 用密匙初始化Cipher对象
  cipher.init(Cipher.DECRYPT_MODE, securekey, random);
  // 真正开始解密操作
  return cipher.doFinal(src);
 }
}
 
输出
 
加密前:123456
加密后:>p.72|
解密后:123456

3.非对称加密

非对称加密算法需要两个密钥:公开密钥(publickey:简称公钥)和私有密钥(privatekey:简称私钥)。

公钥与私钥是一对

  • 公钥对数据进行加密,只有用对应的私钥才能解密

  • 私钥对数据进行加密,只有用对应的公钥才能解密

过程:

  • 甲方生成一对密钥,并将公钥公开,乙方使用该甲方的公钥对机密信息进行加密后再发送给甲方;

  • 甲方用自己私钥对加密后的信息进行解密。

  • 甲方想要回复乙方时,使用乙方的公钥对数据进行加密

  • 乙方使用自己的私钥来进行解密。

  • 甲方只能用其私钥解密由其公钥加密后的任何信息。

特点:

  • 算法强度复杂

  • 保密性比较好

  • 加密解密速度没有对称加密解密的速度快。

  • 对称密码体制中只有一种密钥,并且是非公开的,如果要解密就得让对方知道密钥。所以保证其安全性就是保证密钥的安全,而非对称密钥体制有两种密钥,其中一个是公开的,这样就可以不需要像对称密码那样传输对方的密钥了。这样安全性就大了很多

  • 适用于:金融,支付领域

RSA加密是一种非对称加密

import javax.crypto.Cipher;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import org.apache.commons.codec.binary.Base64;
 
 
/**
 * RSA加解密工具类
 *
 * 
 */
public class RSAUtil {
 
 public static String publicKey; // 公钥
 public static String privateKey; // 私钥
 
 /**
  * 生成公钥和私钥
  */
 public static void generateKey() {
  // 1.初始化秘钥
  KeyPairGenerator keyPairGenerator;
  try {
   keyPairGenerator = KeyPairGenerator.getInstance("RSA");
   SecureRandom sr = new SecureRandom(); // 随机数生成器
   keyPairGenerator.initialize(512, sr); // 设置512位长的秘钥
   KeyPair keyPair = keyPairGenerator.generateKeyPair(); // 开始创建
   RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
   RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
   // 进行转码
   publicKey = Base64.encodeBase64String(rsaPublicKey.getEncoded());
   // 进行转码
   privateKey = Base64.encodeBase64String(rsaPrivateKey.getEncoded());
  } catch (NoSuchAlgorithmException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 }
 
 /**
  * 私钥匙加密或解密
  * 
  * @param content
  * @param privateKeyStr
  * @return
  */
 public static String encryptByprivateKey(String content, String privateKeyStr, int opmode) {
  // 私钥要用PKCS8进行处理
  PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyStr));
  KeyFactory keyFactory;
  PrivateKey privateKey;
  Cipher cipher;
  byte[] result;
  String text = null;
  try {
   keyFactory = KeyFactory.getInstance("RSA");
   // 还原Key对象
   privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
   cipher = Cipher.getInstance("RSA");
   cipher.init(opmode, privateKey);
   if (opmode == Cipher.ENCRYPT_MODE) { // 加密
    result = cipher.doFinal(content.getBytes());
    text = Base64.encodeBase64String(result);
   } else if (opmode == Cipher.DECRYPT_MODE) { // 解密
    result = cipher.doFinal(Base64.decodeBase64(content));
    text = new String(result, "UTF-8");
   }
 
  } catch (Exception e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  return text;
 }
 
 /**
  * 公钥匙加密或解密
  * 
  * @param content
  * @param privateKeyStr
  * @return
  */
 public static String encryptByPublicKey(String content, String publicKeyStr, int opmode) {
  // 公钥要用X509进行处理
  X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyStr));
  KeyFactory keyFactory;
  PublicKey publicKey;
  Cipher cipher;
  byte[] result;
  String text = null;
  try {
   keyFactory = KeyFactory.getInstance("RSA");
   // 还原Key对象
   publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
   cipher = Cipher.getInstance("RSA");
   cipher.init(opmode, publicKey);
   if (opmode == Cipher.ENCRYPT_MODE) { // 加密
    result = cipher.doFinal(content.getBytes());
    text = Base64.encodeBase64String(result);
   } else if (opmode == Cipher.DECRYPT_MODE) { // 解密
    result = cipher.doFinal(Base64.decodeBase64(content));
    text = new String(result, "UTF-8");
   }
  } catch (Exception e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  return text;
 }
 
 // 测试方法
 public static void main(String[] args) {
  /**
   * 注意: 私钥加密必须公钥解密 公钥加密必须私钥解密
   *  // 正常在开发中的时候,后端开发人员生成好密钥对,服务器端保存私钥 客户端保存公钥
   */
  System.out.println("-------------生成两对秘钥,分别发送方和接收方保管-------------");
  RSAUtil.generateKey();
  System.out.println("公钥:" + RSAUtil.publicKey);
  System.out.println("私钥:" + RSAUtil.privateKey);
 
  System.out.println("-------------私钥加密公钥解密-------------");
   String textsr = "11111111";
   // 私钥加密
   String cipherText = RSAUtil.encryptByprivateKey(textsr,
   RSAUtil.privateKey, Cipher.ENCRYPT_MODE);
   System.out.println("私钥加密后:" + cipherText);
   // 公钥解密
   String text = RSAUtil.encryptByPublicKey(cipherText,
   RSAUtil.publicKey, Cipher.DECRYPT_MODE);
   System.out.println("公钥解密后:" + text);
 
  System.out.println("-------------公钥加密私钥解密-------------");
  // 公钥加密
  String textsr2 = "222222";
 
  String cipherText2 = RSAUtil.encryptByPublicKey(textsr2, RSAUtil.publicKey, Cipher.ENCRYPT_MODE);
  System.out.println("公钥加密后:" + cipherText2);
  // 私钥解密
  String text2 = RSAUtil.encryptByprivateKey(cipherText2, RSAUtil.privateKey, Cipher.DECRYPT_MODE);
  System.out.print("私钥解密后:" + text2 );
 }
 
}

图片

四、使用加签名方式,防止数据篡改

客户端:请求的数据分为2部分(业务参数,签名参数),签名参数=md5(业务参数)

服务端:验证md5(业务参数)是否与签名参数相同

### 回答1: Java Web API 接口开发实例可以分为以下步骤: 1. 设计 API 接口:定义 API 接口的请求和响应数据格式、接口地址、请求方法等。 2. 编写 API 接口实现代码:根据设计好的接口定义编写具体的 API 实现代码,处理请求数据并生成响应数据。 3. 部署 API 接口代码:将 API 实现代码部署到服务器上,使其可以被其他应用程序或服务调用。 4. 测试 API 接口:使用 API 调试工具对接口进行测试,验证接口的功能和正确性。 5. 文档编写和发布:编写 API 接口的文档,并发布到合适的文档平台上,方便其他开发者使用和集成。 具体实现中,可以使用 Java 的框架(如 Spring、Spring Boot 等)来简化 API 接口开发和部署过程。同时,还可以使用常见的数据库(如 MySQL、MongoDB 等)来存储和管理 API 接口所需的数据。 ### 回答2: Java Web API接口开发实例 Java Web API是Web应用程序中最常用的一种技术。它通过一组标准和协议来允许Web应用程序与Web服务器之间相互通信。Java Web API通常被用于开发RESTful API接口,这种接口主要是基于HTTP协议和HTTP方法,以实现数据的传输和服务的调用。 下面将介绍一个Java Web API接口开发的实例。本实例主要实现的是一个简单的学生信息管理系统。 Step 1:准备工作 在开始开发Java Web API接口前,需要做好以下准备工作: 1.安装JDK和Eclipse开发环境。 2.下载并安装Tomcat Web Server。 3.使用Eclipse创建一个新的Java Web项目。 4.添加必要的依赖库。 Step 2:定义数据模型 在Java Web API接口中,需要使用数据模型来表示RESTful的资源。本例中定义的数据模型是学生信息,其中包括学生姓名、学号、性别、班级等信息。 Step 3:创建RESTful资源 在Java Web API接口中,需要使用RESTful风格的资源来实现数据的增删改查等操作,以此来实现对学生信息的管理。本例中,我们将使用以下HTTP方法来进行操作: 1.GET:获取学生信息列表和指定学号的学生信息。 2.POST:添加新的学生信息。 3.PUT:修改指定学号的学生信息。 4.DELETE:删除指定学号的学生信息。 Step 4:实现接口 根据RESTful接口的定义,我们需要分别实现以下请求: 1.获取学生信息列表:主要使用GET方法来实现,返回JSON格式的学生信息列表。 2.获取指定学号的学生信息:同样使用GET方法来实现,返回JSON格式的学生信息。 3.添加新的学生信息:使用POST方法来实现,在请求体中包含要添加的学生信息,返回成功或失败信息。 4.修改指定学号的学生信息:使用PUT方法来实现,在请求体中包含要修改的学生信息,返回成功或失败信息。 5.删除指定学号的学生信息:使用DELETE方法来实现,返回成功或失败信息。 Step 5:测试接口 使用Postman等工具来测试Java Web API接口的正确性,主要需要测试请求和响应的数据格式以及各类异常情况的处理。 总结 Java Web API接口开发是Web应用程序中不可或缺的一部分。对于想要开发基于Web的应用程序的开发者来说,精通Java Web API接口开发是必不可少的技能之一。掌握了Java Web API开发技术,可以极大地提升Web应用程序的性能和用户体验。 ### 回答3: Java Web API 接口开发实例的目的是为了解决 Web 应用之间的数据交互问题。在这个过程中,使用基于 Java 的 Web API 接口对外提供数据交换接口,这样不仅能够使不同平台、不同语言的应用程序间进行数据交互,而且能够兼容现有的系统,提高系统的整体性能。 Java Web API 接口开发需要关注以下几个方面: 1. 接口设计 接口设计是 Java Web API 接口开发一个重要环节,需要根据数据交换的需求设计 RESTful API 。RESTful API 是一种基于 HTTP 规范的 Web API 设计,它具有简洁、灵活、可扩展等特点,在实现Web API 接口开发时,能够快速创建符合规范的接口。 2. 安全性 由于 Web API 接口经过公网传输,因此安全性是 Web API 接口开发不可忽视的因素。在接口开发中通常采用 Token 认证机制,来确保用户的身份安全,同时也需要考虑防止 SQL 注入等攻击,提高安全性。 3. 数据库操作 Java Web API 接口开发需要对底层数据库进行操作,常用的数据库包括 MySQL、PostgreSQL 等。在 API 接口开发中通常采用 ORM 框架来简化数据库操作,例如 MyBatis、Hibernate 等开源框架。 4. 使用 RESTful 工具包 使用 RESTful 工具包能够大大降低 Web API 接口开发的难度。常用的 RESTful 工具包包括 Jersey、Spring Web MVC 等,这些工具包提供了快速构建 RESTful API 接口的能力,同时也支持 JSON、XML 等常用的数据格式,便于数据交换。 综上所述,Java Web API 接口开发是实现跨平台、跨语言、实时数据交换的重要手段。在接口开发需要关注接口设计安全性、数据库操作和使用 RESTful 工具包等方面,这样才能够高效地实现数据交换接口,提高系统整体性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值