4

我正在开发一个将数据发送到我的 Web 服务并将它们存储在我的数据库中的 Android 项目。我正在使用 HTTP 协议连接到我的网络服务。使用 JSON 作为数据格式。

我将数据和这些数据的 HASH (SHA256) 发送到 Web 服务。

在将数据存储到数据库之前,我使用 HASH 验证我发送的(数据)是否等于 Webservice 接收的。如果没有,我会发送一条错误消息。

有时 HASH 的值不同会导致错误消息,并且没有数据存储在数据库中

所以我的问题是:是否有另一种方法来验证数据在发送操作期间是否未更改?

4

7 回答 7

13

哈希似乎适用于您的场景,因为您可以很好地检测到数据修改。

但是哈希可以与数据一起更改,因此这不是针对恶意攻击者的安全措施。如果您关心安全性,您可能会对WS-Security感兴趣。

本质上,您必须使用加密通道 (HTTPS) 或签署您的消息。

于 2013-01-07T09:26:04.797 回答
3

如果您不信任该频道 - 您应该使用 HTTPS。就这样。尝试建立自己的完整性验证机制就是尝试设计自己的安全协议,这是您最不想做的事情。

在任何情况下,您使用的未加密哈希(如 SHA256)是不够的。能够修改消息的对手也能够重新计算修改后的文本的哈希值并将其与消息一起发送。您需要一个更强大的原语:MAC(消息验证码)http://en.wikipedia.org/wiki/Message_authentication_code

HTTPS 为您提供这些以及更多。

于 2013-01-16T08:39:10.507 回答
2

Hashing techniques将是这里的最佳选择。

您可以使用任何散列算法,如HmacSHA1orMD5等​​。

当您使用Postor将数据传递到服务器Get时,首先,使用任何散列算法从数据中创建一个令牌。(请参阅下面将数据转换为 HMAC SHA1 的函数)

当您传递此数据时,将令牌也传递给服务器。现在服务器也将使用与客户端相同的散列算法,服务器将根据请求传递的数据创建令牌。

之后,服务器将生成的令牌与随请求传递的令牌相匹配。

如果两个令牌都匹配,则与请求一起传递的数据不会被篡改,否则数据会被篡改。

您可以使用以下方法为您的数据创建令牌:

    /**
     * Encrypts the data passed to it using Hmac-SHA1.
     * 
     * @param dataToEncrypt
     *            data that is to be encrypted.
     * @return The token that is generated after encrypting data.
     */
    public static String convertDataToHmacSHA1(final String dataToEncrypt) {
        String returnString;
        try {
            // Get an hmac_sha1 key from the raw key bytes
            final byte[] keyBytes = HMAC_SHA1_KEY.getBytes();
            final SecretKeySpec signingKey = new SecretKeySpec(keyBytes,
                    "HmacSHA1");

            // Get an hmac_sha1 Mac instance and initialize with the signing key
            final Mac mac = Mac.getInstance("HmacSHA1");
            mac.init(signingKey);

            // Compute the hmac on input data bytes
            final byte[] rawHmac = mac.doFinal(dataToEncrypt.getBytes());

            final StringBuffer stringBuffer = new StringBuffer();
            for (byte b : rawHmac) {
                stringBuffer.append(String.format("%02x", b));
            }
            returnString = stringBuffer.toString();
            Log.e("Token", returnString);
            return returnString;
        } catch (Exception e) {
            Log.e(TAG, "" + e);
        }
        return returnString;
    }
于 2013-01-16T09:53:18.673 回答
1

目前您使用哈希来验证数据的完整性 - 假设您在两端使用完全相同的哈希,这意味着您正在获取损坏的数据。

而不是仅仅检测数据损坏,您可以将数据编码为纠错码,以便您可以在接收端重建原始数据,即使它在途中被损坏

您可以在这个问题的答案中找到这样的库 - Java: ECC (error correction code) library?

于 2013-01-07T09:30:18.373 回答
1

我觉得你的方法很好。

您有一个重要的解决方案,分 3 步:第 1 步:将数据发送到 android 第 2 步:android 接收数据并通知 Web 服务器他得到了什么第 3 步:服务器检查每个字段并通知 android,如果 orverall 正确与否.

但我认为这个解决方案对于大多数情况来说太重了,如果有其他解决方案,它是为了回答你的问题。

于 2013-01-07T09:44:21.797 回答
1

您是否需要读回数据,如果不只是散列一次并比较散列。

根据散列错误的频率,您是否可以在错误消息之前给应用程序五次尝试使其正确。

你试过其他算法,比如 md5、成熟或 crc 吗?也许他们更有效率。

根据我对小字符串的经验,我使用 crc,但对于登录详细信息,我使用 sha256 或 sha512,我只是散列密码并比较散列。那么你的数据库中就没有密码了。

希望这可以帮助!

于 2013-01-12T16:16:28.270 回答
1

如果我错了,请纠正我,但是您正在散列以尝试检测两件事之一。

  1. 检测“中间人攻击”。(MITM)请参阅此处了解更多信息
  2. 检测不可靠的网络。

@Samuel Edwin Ward@radai正在谈论上面的这两个。

这两个问题都有相当好的现有解决方案,不涉及您明确地散列您的数据。

首先,为了降低 MITM 攻击的可能性,请使用HTTPS。客户端可以放心地确定服务器的身份,并且在防止窃听方面也做得相当好。

其次,要解决您对不可靠网络的担忧,请使用TCP ...

TCP 提供从一台计算机上的程序到另一台计算机上的另一个程序的可靠、有序的八位字节流传递。维基百科

我猜你没有做任何特别的事情(比如使用 UDP 网络或其他东西),并且你的 Web 服务已经使用了 TCP。

您在哈希比较中看到的问题可能是由于您的应用程序逻辑中的假设不正确。我建议您比较错误事物的哈希值。

作为想到的众多示例之一,一些 Web 服务器会在处理 HTTP 请求时添加内容。例如,这就是代理的工作方式。在比较设备发送的 HTTP 请求的哈希值和 Web 服务器最终接收的 HTTP 请求的哈希值时,这会给您不同的结果。

我建议您阅读我提供的内联链接,以确保您对损坏数据的担忧已在很大程度上通过现有解决方案得到解决。如果不是,至少你会更好地理解为什么你觉得你需要散列你的数据。:)

于 2013-01-16T08:21:12.517 回答