# Segurança
A transfersmile inclui uma assinatura no cabeçalho d transfersmile-Signature de cada evento. Isto permite verificar que o evento foi enviado pela transfersmile ao invés de um terceiro.
# Assinatura
# Verificação manual das assinaturas
O conteúdo aproximado do cabeçalho transfersmile-Signature é o seguinte (aqui com quebras de linha para fácil visualização, o conteúdo real está todo em uma linha):
transfersmile-Signature:
t=1577808000,
v2=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd
O cabeçalho transfersmile-Signature contém um timestamp e uma assinatura. O timestamp é prefixado por t=, seguido por um timestamp UNIX; a assinatura é prefixada por v2=, seguido pelo conteúdo da assinatura.
A notificação enviada usa o seguinte formato:
{
Content-Type: application/json,
Method: POST,
Header: transfersmile-Signature,
Body: {
"trade_no":"",
"out_trade_no":"",
"out_request_no":"",
"app_id":"",
"trade_status":"",
"amount":"",
"method":"",
"currency":"",
"timestamp":""
}
}
# Etapa 1 : Extrair o timestamp e as assinaturas do cabeçalho
Divida o cabeçalho usando o caracter [,] como separador, para obter uma lista de elementos. Em seguida, dividir cada elemento usando o caractere [=] como separador, para obter um prefixo e um par de valores.
O valor para o prefixo [t] corresponde ao timestamp, e [v2] corresponde à assinatura. Você pode descartar todos os outros elementos.
# Etapa 2 : Preparar a string RequestBody original
Obtenha todo o conteúdo no RequestBody. Por favor, não utilize a estrutura autoconstruída do programa para formatar e/ou seriar o conteúdo do RequestBody. Se você tiver requisitos semelhantes, por favor, faça após obter os dados originais para verificação para evitar a ordenação desnecessária de campos e a adição de caracteres afeta a assinatura.
# Etapa 3 : Determinar a assinatura esperada
Calcule um HMAC com a função hash SHA256. Use o SecretKey get do dashboard do comerciante como a chave (salt), e use a string RequestBody original como a mensagem.
# Etapa 4 : Compare as assinaturas
Compare a assinatura no cabeçalho com a assinatura esperada. Para uma correspondência de igualdade, calcule a diferença entre o timestamp atual e o timestamp recebido, depois decida se a diferença está dentro de sua tolerância.
# Exemplo de verificação de códigos em Java
String content = JSON.toJSONString(notify);
String sign = SignHelper.macSha256(content, privateKey());
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
/**
*
*/
@Slf4j
public final class SignHelper{
/**
* HMAC with SHA-256
*
* @param content
* @param salt
* @return
*/
public static String macSha256(String content, String salt) {
StringBuilder result = new StringBuilder();
try {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(salt.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
byte[] hash = mac.doFinal(content.getBytes(StandardCharsets.UTF_8));
for (byte b : hash) {
result.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
}
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
e.printStackTrace();
}
return result.toString();
}
}