APIインターフェース署名生成アルゴリズムと署名検証アルゴリズム
1、インターネット資料と本資料を参考にして、APIインタフェース署名生成アルゴリズムと署名検証アルゴリズムを実現しました.
(1)参考資料:https://www.jianshu.com/p/d47da77b6419
(2)参考書:高級ソフトウェア構築師教程(311-12)
2、APIインターフェース署名生成アルゴリズム
主な手順は以下の通りです.
(1)すべての業務要求パラメータをアルファベット順に並べ替える.
(2)パラメータ名とパラメータ値は、文字列Aにリンクされています.
(3)文字列Aの先頭にapiSecretインターフェースの隠しスプーンを加えて、新しい文字列Bを構成する.
(4)文字列をMD 5ハッシュ演算し、API署名signを得てからBase 64符号化を行う.
要求されたパラメータはf=1,b=23,k=33で、並べ替え後はb=23,f=1,k=33で、パラメータ名とパラメータ値をリンクした後はb 23 f 1 k 33で、最初の尾にappecretを加えた後md 5:
C=md 5(secretkey 1 value 1 key 2 value 2...secret);
Base 646.encode(C)
以上の署名方法は安全で効果的にパラメータの改竄と身分認証の問題を解決しました.もしパラメータが改竄されたら大丈夫です.他の人がapiSecretを知ることができなくて、新しいsignを再生成できなくなり、インタフェースの呼び出しが信頼できると保証します.
Javaコード
3、署名検証アルゴリズム(インターフェース提供者検証インターフェース要求が信頼できるかどうかは、主なアルゴリズムとAPI署名を生成するアルゴリズムと同じである)
主な手順は以下の通りです.
1、要求側が携帯するAPIの署名を得る.
2、すべての業務要求パラメータをアルファベット順に並べ替える.
3、パラメータ名とパラメータ値を文字列Aにリンクします.
4、文字列Aの先頭にappiSecretインターフェースの隠しスプーンを加えて、新しい文字列Bを構成します.
5、新しい文字列BにMD 5ハッシュ演算を行い、サーバ端のAPI署名を生成し、クライアントのAPI署名をBase 64で復号し、署名の検証を開始する.
6、サーバ端で生成されたAPI署名がクライアント要求のAPI署名と一致する場合、要求は信頼され、そうでなければ信頼されない.
javaコード
(1)参考資料:https://www.jianshu.com/p/d47da77b6419
(2)参考書:高級ソフトウェア構築師教程(311-12)
2、APIインターフェース署名生成アルゴリズム
主な手順は以下の通りです.
(1)すべての業務要求パラメータをアルファベット順に並べ替える.
(2)パラメータ名とパラメータ値は、文字列Aにリンクされています.
(3)文字列Aの先頭にapiSecretインターフェースの隠しスプーンを加えて、新しい文字列Bを構成する.
(4)文字列をMD 5ハッシュ演算し、API署名signを得てからBase 64符号化を行う.
要求されたパラメータはf=1,b=23,k=33で、並べ替え後はb=23,f=1,k=33で、パラメータ名とパラメータ値をリンクした後はb 23 f 1 k 33で、最初の尾にappecretを加えた後md 5:
C=md 5(secretkey 1 value 1 key 2 value 2...secret);
Base 646.encode(C)
以上の署名方法は安全で効果的にパラメータの改竄と身分認証の問題を解決しました.もしパラメータが改竄されたら大丈夫です.他の人がapiSecretを知ることができなくて、新しいsignを再生成できなくなり、インタフェースの呼び出しが信頼できると保証します.
Javaコード
/**
* HTTP
* @param method
* @param path
* @param params
* @param apiKey
* @param apiSecret
*/
void addRequiredParams(String method, String path, Map params, String apiKey, String apiSecret) {
params.put("key", apiKey); //
params.put("sigVer", "1"); //
String ts = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss:SSS").format(LocalDateTime.now());
params.put("ts", ts); //
params.put("nonce", RandomStringUtils.randomAlphanumeric(16));
String sig = getSig(method, path, apiSecret, params);
params.put("sig", sig); //API
}
/**
* API
*
* @param method
* @param path
* @param apiSecret
* @param params
* @return
*/
private String getSig(String method, String path, String apiSecret, Map params) {
StringBuilder stringA = new StringBuilder();
///1、 .
// 2、 A
Set keySet = new TreeSet<>(params.keySet());
for (String key : keySet) {
String value = params.get(key);
if (value == null) {
continue;
}
System.out.println(key + ":" + params.get(key));
stringA.append(key);
stringA.append("=");
stringA.append(params.get(key));
stringA.append("&");
}
stringA.setLength(stringA.length() - 1); // trim the last "&"
System.out.println(" A:" + stringA.toString());
logger.debug(" A:" + stringA.toString());
String unifiedString = method.toUpperCase() + ":" + path + ":" + stringA.toString();
logger.debug("unified string: " + unifiedString);
String sig = null;
///3、 A apiSecret B
StringBuilder stringB = new StringBuilder();
stringB.append(apiSecret).append(stringA).append(apiSecret);
try {
//4、 MD5 sign, Base64
byte[] bytes = Base64.getEncoder().encode(MD5Utils.md5(stringB.toString()).getBytes("UTF-8"));
sig = new String(bytes, "UTF-8");
} catch (Exception e) {
logger.error("getSig error: " + e.getMessage());
}
return sig;
}
3、署名検証アルゴリズム(インターフェース提供者検証インターフェース要求が信頼できるかどうかは、主なアルゴリズムとAPI署名を生成するアルゴリズムと同じである)
主な手順は以下の通りです.
1、要求側が携帯するAPIの署名を得る.
2、すべての業務要求パラメータをアルファベット順に並べ替える.
3、パラメータ名とパラメータ値を文字列Aにリンクします.
4、文字列Aの先頭にappiSecretインターフェースの隠しスプーンを加えて、新しい文字列Bを構成します.
5、新しい文字列BにMD 5ハッシュ演算を行い、サーバ端のAPI署名を生成し、クライアントのAPI署名をBase 64で復号し、署名の検証を開始する.
6、サーバ端で生成されたAPI署名がクライアント要求のAPI署名と一致する場合、要求は信頼され、そうでなければ信頼されない.
javaコード
/**
* API
* (1) ( apiSecret )
* (2) apiSecret 。
* (3) , 。 , , 。
*
* @param request
* @param apiSecret
* @return
*/
public static boolean checkSig(HttpServletRequest request, String apiSecret) throws IOException{
//1、 API
String clientSig = null;
StringBuilder stringA = new StringBuilder();
Enumeration parameterNames = request.getParameterNames();
Set keySet = new TreeSet<>();
//2、 。
while (parameterNames.hasMoreElements()) {
String parameterName = parameterNames.nextElement();
if (parameterName.equals("sig")) {
// API
clientSig = request.getParameter("sig");
continue;
}
keySet.add(parameterName);
}
//3、 A。
for (String key : keySet) {
String value = request.getParameter(key);
if (value == null) {
continue;
}
stringA.append(key);
stringA.append("=");
stringA.append(value);
stringA.append("&");
}
stringA.setLength(stringA.length() - 1); // trim the last "&"
//
String serverSig = null;
//Base64
clientSig = new String(Base64.getDecoder().decode(clientSig), "UTF-8");
//4、 A apiSecret B。
StringBuilder stringB = new StringBuilder();
stringB.append(apiSecret).append(stringA).append(apiSecret);
//5、 B MD5 API , API Base64 , 。
//6、 API API , , 。
serverSig = MD5Utils.md5(stringB.toString());
return clientSig != null && serverSig != null && clientSig.equals(serverSig);
}
3、 OpenApi API
: , API 。 , API 。
:
/**
* : OpenAPI
*
* @author chenlw
* @create 2018-11-19 11:21
*/
public class OpenApiRequestCheckFilter implements Filter {
@Autowired
private SystemConnectionConfigClient systemConnectionConfigClient;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
System.out.println("-----------------OpenApiRequestCheckFilter--------------------");
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
if (systemConnectionConfigClient == null) {
// @Autowired
BeanFactory factory = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getServletContext());
systemConnectionConfigClient = (SystemConnectionConfigClient) factory.getBean("systemConnectionConfigClient");
}
String apiKey = request.getParameter("key"); //apiKey
if(apiKey == null){
///API , Controller
UnauthorizedForward(request,response);
return;
}
String apiSecret = systemConnectionConfigClient.queryDcToFrontApiSecretByApiKey(apiKey);
//
if (apiSecret != null) {
/// API
boolean sigCheckResult = OpenApiRequestCheckUtils.checkSig(request, apiSecret);
if (sigCheckResult) {
//API
chain.doFilter(request, response);
} else {
///API , Controller
UnauthorizedForward(request,response);
}
} else {
///API , Controller
UnauthorizedForward(request,response);
}
}
private void UnauthorizedForward(HttpServletRequest request,HttpServletResponse response) throws IOException,ServletException{
/// , Controller
if ("GET".equals(request.getMethod())) {
request.getRequestDispatcher("/api/dataCenterRequest/handleUnauthorizedGetRequest").forward(request, response);
} else {
request.getRequestDispatcher("/api/dataCenterRequest/handleUnauthorizedPostRequest").forward(request, response);
}
}
@Override
public void destroy() {
}
}