Todos os produtos
Search
Central de documentação

Mobile Platform as a Service:Verificação de assinatura de backend

Última atualização: Jun 28, 2026

O Mobile Gateway Service assina cada solicitação de API e a envia ao seu servidor de backend. Nesse servidor, verifique a assinatura para confirmar que a solicitação veio do gateway e não sofreu adulteração.

  • Ao ativar a verificação de assinatura para um grupo de APIs no console do gateway, o Mobile Gateway Service assina cada solicitação desse grupo. Crie as chaves pública e privada usadas na assinatura no próprio console do gateway.

  • Seu servidor de backend lê a assinatura no cabeçalho da solicitação, reconstrói localmente a string a ser assinada, aplica o mesmo algoritmo e compara o resultado com a assinatura recebida para determinar a validade da solicitação.

Como funciona

A verificação ocorre em três etapas:

  1. Leia os cabeçalhos. O Mobile Gateway Service anexa a assinatura e o identificador da chave a todas as solicitações em dois cabeçalhos específicos.

  2. Reconstrua a string a ser assinada. Monte a mesma string usada pelo gateway como entrada para a assinatura: o método HTTP, o valor Content-MD5 e a URL construída.

  3. Verifique a assinatura. Aplique o algoritmo escolhido (MD5+salt, RSA, SM3 ou SM2) à string reconstruída e compare a saída com a assinatura recebida.

O gateway armazena a assinatura calculada no cabeçalho da solicitação X-Mgs-Proxy-Signature.

O identificador da chave secreta — usado para buscar o valor secreto correspondente — é enviado no cabeçalho da solicitação X-Mgs-Proxy-Signature-Secret-Key.

Construir a string a ser assinada

Montar a string a ser assinada

String stringToSign =
HTTPMethod + "\n" +
Content-MD5 + "\n" +
Url
  • HTTPMethod: O método HTTP em letras maiúsculas, como PUT ou POST.

  • Content-MD5: O valor MD5 do corpo da solicitação, calculado da seguinte forma:

    1. Se HTTPMethod não for PUT ou POST, o valor MD5 será uma string vazia ("").

    2. Caso o corpo da solicitação seja um formulário, o MD5 será uma string vazia "". Caso contrário, prossiga para a próxima etapa.

    3. Calcule o valor MD5. Se a solicitação não tiver corpo, bodyStream será a string "null".

      String content-MD5 = Base64.encodeBase64(MD5(bodyStream.getBytes("UTF-8")));
      Importante

      Mesmo que o valor de Content-MD5 seja uma string vazia (""), inclua a quebra de linha subsequente (\n) na string a ser assinada. Isso resulta em dois caracteres \n consecutivos na string.

  • Url: Construída a partir do caminho, da query e dos parâmetros de formulário. Por exemplo, dada a solicitação http://ip:port/test/testSign?c=3&a=1 com parâmetros de formulário b=2&d=4, monte a Url conforme descrito abaixo:

    1. Extraia o caminho — a parte após ip:port e antes de ?. Neste exemplo, o caminho é /test/testSign.

    2. Quando a solicitação não possui parâmetros de query ou de formulário, a Url corresponde ao caminho.

    3. Ordene os parâmetros de query e de formulário por chave em ordem lexicográfica e concatene-os no formato Key1=Value1&Key2=Value2&...&KeyN=ValueN. Neste exemplo, o resultado é a=1&b=2&c=3&d=4.

      Nota

      Se um parâmetro de query ou de formulário tiver vários valores, use apenas o primeiro value.

    4. Monte a Url no formato Path?Key1=Value1&Key2=Value2&...&KeyN=ValueN. Neste exemplo, a Url é /test/testSign?a=1&b=2&c=3&d=4.

Verificar a assinatura

Utilize o mesmo algoritmo configurado ao definir o grupo de APIs no console do gateway.

  • Verifique a assinatura com o algoritmo MD5

      String sign = "xxxxxxx"; // The signature from Mobile Gateway Service
      String salt ="xxx";     // The MD5 salt
    
      MessageDigest digest = MessageDigest.getInstance("MD5");
      String toSignedContent = stringToSign + salt;
      byte[] content = digest.digest(toSignedContent.getBytes("UTF-8"));
      String computedSign = new String(Hex.encodeHexString(content));
    
      boolean isSignLegal = sign.equals(computedSign) ? true : false;
  • Verifique a assinatura com o algoritmo RSA

      String sign = "xxxxxxx"; // The signature from Mobile Gateway Service
      String publicKey ="xxx"; // The RSA public key from Mobile Gateway Service
    
      PublicKey pubKey = KeyReader.getPublicKeyFromX509("RSA", new ByteArrayInputStream(publicKey.getBytes()));
      java.security.Signature signature = java.security.Signature.getInstance("SHA1WithRSA");
      signature.initVerify(pubKey);
      signature.update(stringToSign.getBytes("UTF-8"));
    
      boolean isSignLegal = signature.verify(Base64.decodeBase64(sign.getBytes("UTF-8")));
  • Verifique a assinatura com um algoritmo criptográfico chinês

    Algoritmo SM3:

     String sign = xxxx;
     String salt = xxxxxx;
     String toSignedContent = stringToSign + salt;
     byte[] srcData = toSignedContent.getBytes("UTF-8");
     SM3Digest digest = new SM3Digest();
     digest.update(srcData, 0, srcData.length);
     byte[] resultHash = new byte[digest.getDigestSize()];
     digest.doFinal(resultHash, 0);
     String computedSign = Hex.encodeHexString(resultHash);
     boolean isSignLegal  = sign.equals(computedSign);

    Algoritmo SM2:

    String sign = xxxx;
    String pubKey = xxxx;
    
     Signature signature = Signature.getInstance("SM3withSM2", "LOCCSBC");
     KeyPair keyPair = getSmKeyPair(pubKey);
    
     PublicKey publicKey = keyPair.getPublic();
     signature.initVerify(publicKey);
     signature.update(stringToSign.getBytes("UTF-8"));
     return signature.verify(Hex.decodeHex(sign));
    public static KeyPair getSmKeyPair(String keyPairContent) throws IOException, InvalidKeySpecException, NoSuchProviderException, NoSuchAlgorithmException {
      KeyFactory keyFactory = KeyFactory.getInstance("SM2", "LOCCSBC");
    
      byte[] keyBytes = getPKCS1fromPEMString(keyPairContent);
      SM2ParameterSpec spec = SM2NamedCurveTable.getParameterSpec("sm2p256v1", "1234567812345678");
    
      SM2PrivateKeySpec sm2PrivateKeySpec = new SM2PrivateKeySpec(BigIntegers.fromUnsignedByteArray(keyBytes), spec);
      SM2PrivateKey prvkey = (SM2PrivateKey) keyFactory.generatePrivate(sm2PrivateKeySpec);
    
      SM2PublicKeySpec sm2PublicKeySpec = new SM2PublicKeySpec(prvkey.getQ(), spec);
      SM2PublicKey pubKey = (SM2PublicKey) keyFactory.generatePublic(sm2PublicKeySpec);
    
      return new KeyPair(pubKey, prvkey);
     }
    public static byte[] getPKCS1fromPEMString(String pemStr) {
      // pkcs1
      try {
       PEMParser reader = new PEMParser(new StringReader(pemStr));
       PemObject pemObject = reader.readPemObject();
       reader.close();
    
       ASN1InputStream asn1In = new ASN1InputStream(pemObject.getContent());
       ASN1Sequence derSequence = (ASN1Sequence) asn1In.readObject();
       asn1In.close();
    
       // openssl format
       Object obj = derSequence.getObjectAt(1);
       if (obj instanceof ASN1OctetString){
        return ((ASN1OctetString) obj).getOctets();
       }
    
       // gmssl format
       DEROctetString derOctetString = (DEROctetString)derSequence.getObjectAt(2);
       ASN1Sequence sequence = (ASN1Sequence)ASN1Sequence.fromByteArray(derOctetString.getOctets());
       return ((ASN1OctetString)sequence.getObjectAt(1)).getOctets();
      } catch (Exception e) {
       throw new RuntimeException(e);
      }
     }

Exemplos de código

Para uma implementação completa, consulte HttpSignUtil.java.

Solução de problemas

Incompatibilidade de assinatura

Quando a verificação falha, a causa mais comum é a incompatibilidade entre a string a ser assinada construída pelo seu backend e a string usada pelo gateway.

Registre o valor exato de stringToSign que seu backend constrói e compare-o caractere por caractere com o valor computado pelo gateway. Verifique os seguintes pontos:

  • **Caractere \n final após um Content-MD5 vazio.** Mesmo quando Content-MD5 é uma string vazia, o separador \n ainda deve estar presente na string a ser assinada. Isso gera dois caracteres \n consecutivos — uma fonte frequente de incompatibilidade.

  • Ordem de classificação dos parâmetros. Ordene os parâmetros de query e de formulário por chave em ordem lexicográfica antes da concatenação. Confirme se a sua classificação diferencia maiúsculas de minúsculas e corresponde à ordenação do gateway.

  • Corpo de formulário tratado como conteúdo. Se o corpo da solicitação for um formulário, Content-MD5 deve ser uma string vazia (""), e não o MD5 dos bytes do corpo do formulário.

  • Valor secreto incorreto. Confirme se o salt ou a chave pública que seu backend utiliza corresponde ao valor configurado no console do gateway para o identificador de chave secreta em X-Mgs-Proxy-Signature-Secret-Key.